Files
wg_cpso/CaeModel/FileInOut/Output/Mmg/MmgFileWriter.cs

979 lines
48 KiB
C#
Raw Normal View History

2026-03-25 18:20:24 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using CaeMesh;
using CaeGlobals;
namespace FileInOut.Output
{
static public class MmgFileWriter
{
public static void Write(string fileName, BasePart part, FeMesh mesh, bool keepModelEdges, bool keepVertexEdges)
{
if (part.PartType == PartType.Solid) Write3D(fileName, part, mesh, keepModelEdges, keepVertexEdges);
else if (part.PartType == PartType.Shell) Write2D(fileName, part, mesh, keepModelEdges, keepVertexEdges);
else throw new NotSupportedException();
}
private static void Write2D(string fileName, BasePart part, FeMesh mesh, bool keepModelEdges, bool keepVertexEdges)
{
VisualizationData vis = part.Visualization;
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices
Dictionary<int, int> oldNodeIdNewId;
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh);
WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId);
// Corners
List<int> cornerIds = new List<int>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]);
WriteCorners(sb, cornerIds);
// Triangles
int elementId;
FeElement element;
List<int[]> elementNodeIdsSurfaceId = new List<int[]>();
for (int i = 0; i < vis.CellIdsByFace.Length; i++)
{
for (int j = 0; j < vis.CellIdsByFace[i].Length; j++)
{
elementId = vis.CellIds[vis.CellIdsByFace[i][j]];
element = mesh.Elements[elementId];
if (element is LinearTriangleElement)
{
elementNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
i + 1 });
}
//else if (element is ParabolicTriangleElement)
//{
// elementNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
// oldNodeIdNewId[element.NodeIds[1]],
// oldNodeIdNewId[element.NodeIds[2]],
// i + 1 });
//}
else throw new NotSupportedException();
}
}
WriteTriangles(sb, elementNodeIdsSurfaceId);
// Edges
int id1, id2;
int edgeId = 1;
List<int> edgeIds;
// Collect all edge cells connected to a vertex
Dictionary<int, List<int>> vertexEdgeIds = new Dictionary<int, List<int>>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++)
vertexEdgeIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]], new List<int>());
//
List<int[]> edgeNodeIdsEdgeId = new List<int[]>();
for (int i = 0; i < vis.EdgeCellIdsByEdge.Length; i++)
{
for (int j = 0; j < vis.EdgeCellIdsByEdge[i].Length; j++)
{
id1 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][0];
id2 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][1];
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], i + 1 });
//
if (vertexEdgeIds.TryGetValue(id1, out edgeIds)) edgeIds.Add(edgeId);
if (vertexEdgeIds.TryGetValue(id2, out edgeIds)) edgeIds.Add(edgeId);
//
edgeId++;
}
}
//
if (keepModelEdges) WriteEdges(sb, edgeNodeIdsEdgeId);
// Ridges - all edges are ridges
int[] ridgeIds = new int[vis.EdgeCells.Length];
for (int i = 0; i < ridgeIds.Length; i++) ridgeIds[i] = i + 1;
WriteRidges(sb, ridgeIds);
// Required edges - keep edge cells connected to the vertices with only 2 edge cells: on the outside of the rectangle
HashSet<int> requiredEdgeIds = new HashSet<int>();
foreach (var cornerEntry in vertexEdgeIds)
{
if (cornerEntry.Value.Count == 2) requiredEdgeIds.UnionWith(cornerEntry.Value);
}
if (keepVertexEdges) WriteRequiredEdges(sb, requiredEdgeIds.ToArray());
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
private static void Write3D(string fileName, BasePart part, FeMesh mesh, bool keepModelEdges, bool keepVertexEdges)
{
VisualizationData vis = part.Visualization;
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices
Dictionary<int, int> oldNodeIdNewId;
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh);
WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId);
// Corners
List<int> cornerIds = new List<int>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]);
WriteCorners(sb, cornerIds);
// Edges
int id1, id2;
int edgeId = 1;
List<int> edgeIds;
// Collect all edge cells connected to a vertex
Dictionary<int, List<int>> vertexEdgeIds = new Dictionary<int, List<int>>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++)
vertexEdgeIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]], new List<int>());
//
List<int[]> edgeNodeIdsEdgeId = new List<int[]>();
for (int i = 0; i < vis.EdgeCellIdsByEdge.Length; i++)
{
for (int j = 0; j < vis.EdgeCellIdsByEdge[i].Length; j++)
{
id1 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][0];
id2 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][1];
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], i + 1 });
//
if (vertexEdgeIds.TryGetValue(id1, out edgeIds)) edgeIds.Add(edgeId);
if (vertexEdgeIds.TryGetValue(id2, out edgeIds)) edgeIds.Add(edgeId);
//
edgeId++;
}
}
//
if (keepModelEdges) WriteEdges(sb, edgeNodeIdsEdgeId);
// Ridges - all edges are ridges
int[] ridgeIds = new int[vis.EdgeCells.Length];
for (int i = 0; i < ridgeIds.Length; i++) ridgeIds[i] = i + 1;
WriteRidges(sb, ridgeIds);
// Required edges - keep edge cells connected to the vertices with only 2 edge cells: on the outside of the rectangle
HashSet<int> requiredEdgeIds = new HashSet<int>();
foreach (var cornerEntry in vertexEdgeIds)
{
if (cornerEntry.Value.Count == 2) requiredEdgeIds.UnionWith(cornerEntry.Value);
}
if (keepVertexEdges) WriteRequiredEdges(sb, requiredEdgeIds.ToArray());
// Triangles
int[] cell;
List<int[]> elementNodeIdsSurfaceId = new List<int[]>();
for (int i = 0; i < vis.CellIdsByFace.Length; i++)
{
for (int j = 0; j < vis.CellIdsByFace[i].Length; j++)
{
cell = vis.Cells[vis.CellIdsByFace[i][j]];
// Linear
if (cell.Length == 3 || cell.Length == 6) // reduce parabolic elements to linear
{
elementNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[cell[0]],
oldNodeIdNewId[cell[1]],
oldNodeIdNewId[cell[2]],
i + 1 });
}
else throw new CaeException("Mmg meshes only support triangular faces.");
}
}
WriteTriangles(sb, elementNodeIdsSurfaceId);
// Tetrahedrons
int elementId;
FeElement element;
elementNodeIdsSurfaceId.Clear();
for (int i = 0; i < part.Labels.Length; i++)
{
elementId = part.Labels[i];
element = mesh.Elements[elementId];
if (element is LinearTetraElement || element is ParabolicTetraElement)
{
elementNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
oldNodeIdNewId[element.NodeIds[3]],
part.PartId });
}
else throw new CaeException("Mmg meshes only support tetrahedral volume elements.");
}
WriteTetrahedrons(sb, elementNodeIdsSurfaceId);
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
public static void WriteSolution(string fileName, BasePart part, FeMesh mesh, Dictionary<int, double> nodeIdValue)
{
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices order
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh);
// Solution at vertices
WriteSolutionAtVertices(sb, nodeCoorNodeId, nodeIdValue);
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
public static void Write(string fileName, BasePart[] parts, FeMesh mesh, bool keepModelEdges, bool keepVertexEdges)
{
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices
HashSet<int> allNodeIds = new HashSet<int>();
foreach (var part in parts) allNodeIds.UnionWith(part.NodeLabels);
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(allNodeIds.ToArray(), mesh);
Dictionary<int, int> oldNodeIdNewId;
WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId);
// Corners
HashSet<int> cornerIds = new HashSet<int>();
VisualizationData vis;
foreach (var part in parts)
{
vis = part.Visualization;
for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]);
}
WriteCorners(sb, cornerIds);
// Edges
int id1, id2;
int edgeId = 1;
int edgeSegmentId = 1;
List<int> edgeIds;
List<int> ridgeIds = new List<int>();
// Collect all edge cells connected to a vertex
Dictionary<int, List<int>> vertexEdgeIds = new Dictionary<int, List<int>>();
List<int[]> edgeNodeIdsEdgeId = new List<int[]>();
//
foreach (var part in parts)
{
vis = part.Visualization;
//
for (int i = 0; i < vis.VertexNodeIds.Length; i++)
{
if (!vertexEdgeIds.ContainsKey(oldNodeIdNewId[vis.VertexNodeIds[i]]))
vertexEdgeIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]], new List<int>());
}
//
for (int i = 0; i < vis.EdgeCellIdsByEdge.Length; i++)
{
for (int j = 0; j < vis.EdgeCellIdsByEdge[i].Length; j++)
{
id1 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][0];
id2 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][1];
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], edgeId });
//
if (vertexEdgeIds.TryGetValue(id1, out edgeIds)) edgeIds.Add(edgeSegmentId);
if (vertexEdgeIds.TryGetValue(id2, out edgeIds)) edgeIds.Add(edgeSegmentId);
//
ridgeIds.Add(edgeSegmentId);
//
edgeSegmentId++;
}
edgeId++;
}
//
}
if (keepModelEdges) WriteEdges(sb, edgeNodeIdsEdgeId);
// Ridges - all edges are ridges
WriteRidges(sb, ridgeIds.ToArray());
// Required edges - keep edge cells connected to the vertices with only 2 edge cells: on the outside of the rectangle
HashSet<int> requiredEdgeIds = new HashSet<int>();
foreach (var cornerEntry in vertexEdgeIds)
{
if (cornerEntry.Value.Count == 2) requiredEdgeIds.UnionWith(cornerEntry.Value);
}
if (keepVertexEdges) WriteRequiredEdges(sb, requiredEdgeIds.ToArray());
// Surface elements
int surfId = 1;
int[] cell;
List<int[]> triangleNodeIdsSurfaceId = new List<int[]>();
List<int[]> quadNodeIdsSurfaceId = new List<int[]>();
foreach (var part in parts)
{
vis = part.Visualization;
//
for (int i = 0; i < vis.CellIdsByFace.Length; i++)
{
for (int j = 0; j < vis.CellIdsByFace[i].Length; j++)
{
cell = vis.Cells[vis.CellIdsByFace[i][j]];
// Triangles
if (cell.Length == 3 || cell.Length == 6) // reduce parabolic elements to linear
{
triangleNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[cell[0]],
oldNodeIdNewId[cell[1]],
oldNodeIdNewId[cell[2]],
surfId });
}
// Quads
else if (cell.Length == 4 || cell.Length == 8) // reduce parabolic elements to linear
{
quadNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[cell[0]],
oldNodeIdNewId[cell[1]],
oldNodeIdNewId[cell[2]],
oldNodeIdNewId[cell[3]],
surfId });
}
else throw new NotSupportedException();
}
//
surfId++;
}
}
WriteTriangles(sb, triangleNodeIdsSurfaceId);
WriteQuadrilaterals(sb, quadNodeIdsSurfaceId);
// Volume elements
int elementId;
FeElement element;
List<int[]> tetraNodeIdsSurfaceId = new List<int[]>();
List<int[]> hexaNodeIdsSurfaceId = new List<int[]>();
//
foreach (var part in parts)
{
for (int i = 0; i < part.Labels.Length; i++)
{
elementId = part.Labels[i];
element = mesh.Elements[elementId];
if (element is LinearTetraElement || element is ParabolicTetraElement)
{
tetraNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
oldNodeIdNewId[element.NodeIds[3]],
part.PartId });
}
//else if (element is LinearHexaElement || element is ParabolicHexaElement)
//{
// hexaNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
// oldNodeIdNewId[element.NodeIds[1]],
// oldNodeIdNewId[element.NodeIds[2]],
// oldNodeIdNewId[element.NodeIds[3]],
// oldNodeIdNewId[element.NodeIds[4]],
// oldNodeIdNewId[element.NodeIds[5]],
// part.PartId });
//}
else throw new CaeException("Mmg meshes only support tetrahedral volume elements.");
}
}
WriteTetrahedrons(sb, tetraNodeIdsSurfaceId);
WriteHexahedrons(sb, hexaNodeIdsSurfaceId);
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
public static void WriteSolution(string fileName, BasePart[] parts, FeMesh mesh, Dictionary<int, double> nodeIdValue)
{
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices order
HashSet<int> nodeIds = new HashSet<int>();
foreach (var part in parts) nodeIds.UnionWith(part.NodeLabels);
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(nodeIds.ToArray(), mesh);
// Solution at vertices
WriteSolutionAtVertices(sb, nodeCoorNodeId, nodeIdValue);
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
public static void WriteMaterial(string fileName, BasePart[] parts)
{
// File
StringBuilder sb = new StringBuilder();
//
sb.AppendLine("LSReferences");
sb.AppendLine(parts.Length.ToString());
sb.AppendLine();
//
int maxParId = -1;
foreach (var part in parts) if (part.PartId > maxParId) maxParId = part.PartId;
//
foreach (var part in parts)
{
sb.AppendFormat("{0} {1} {2}{3}", part.PartId, maxParId + 1, maxParId + 2, Environment.NewLine);
maxParId += 2;
}
//
File.WriteAllText(fileName, sb.ToString());
}
//
public static void WriteShellElementsFix(string fileName, int[] elementIds, BasePart part, FeMesh mesh,
bool keepModelEdges)
{
VisualizationData vis = part.Visualization;
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices
Dictionary<int, int> oldNodeIdNewId;
List<double[]> nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh);
WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId);
// Corners
List<int> cornerIds = new List<int>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]);
WriteCorners(sb, cornerIds);
// Elements
int elementId;
FeElement element;
List<int[]> triangleNodeIdsSurfaceId = new List<int[]>();
List<int[]> quadNodeIdsSurfaceId = new List<int[]>();
for (int i = 0; i < vis.CellIdsByFace.Length; i++)
{
for (int j = 0; j < vis.CellIdsByFace[i].Length; j++)
{
elementId = vis.CellIds[vis.CellIdsByFace[i][j]];
element = mesh.Elements[elementId];
if (element is LinearTriangleElement || element is ParabolicTriangleElement)
{
triangleNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
i + 1 });
}
else if (element is LinearQuadrilateralElement || element is ParabolicQuadrilateralElement)
{
quadNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
oldNodeIdNewId[element.NodeIds[3]],
i + 1 });
}
else throw new NotSupportedException();
}
}
// Triangles
WriteTriangles(sb, triangleNodeIdsSurfaceId);
// Quadrilaterals
WriteQuadrilaterals(sb, quadNodeIdsSurfaceId);
// RequiredElements
int[] requiredTriangleIds = part.Labels.Except(elementIds).ToArray();
WriteRequiredTriangles(sb, requiredTriangleIds);
// Edges
int id1, id2;
List<int[]> edgeNodeIdsEdgeId = new List<int[]>();
for (int i = 0; i < vis.EdgeCellIdsByEdge.Length; i++)
{
for (int j = 0; j < vis.EdgeCellIdsByEdge[i].Length; j++)
{
id1 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][0];
id2 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][1];
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], i + 1 });
}
}
//
if (keepModelEdges) WriteEdges(sb, edgeNodeIdsEdgeId);
// Ridges - all edges are ridges
int[] ridgeIds = new int[vis.EdgeCells.Length];
for (int i = 0; i < ridgeIds.Length; i++) ridgeIds[i] = i + 1;
WriteRidges(sb, ridgeIds);
// Required edges - keep edge cells connected to the vertices with only 2 edge cells: on the outside of the rectangle
//HashSet<int> requiredEdgeIds = new HashSet<int>();
//foreach (var cornerEntry in vertexEdgeIds)
//{
// if (cornerEntry.Value.Count == 2) requiredEdgeIds.UnionWith(cornerEntry.Value);
//}
//if (keepVetexEdges) WriteRequiredEdges(sb, requiredEdgeIds.ToArray());
// End
WriteEnd(sb);
//
File.WriteAllText(fileName, sb.ToString());
}
public static void WriteShellElements(string fileName, int[] elementIds, BasePart part, FeMesh mesh, bool keepModelEdges,
out Dictionary<int[], FeNode> midNodes)
{
CompareIntArray comparer = new CompareIntArray();
midNodes = new Dictionary<int[], FeNode>(comparer);
Dictionary<int[], FeNode> allMidNodes = new Dictionary<int[], FeNode>(comparer);
VisualizationData vis = part.Visualization;
// File
StringBuilder sb = new StringBuilder();
WriteHeading(sb);
// Vertices
int nodeId;
int numOfSignificantNodes;
FeNode node;
FeElement element;
Dictionary<int, int> oldNodeIdNewId;
HashSet<int> allNodeIds = new HashSet<int>();
List<double[]> nodeCoorNodeId = new List<double[]>();
// Use only vertices of the selected element set
for (int i = 0; i < elementIds.Length; i++)
{
element = mesh.Elements[elementIds[i]];
if (element is LinearTriangleElement || element is ParabolicTriangleElement)
numOfSignificantNodes = 3;
else if (element is LinearQuadrilateralElement || element is ParabolicQuadrilateralElement)
numOfSignificantNodes = 4;
else throw new NotSupportedException();
//
for (int j = 0; j < numOfSignificantNodes; j++)
{
nodeId = element.NodeIds[j];
if (!allNodeIds.Contains(nodeId))
{
node = mesh.Nodes[nodeId];
nodeCoorNodeId.Add(new double[] { node.X, node.Y, node.Z, node.Id });
allNodeIds.Add(nodeId);
}
}
}
WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId);
// Corners
List<int> cornerIds = new List<int>();
for (int i = 0; i < vis.VertexNodeIds.Length; i++)
{
nodeId = vis.VertexNodeIds[i];
if (allNodeIds.Contains(nodeId)) cornerIds.Add(oldNodeIdNewId[nodeId]);
}
WriteCorners(sb, cornerIds);
// Elements
int elementId;
int[] key;
bool parabolic;
HashSet<int> allElementIds = new HashSet<int>(elementIds); // for speedup
List<int[]> triangleNodeIdsSurfaceId = new List<int[]>();
List<int[]> quadNodeIdsSurfaceId = new List<int[]>();
HashSet<int[]> allElementEdges = new HashSet<int[]>(comparer);
for (int i = 0; i < vis.CellIdsByFace.Length; i++)
{
for (int j = 0; j < vis.CellIdsByFace[i].Length; j++)
{
elementId = vis.CellIds[vis.CellIdsByFace[i][j]];
if (allElementIds.Contains(elementId))
{
element = mesh.Elements[elementId];
if (element is LinearTriangleElement || element is ParabolicTriangleElement)
{
triangleNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
i + 1 });
//
parabolic = element is ParabolicTriangleElement;
//
key = Tools.GetSortedKey(element.NodeIds[0], element.NodeIds[1]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[3]]);
}
key = Tools.GetSortedKey(element.NodeIds[1], element.NodeIds[2]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[4]]);
}
key = Tools.GetSortedKey(element.NodeIds[2], element.NodeIds[0]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[5]]);
}
}
else if (element is LinearQuadrilateralElement || element is ParabolicQuadrilateralElement)
{
triangleNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[1]],
oldNodeIdNewId[element.NodeIds[2]],
i + 1 });
triangleNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
oldNodeIdNewId[element.NodeIds[2]],
oldNodeIdNewId[element.NodeIds[3]],
i + 1 });
//
parabolic = element is ParabolicQuadrilateralElement;
//
key = Tools.GetSortedKey(element.NodeIds[0], element.NodeIds[1]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[4]]);
}
key = Tools.GetSortedKey(element.NodeIds[1], element.NodeIds[2]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[5]]);
}
key = Tools.GetSortedKey(element.NodeIds[2], element.NodeIds[3]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[6]]);
}
key = Tools.GetSortedKey(element.NodeIds[3], element.NodeIds[0]);
if (!allElementEdges.Contains(key))
{
allElementEdges.Add(key);
if (parabolic) allMidNodes.Add(key, mesh.Nodes[element.NodeIds[7]]);
}
//quadNodeIdsSurfaceId.Add(new int[] { oldNodeIdNewId[element.NodeIds[0]],
// oldNodeIdNewId[element.NodeIds[1]],
// oldNodeIdNewId[element.NodeIds[2]],
// oldNodeIdNewId[element.NodeIds[3]],
// i + 1 });
}
else throw new NotSupportedException();
}
}
}
// Triangles
WriteTriangles(sb, triangleNodeIdsSurfaceId);
// Quadrilaterals
WriteQuadrilaterals(sb, quadNodeIdsSurfaceId);
// Edges
int id1, id2;
Dictionary<int[], int> edgeKeys = new Dictionary<int[], int>(comparer);
List<int[]> edgeNodeIdsEdgeId = new List<int[]>();
// Free edges
HashSet<int[]> freeEdgeCells = GetFreeEdgeCells(part);
// Model edges - first since they are numbered by the EdgeCellIdsByEdge
if (keepModelEdges)
{
for (int i = 0; i < vis.EdgeCellIdsByEdge.Length; i++)
{
for (int j = 0; j < vis.EdgeCellIdsByEdge[i].Length; j++)
{
id1 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][0];
id2 = vis.EdgeCells[vis.EdgeCellIdsByEdge[i][j]][1];
key = Tools.GetSortedKey(id1, id2);
if (!edgeKeys.ContainsKey(key) && allElementEdges.Contains(key))
{
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], i + 1 });
edgeKeys.Add(key, edgeNodeIdsEdgeId.Count);
}
}
}
}
// Other part nodeIds
HashSet<int> otherVisualizationNodeIds = new HashSet<int>();
foreach (var entry in mesh.Parts)
{
if (entry.Value != part)
otherVisualizationNodeIds.UnionWith(entry.Value.Visualization.GetNodeIds());
}
// Boundary edges - free edges of the new subPart
int edgeId;
int[] edgeCell;
List<int> requiredEdgeIds = new List<int>();
GeometryPart subPart = mesh.CreateGeometryPartFromElementIds(elementIds);
for (int i = 0; i < subPart.FreeEdgeCellIds.Length; i++)
{
edgeCell = subPart.Visualization.EdgeCells[subPart.FreeEdgeCellIds[i]];
id1 = edgeCell[0];
id2 = edgeCell[1];
key = Tools.GetSortedKey(id1, id2);
// Add boundary edges to all edges
if (!edgeKeys.TryGetValue(key, out edgeId))
{
edgeNodeIdsEdgeId.Add(new int[] { oldNodeIdNewId[id1], oldNodeIdNewId[id2], 0 });
edgeId = edgeNodeIdsEdgeId.Count;
edgeKeys.Add(key, edgeId);
}
// Free part edge nodes must not be kept as midside nodes
if (!freeEdgeCells.Contains(key))
{
requiredEdgeIds.Add(edgeId);
if (allMidNodes.Count > 0) midNodes.Add(key, allMidNodes[key]);
}
// Keep free edge midside nodes if they belong to other assembly parts
else
{
requiredEdgeIds.Add(edgeId);
if (allMidNodes.Count > 0 && otherVisualizationNodeIds.Contains(allMidNodes[key].Id))
midNodes.Add(key, allMidNodes[key]);
}
}
WriteEdges(sb, edgeNodeIdsEdgeId);
// Ridges - sharp or triple edges between faces - all edges are ridges
int[] ridgeIds = new int[edgeNodeIdsEdgeId.Count];
for (int i = 0; i < ridgeIds.Length; i++) ridgeIds[i] = i + 1;
WriteRidges(sb, ridgeIds);
// Required edges
WriteRequiredEdges(sb, requiredEdgeIds.ToArray());
// End
WriteEnd(sb);
//
if (midNodes.Count == 0) midNodes = null;
//
File.WriteAllText(fileName, sb.ToString());
}
//
private static void WriteHeading(StringBuilder sb)
{
sb.AppendLine("MeshVersionFormatted 2");
sb.AppendLine("Dimension 3");
}
//
private static List<double[]> GetNodeCoorNodeId(int[] nodeIds, FeMesh mesh)
{
// The same order is used for writing solution values
FeNode node;
List<double[]> nodeCoorNodeId = new List<double[]>();
foreach (var nodeId in nodeIds)
{
node = mesh.Nodes[nodeId];
nodeCoorNodeId.Add(new double[] { node.X, node.Y, node.Z, node.Id });
}
return nodeCoorNodeId;
}
private static void WriteVertices(StringBuilder sb, List<double[]> nodeCoorNodeId,
out Dictionary<int, int> oldNodeIdNewId)
{
int count = 1;
oldNodeIdNewId = new Dictionary<int, int>();
//
if (nodeCoorNodeId == null || nodeCoorNodeId.Count == 0) return;
// Vertices
sb.AppendLine();
sb.AppendLine("Vertices");
sb.AppendLine(nodeCoorNodeId.Count.ToString());
//
foreach (var nodeData in nodeCoorNodeId)
{
sb.AppendFormat("{0} {1} {2} {3}{4}", nodeData[0], nodeData[1], nodeData[2],
(int)(nodeData[3]), Environment.NewLine);
oldNodeIdNewId.Add((int)nodeData[3], count);
count++;
}
}
private static void WriteCorners(StringBuilder sb, IEnumerable<int> cornerIds)
{
if (cornerIds == null || cornerIds.Count() == 0) return;
//
sb.AppendLine();
sb.AppendLine("Corners");
sb.AppendLine(cornerIds.Count().ToString());
//
foreach (var cornerId in cornerIds)
{
sb.AppendFormat("{0}{1}", cornerId, Environment.NewLine);
}
}
private static void WriteSolutionAtVertices(StringBuilder sb, List<double[]> nodeCoorNodeId,
Dictionary<int, double> nodeIdValue)
{
if (nodeCoorNodeId == null || nodeCoorNodeId.Count == 0) return;
// Vertices
sb.AppendLine();
sb.AppendLine("SolAtVertices");
sb.AppendLine(nodeCoorNodeId.Count.ToString());
sb.AppendLine("1 1");
//
int nodeId;
double value;
foreach (var nodeData in nodeCoorNodeId)
{
nodeId = (int)nodeData[3];
value = (double)nodeIdValue[nodeId];
//
sb.AppendFormat("{0}{1}", value, Environment.NewLine);
}
}
//
private static void WriteEdges(StringBuilder sb, List<int[]> edgeCellEdgeId)
{
if (edgeCellEdgeId == null || edgeCellEdgeId.Count == 0) return;
//
sb.AppendLine();
sb.AppendLine("Edges");
sb.AppendLine(edgeCellEdgeId.Count.ToString());
foreach (var edgeData in edgeCellEdgeId)
{
sb.AppendFormat("{0} {1} {2}{3}", edgeData[0],
edgeData[1],
edgeData[2],
Environment.NewLine);
}
}
private static void WriteRidges(StringBuilder sb, int[] ridgeIds)
{
if (ridgeIds == null || ridgeIds.Length == 0) return;
//
sb.AppendLine();
sb.AppendLine("Ridges");
sb.AppendLine(ridgeIds.Length.ToString());
for (int i = 0; i < ridgeIds.Length; i++)
{
sb.AppendFormat("{0}{1}", ridgeIds[i], Environment.NewLine);
}
}
private static void WriteRequiredEdges(StringBuilder sb, int[] requiredEdgeIds)
{
if (requiredEdgeIds == null || requiredEdgeIds.Length == 0) return;
//
sb.AppendLine();
sb.AppendLine("RequiredEdges");
sb.AppendLine(requiredEdgeIds.Length.ToString());
for (int i = 0; i < requiredEdgeIds.Length; i++)
{
sb.AppendFormat("{0}{1}", requiredEdgeIds[i], Environment.NewLine);
}
}
//
private static void WriteTriangles(StringBuilder sb, List<int[]> elementNodeIdsElementId)
{
if (elementNodeIdsElementId == null || elementNodeIdsElementId.Count == 0) return;
//
sb.AppendLine();
sb.AppendLine("Triangles");
sb.AppendLine(elementNodeIdsElementId.Count.ToString());
//
foreach (var elementData in elementNodeIdsElementId)
{
sb.AppendFormat("{0} {1} {2} {3}{4}", elementData[0],
elementData[1],
elementData[2],
elementData[3],
Environment.NewLine);
}
}
private static void WriteQuadrilaterals(StringBuilder sb, List<int[]> elementNodeIdsElementId)
{
if (elementNodeIdsElementId == null || elementNodeIdsElementId.Count == 0) return;
//
sb.AppendLine();
sb.AppendLine("Quadrilaterals");
sb.AppendLine(elementNodeIdsElementId.Count.ToString());
//
foreach (var elementData in elementNodeIdsElementId)
{
sb.AppendFormat("{0} {1} {2} {3} {4}{5}", elementData[0],
elementData[1],
elementData[2],
elementData[3],
elementData[4], // id
Environment.NewLine);
}
}
private static void WriteRequiredTriangles(StringBuilder sb, int[] requiredTrianglesIds)
{
if (requiredTrianglesIds == null || requiredTrianglesIds.Length == 0) return;
//
sb.AppendLine();
sb.AppendLine("RequiredTriangles");
sb.AppendLine(requiredTrianglesIds.Length.ToString());
for (int i = 0; i < requiredTrianglesIds.Length; i++)
{
sb.AppendFormat("{0}{1}", requiredTrianglesIds[i], Environment.NewLine);
}
}
private static void WriteTetrahedrons(StringBuilder sb, List<int[]> elementNodeIdsElementId)
{
if (elementNodeIdsElementId == null || elementNodeIdsElementId.Count == 0) return;
//
sb.AppendLine();
sb.AppendLine("Tetrahedra");
sb.AppendLine(elementNodeIdsElementId.Count.ToString());
//
foreach (var elementData in elementNodeIdsElementId)
{
sb.AppendFormat("{0} {1} {2} {3} {4}{5}", elementData[0],
elementData[1],
elementData[2],
elementData[3],
elementData[4],
Environment.NewLine);
}
}
private static void WriteHexahedrons(StringBuilder sb, List<int[]> elementNodeIdsElementId)
{
if (elementNodeIdsElementId == null || elementNodeIdsElementId.Count == 0) return;
//
sb.AppendLine();
sb.AppendLine("Hexahedra");
sb.AppendLine(elementNodeIdsElementId.Count.ToString());
//
foreach (var elementData in elementNodeIdsElementId)
{
sb.AppendFormat("{0} {1} {2} {3} {4} {5} {6}{7}", elementData[0],
elementData[1],
elementData[2],
elementData[3],
elementData[4],
elementData[5],
elementData[6],
Environment.NewLine);
}
}
//
private static void WriteEnd(StringBuilder sb)
{
sb.AppendLine();
sb.AppendLine("End");
}
//
private static HashSet<int[]> GetFreeEdgeCells(BasePart part)
{
int[] key;
int[] edgeCell;
CompareIntArray comparer = new CompareIntArray();
HashSet<int[]> freeEdgeCells = new HashSet<int[]>(comparer);
HashSet<int> freeEdgeIds = part.Visualization.GetFreeEdgeIds();
//
foreach (var edgeId in freeEdgeIds)
{
foreach (var edgeCellId in part.Visualization.EdgeCellIdsByEdge[edgeId])
{
edgeCell = part.Visualization.EdgeCells[edgeCellId];
key = Tools.GetSortedKey(edgeCell[0], edgeCell[1]);
freeEdgeCells.Add(key);
}
}
return freeEdgeCells;
//int[][] cells = part.Visualization.Cells;
//CompareIntArray comparer = new CompareIntArray();
//Dictionary<int[], byte[]> allEdges = new Dictionary<int[], byte[]>(comparer);
////
//int[] key;
//byte[] count;
//int[][] cellEdges;
//// Get all edges
//for (int i = 0; i < cells.Length; i++)
//{
// cellEdges = FeMesh.GetVisualizationEdgeCells(cells[i], ElementFaceType.Face);
// //
// foreach (var cellEdge in cellEdges)
// {
// key = Tools.GetSortedKey(cellEdge[0], cellEdge[1]);
// if (allEdges.TryGetValue(key, out count)) count[0]++;
// else allEdges.Add(key, new byte[] { 1 });
// }
//}
////
//HashSet<int[]> freeEdges = new HashSet<int[]>(comparer);
//foreach (var entry in allEdges)
//{
// if (entry.Value[0] == 1) freeEdges.Add(entry.Key);
//}
////
//return freeEdges;
}
private static FeNode GetOrCreateMidNode(FeNode n1, FeNode n2, ref Dictionary<int[], FeNode> midNodes, ref int maxNodeId)
{
int[] ids;
if (n1.Id < n2.Id) ids = new int[] { n1.Id, n2.Id };
else ids = new int[] { n2.Id, n1.Id };
//
FeNode newNode;
if (!midNodes.TryGetValue(ids, out newNode))
{
maxNodeId++;
newNode = new FeNode(maxNodeId, GetMidNodeCoor(n1, n2));
midNodes.Add(ids, newNode);
}
return newNode;
}
private static double[] GetMidNodeCoor(FeNode n1, FeNode n2)
{
double[] coor = new double[3];
coor[0] = 0.5 * (n1.X + n2.X);
coor[1] = 0.5 * (n1.Y + n2.Y);
coor[2] = 0.5 * (n1.Z + n2.Z);
return coor;
}
}
}