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 oldNodeIdNewId; List nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh); WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId); // Corners List cornerIds = new List(); for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]); WriteCorners(sb, cornerIds); // Triangles int elementId; FeElement element; List elementNodeIdsSurfaceId = new List(); 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 edgeIds; // Collect all edge cells connected to a vertex Dictionary> vertexEdgeIds = new Dictionary>(); for (int i = 0; i < vis.VertexNodeIds.Length; i++) vertexEdgeIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]], new List()); // List edgeNodeIdsEdgeId = new List(); 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 requiredEdgeIds = new HashSet(); 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 oldNodeIdNewId; List nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh); WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId); // Corners List cornerIds = new List(); 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 edgeIds; // Collect all edge cells connected to a vertex Dictionary> vertexEdgeIds = new Dictionary>(); for (int i = 0; i < vis.VertexNodeIds.Length; i++) vertexEdgeIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]], new List()); // List edgeNodeIdsEdgeId = new List(); 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 requiredEdgeIds = new HashSet(); foreach (var cornerEntry in vertexEdgeIds) { if (cornerEntry.Value.Count == 2) requiredEdgeIds.UnionWith(cornerEntry.Value); } if (keepVertexEdges) WriteRequiredEdges(sb, requiredEdgeIds.ToArray()); // Triangles int[] cell; List elementNodeIdsSurfaceId = new List(); 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 nodeIdValue) { // File StringBuilder sb = new StringBuilder(); WriteHeading(sb); // Vertices order List 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 allNodeIds = new HashSet(); foreach (var part in parts) allNodeIds.UnionWith(part.NodeLabels); List nodeCoorNodeId = GetNodeCoorNodeId(allNodeIds.ToArray(), mesh); Dictionary oldNodeIdNewId; WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId); // Corners HashSet cornerIds = new HashSet(); 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 edgeIds; List ridgeIds = new List(); // Collect all edge cells connected to a vertex Dictionary> vertexEdgeIds = new Dictionary>(); List edgeNodeIdsEdgeId = new List(); // 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()); } // 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 requiredEdgeIds = new HashSet(); 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 triangleNodeIdsSurfaceId = new List(); List quadNodeIdsSurfaceId = new List(); 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 tetraNodeIdsSurfaceId = new List(); List hexaNodeIdsSurfaceId = new List(); // 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 nodeIdValue) { // File StringBuilder sb = new StringBuilder(); WriteHeading(sb); // Vertices order HashSet nodeIds = new HashSet(); foreach (var part in parts) nodeIds.UnionWith(part.NodeLabels); List 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 oldNodeIdNewId; List nodeCoorNodeId = GetNodeCoorNodeId(part.NodeLabels, mesh); WriteVertices(sb, nodeCoorNodeId, out oldNodeIdNewId); // Corners List cornerIds = new List(); for (int i = 0; i < vis.VertexNodeIds.Length; i++) cornerIds.Add(oldNodeIdNewId[vis.VertexNodeIds[i]]); WriteCorners(sb, cornerIds); // Elements int elementId; FeElement element; List triangleNodeIdsSurfaceId = new List(); List quadNodeIdsSurfaceId = new List(); 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 edgeNodeIdsEdgeId = new List(); 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 requiredEdgeIds = new HashSet(); //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 midNodes) { CompareIntArray comparer = new CompareIntArray(); midNodes = new Dictionary(comparer); Dictionary allMidNodes = new Dictionary(comparer); VisualizationData vis = part.Visualization; // File StringBuilder sb = new StringBuilder(); WriteHeading(sb); // Vertices int nodeId; int numOfSignificantNodes; FeNode node; FeElement element; Dictionary oldNodeIdNewId; HashSet allNodeIds = new HashSet(); List nodeCoorNodeId = new List(); // 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 cornerIds = new List(); 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 allElementIds = new HashSet(elementIds); // for speedup List triangleNodeIdsSurfaceId = new List(); List quadNodeIdsSurfaceId = new List(); HashSet allElementEdges = new HashSet(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 edgeKeys = new Dictionary(comparer); List edgeNodeIdsEdgeId = new List(); // Free edges HashSet 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 otherVisualizationNodeIds = new HashSet(); 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 requiredEdgeIds = new List(); 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 GetNodeCoorNodeId(int[] nodeIds, FeMesh mesh) { // The same order is used for writing solution values FeNode node; List nodeCoorNodeId = new List(); 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 nodeCoorNodeId, out Dictionary oldNodeIdNewId) { int count = 1; oldNodeIdNewId = new Dictionary(); // 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 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 nodeCoorNodeId, Dictionary 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 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 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 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 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 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 GetFreeEdgeCells(BasePart part) { int[] key; int[] edgeCell; CompareIntArray comparer = new CompareIntArray(); HashSet freeEdgeCells = new HashSet(comparer); HashSet 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 allEdges = new Dictionary(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 freeEdges = new HashSet(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 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; } } }