using CaeGlobals; using CaeMesh; using CaeModel; using FileInOut.Output.Calculix; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; #pragma warning disable IDE0130 namespace FileInOut.Output { [Serializable] public static class CalculixFileWriter { // Methods public static void Write(string fileName, FeModel model, ConvertPyramidsToEnum convertPyramidsTo, Dictionary deformations = null) { List keywords = GetAllKeywords(model, convertPyramidsTo, deformations); // Write file StringBuilder sb = new StringBuilder(); foreach (var keyword in keywords) { WriteKeywordRecursively(sb, keyword); } // Write to file in multiple steps int step = 10_000_000; int upper; using (StreamWriter sw = new StreamWriter(fileName, false)) { for (int i = 0; i < sb.Length; i+=step) { upper = Math.Min(sb.Length - i, step); sw.Write(sb.ToString(i, upper)); } } } private static void Clean(FeModel model) { foreach (var entry in model.Sections) { if (entry.Value is MassSection ms) { if (ms is PointMassSection pms) { pms.ElementSetName = null; } } } } public static void WriteMaterials(string fileName, FeModel model, string[] materialNames) { List keywords = new List(); // 1. Heading CalTitle title = new CalTitle("Heading", ""); keywords.Add(title); AppendHeading(model, title); // 2. Materials title = new CalTitle("Materials", ""); keywords.Add(title); AppendMaterials(model, title, null, materialNames, true); // 3. Write file StringBuilder sb = new StringBuilder(); foreach (var keyword in keywords) { WriteKeywordRecursively(sb, keyword); } File.WriteAllText(fileName, sb.ToString()); } // 添加2025-8-27 public static List GetAllKeywords(FeModel model, ConvertPyramidsToEnum convertPyramidsTo, Dictionary deformations = null) { List keywords = GetModelKeywords(model, convertPyramidsTo, deformations); // Add user keywords if (model.CalculixUserKeywords != null) { foreach (var entry in model.CalculixUserKeywords) { // Deep clone to prevent the changes in user keywords AddUserKeywordByIndices(keywords, entry.Key, entry.Value.DeepClone()); } } return keywords; } public static List GetModelKeywords(FeModel model, ConvertPyramidsToEnum convertPyramidsTo, Dictionary deformations = null, bool addAllMaterials = false) { // Clone surfaces OrderedDictionary originalSurfaces = model.Mesh.Surfaces; OrderedDictionary originalElementSets = model.Mesh.ElementSets; // model.Mesh.Surfaces = originalSurfaces.DeepClone(); model.Mesh.ElementSets = originalElementSets.DeepClone(); Dictionary replacedElements = new Dictionary(); // try { // Only keywords from the model, not user keywords // Always add a title keyword to get all possible keyword types to the keyword editor int maxNodeId = model.Mesh.MaxNodeId; int maxElementId = model.Mesh.MaxElementId; List additionalNodes = new List(); List additionalNodeSets = new List(); List additionalElementKeywords = new List(); HashSet additionalElementSetNames = new HashSet(); Dictionary referencePointsNodeIds; Dictionary referencePointsNodeSetNames; Dictionary> coordinateSystemNodeSets = new Dictionary>(); List additionalSectionData = new List(); List additionalMaterials = new List(); List additionalBoundaryConditions = new List(); OrderedDictionary> preTensionLoads; List equationParameters = new List(); // // Collect pre-tension loads to use them in reference point preparation GetPretensionLoads(model, out preTensionLoads); // Prepare reference points GetReferencePoints(model, preTensionLoads, ref maxNodeId, ref additionalNodeSets, out referencePointsNodeSetNames, out referencePointsNodeIds); // Prepare coordinate system-node set pairs GetCoordinateSystemNodeSet(model, referencePointsNodeSetNames, ref coordinateSystemNodeSets); // Fix pyramid surfaces FixPyramidSurfaces(model, convertPyramidsTo, ref replacedElements, ref additionalElementSetNames); // Prepare mass sections GetMassSections(model, referencePointsNodeIds, ref maxElementId, ref additionalElementKeywords, ref additionalElementSetNames, ref additionalSectionData); // Prepare point springs GetPointSprings(model, referencePointsNodeIds, ref maxElementId, ref additionalElementKeywords, ref additionalElementSetNames, ref additionalSectionData); // Collect compression only constraints GetCompressionOnlyConstraintData(model, ref maxNodeId, ref maxElementId, ref additionalNodes, ref additionalNodeSets, ref additionalElementKeywords, ref additionalElementSetNames, ref additionalSectionData, ref additionalMaterials, ref additionalBoundaryConditions, ref equationParameters); // 修改于: 2025-8-27 by Luke CalTitle title; List keywords = new List(); // 1. Heading title = new CalTitle("Heading", ""); keywords.Add(title); AppendHeading(model, title); // 2. Submodel string[] nodeSetNames = GetAllSubmodelNodeSetNames(model); if (nodeSetNames.Length > 0) { title = new CalTitle("Submodel", ""); keywords.Add(title); AppendSubmodel(model, nodeSetNames, title); } // 3. Nodes title = new CalTitle("Nodes", ""); keywords.Add(title); AppendNodes(model, additionalNodes, referencePointsNodeIds, deformations, title); // 4. Elements title = new CalTitle("Elements", ""); keywords.Add(title); AppendElements(model, additionalElementKeywords, title, convertPyramidsTo); // 5. Node sets title = new CalTitle("Node sets", ""); keywords.Add(title); AppendNodeSets(model, additionalNodeSets, title); // 6. Element sets title = new CalTitle("Element sets", ""); keywords.Add(title); AppendElementSets(model, additionalElementSetNames, title); // 7. Surfaces title = new CalTitle("Surfaces", ""); keywords.Add(title); AppendSurfaces(model, title); // 8. Physical constants title = new CalTitle("Physical constants", ""); keywords.Add(title); AppendPhysicalConstants(model, title); // 9. Coordinate systems title = new CalTitle("Coordinate systems", ""); keywords.Add(title); AppendCoordinateSystems(coordinateSystemNodeSets, title); // 10. Materials title = new CalTitle("Materials", ""); keywords.Add(title); AppendMaterials(model, title, additionalMaterials, null, addAllMaterials); // 11. Sections title = new CalTitle("Sections", ""); keywords.Add(title); AppendSections(model, additionalSectionData, title); // 12. Pre-tension sections title = new CalTitle("Pre-tension sections", ""); keywords.Add(title); AppendPreTensionSections(preTensionLoads, referencePointsNodeIds, title); // 13. Constraints title = new CalTitle("Constraints", ""); keywords.Add(title); AppendConstraints(model, referencePointsNodeIds, equationParameters, title); // 14. Surface interactions title = new CalTitle("Surface interactions", ""); keywords.Add(title); AppendSurfaceInteractions(model, title); // 15. Contact pairs title = new CalTitle("Contact pairs", ""); keywords.Add(title); AppendContactPairs(model, title); // 16. Amplitudes title = new CalTitle("Amplitudes", ""); keywords.Add(title); AppendAmplitudes(model, title); // 17. Initial conditions title = new CalTitle("Initial conditions", ""); keywords.Add(title); AppendInitialConditions(model, referencePointsNodeIds, title); // 18. Steps title = new CalTitle("Steps", ""); keywords.Add(title); AppendSteps(model, additionalBoundaryConditions, referencePointsNodeIds, title); // return keywords; } catch (Exception ex) { throw ex; } finally { model.Mesh.ElementSets = originalElementSets; model.Mesh.Surfaces = originalSurfaces; // foreach (var entry in replacedElements) { model.Mesh.Elements[entry.Key] = entry.Value; } // Clean(model); } } private static void GetPretensionLoads(FeModel model, out OrderedDictionary> preTensionLoads) { string name; List preTensionLoadsList; preTensionLoads = new OrderedDictionary>("Pretension Loads", StringComparer.OrdinalIgnoreCase); foreach (var step in model.StepCollection.StepsList) { foreach (var entry in step.Loads) { if (entry.Value is PreTensionLoad ptl) { name = ptl.SurfaceName; if (!ptl.AutoComputeDirection) name += "_" + ptl.X.ToString() + ptl.Y.ToString() + ptl.Z.ToString(); // if (preTensionLoads.TryGetValue(name, out preTensionLoadsList)) preTensionLoadsList.Add(ptl); else preTensionLoads.Add(name, new List() { ptl }); } } } } private static void GetReferencePoints(FeModel model, OrderedDictionary> preTensionLoads, ref int maxNodeId, ref List additionalNodeSets, out Dictionary referencePointsNodeSetNames, out Dictionary referencePointsNodeIds) { HashSet allNodeSetNames = new HashSet(model.Mesh.NodeSets.Keys); foreach (var nodeSet in additionalNodeSets) allNodeSetNames.Add(nodeSet.Name); // string[] nodeSetNames; FeNodeSet rpNodeSet; referencePointsNodeIds = new Dictionary(); referencePointsNodeSetNames = new Dictionary(); if (model.Mesh != null) { // Fill reference point nodes int id = maxNodeId; FeReferencePoint rp; foreach (var entry in model.Mesh.ReferencePoints) { rp = entry.Value; // Check name rp.RefNodeSetName = rp.Name + FeReferencePoint.RefName + id + 1; if (allNodeSetNames.Contains(rp.RefNodeSetName)) rp.RefNodeSetName = allNodeSetNames.GetNextNumberedKey(rp.RefNodeSetName); rp.RotNodeSetName = rp.Name + FeReferencePoint.RotName + id + 2; if (allNodeSetNames.Contains(rp.RotNodeSetName)) rp.RotNodeSetName = allNodeSetNames.GetNextNumberedKey(rp.RotNodeSetName); // rpNodeSet = new FeNodeSet(rp.RefNodeSetName, new int[] { id + 1 }); additionalNodeSets.Add(rpNodeSet); allNodeSetNames.Add(rpNodeSet.Name); // rpNodeSet = new FeNodeSet(rp.RotNodeSetName, new int[] { id + 2 }); additionalNodeSets.Add(rpNodeSet); allNodeSetNames.Add(rpNodeSet.Name); // nodeSetNames = new string[] { rp.RefNodeSetName, rp.RotNodeSetName }; referencePointsNodeSetNames.Add(entry.Key, nodeSetNames); referencePointsNodeIds.Add(entry.Key, new int[] { id + 1, id + 2 }); id += 2; } // foreach (var entry in preTensionLoads) { referencePointsNodeIds.Add(entry.Key, new int[] { id + 1 }); id++; } // maxNodeId = id; } } private static void GetCoordinateSystemNodeSet(FeModel model, Dictionary referencePointsNodeSetNames, ref Dictionary> coordinateSystemNodeSets) { if (model == null || model.StepCollection == null || model.Mesh.CoordinateSystems == null || model.Mesh.CoordinateSystems.Count() == 0) return; // string nodeSetName; HashSet nodeSetNames; FeSurface surface; FeReferencePoint referencePoint; CoordinateSystem coordinateSystem; // Boundary conditions foreach (var boundaryCondition in model.StepCollection.GetAllBoundaryConditions()) { if (boundaryCondition.Active && model.Mesh.CoordinateSystems.TryGetValue(boundaryCondition.CoordinateSystemName, out coordinateSystem) && coordinateSystem != null && boundaryCondition is DisplacementRotation displacementRotation) { // Node set if (displacementRotation.RegionType == RegionTypeEnum.NodeSetName) { nodeSetName = displacementRotation.RegionName; if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) nodeSetNames.Add(nodeSetName); else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } // Surface else if (displacementRotation.RegionType == RegionTypeEnum.SurfaceName) { surface = model.Mesh.Surfaces[displacementRotation.RegionName]; nodeSetName = surface.NodeSetName; if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) nodeSetNames.Add(nodeSetName); else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } // Reference point - user coordinate systems do not work for reference points else if (displacementRotation.RegionType == RegionTypeEnum.ReferencePointName) { //referencePoint = model.Mesh.ReferencePoints[displacementRotation.RegionName]; //nodeSetName = referencePointsNodeSetNames[referencePoint.Name][0]; //// //if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) // nodeSetNames.Add(nodeSetName); //else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } } } // Loads foreach (var load in model.StepCollection.GetAllLoads()) { if (load.Active && model.Mesh.CoordinateSystems.TryGetValue(load.CoordinateSystemName, out coordinateSystem) && coordinateSystem != null) { if (load is CLoad cLoad) { // Node set if (load.RegionType == RegionTypeEnum.NodeSetName) { nodeSetName = load.RegionName; if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) nodeSetNames.Add(nodeSetName); else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } // Reference point else if (load.RegionType == RegionTypeEnum.ReferencePointName) { referencePoint = model.Mesh.ReferencePoints[load.RegionName]; nodeSetName = referencePointsNodeSetNames[referencePoint.Name][0]; // if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) nodeSetNames.Add(nodeSetName); else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } } else if (load is STLoad stLoad) { // Surface if (stLoad.RegionType == RegionTypeEnum.SurfaceName) { surface = model.Mesh.Surfaces[stLoad.RegionName]; nodeSetName = surface.NodeSetName; if (coordinateSystemNodeSets.TryGetValue(coordinateSystem, out nodeSetNames)) nodeSetNames.Add(nodeSetName); else coordinateSystemNodeSets.Add(coordinateSystem, new HashSet() { nodeSetName }); } } } } } private static void FixPyramidSurfaces(FeModel model, ConvertPyramidsToEnum convertPyramidsTo, ref Dictionary replacedElements, ref HashSet additionalElementSetNames) { // Determine if there are any pyramids in the model List pyramidContainingParts = new List(); foreach (var entry in model.Mesh.Parts) { if (entry.Value.ElementTypes.Contains(typeof(LinearPyramidElement)) || entry.Value.ElementTypes.Contains(typeof(ParabolicPyramidElement))) pyramidContainingParts.Add(entry.Value); } // if (pyramidContainingParts.Count > 0) { // Create a mapping from pyramid faces to wedge or hex faces Dictionary pyramidToNormalFaceName; if (convertPyramidsTo == ConvertPyramidsToEnum.Wedges) { pyramidToNormalFaceName = new Dictionary() {{ FeFaceName.S1, FeFaceName.S5 }, { FeFaceName.S2, FeFaceName.S1 }, { FeFaceName.S3, FeFaceName.S4 }, { FeFaceName.S4, FeFaceName.S2 }, { FeFaceName.S5, FeFaceName.S3 }}; } else if (convertPyramidsTo == ConvertPyramidsToEnum.Hexahedrons) { pyramidToNormalFaceName = new Dictionary() {{ FeFaceName.S1, FeFaceName.S1 }, { FeFaceName.S2, FeFaceName.S3 }, { FeFaceName.S3, FeFaceName.S4 }, { FeFaceName.S4, FeFaceName.S5 }, { FeFaceName.S5, FeFaceName.S6 }}; } else throw new NotSupportedException(); // Type elementType; FeElement element; HashSet elementIds = new HashSet(); HashSet allPyramidElementIds = new HashSet(); foreach (var part in pyramidContainingParts) elementIds.UnionWith(part.Labels); // Collect all pyramid element ids foreach (var elementId in elementIds) { element = model.Mesh.Elements[elementId]; elementType = element.GetType(); if (elementType == typeof(LinearPyramidElement) || elementType == typeof(ParabolicPyramidElement)) { allPyramidElementIds.Add(elementId); replacedElements.Add(element.Id, element); // if (element is LinearPyramidElement lpe) { if (convertPyramidsTo == ConvertPyramidsToEnum.Wedges) model.Mesh.Elements[elementId] = lpe.ConvertToWedge(); else if (convertPyramidsTo == ConvertPyramidsToEnum.Hexahedrons) model.Mesh.Elements[elementId] = lpe.ConvertToHex(); else throw new NotSupportedException(); } else if (element is ParabolicPyramidElement ppe) { if (convertPyramidsTo == ConvertPyramidsToEnum.Wedges) model.Mesh.Elements[elementId] = ppe.ConvertToWedge(); else if (convertPyramidsTo == ConvertPyramidsToEnum.Hexahedrons) model.Mesh.Elements[elementId] = ppe.ConvertToHex(); else throw new NotSupportedException(); } else throw new NotSupportedException(); } } // bool needFixing; string name; FeFaceName faceName; FeSurface surface; FeSurface fixedSurface; FeElementSet elementSet; HashSet normalElementsIds; HashSet pyramidElementsIds; Dictionary> faceNameElementIds; HashSet reservedElementSetNames = model.Mesh.GetReservedElementSetNames(); // foreach (var surfaceEntry in model.Mesh.Surfaces) { // Determine if the surface contain pyramid elements needFixing = false; surface = surfaceEntry.Value; foreach (var entry in surface.ElementFaces) { elementSet = model.Mesh.ElementSets[entry.Value]; if (allPyramidElementIds.Intersect(elementSet.Labels).Count() > 0) { needFixing = true; break; } } // If the surface contains pyramid elements if (needFixing) { // Collect pyramid and normal element ids separately faceNameElementIds = new Dictionary>(); foreach (var entry in surface.ElementFaces) { elementSet = model.Mesh.ElementSets[entry.Value]; pyramidElementsIds = new HashSet(allPyramidElementIds.Intersect(elementSet.Labels)); normalElementsIds = new HashSet(elementSet.Labels.Except(pyramidElementsIds)); // if (normalElementsIds.Count > 0) { faceName = entry.Key; if (faceNameElementIds.TryGetValue(faceName, out elementIds)) elementIds.UnionWith(normalElementsIds); else faceNameElementIds.Add(faceName, normalElementsIds); } // if (pyramidElementsIds.Count > 0) { faceName = pyramidToNormalFaceName[entry.Key]; if (faceNameElementIds.TryGetValue(faceName, out elementIds)) elementIds.UnionWith(pyramidElementsIds); else faceNameElementIds.Add(faceName, pyramidElementsIds); } } // Create new surface with the same name fixedSurface = new FeSurface(surface.Name); // foreach (var entry in faceNameElementIds) { // Get element set name name = surface.Name + "_Pyramid_" + entry.Key; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // Create new element set elementSet = new FeElementSet(name, entry.Value.ToArray()); model.Mesh.ElementSets.Add(elementSet.Name, elementSet); additionalElementSetNames.Add(elementSet.Name); // fixedSurface.AddElementFace(entry.Key, elementSet.Name); // fixedSurface.NodeSetName = surface.NodeSetName; } // Add fixed surface model.Mesh.Surfaces[fixedSurface.Name] = fixedSurface; } } } } private static void GetMassSections(FeModel model, Dictionary referencePointsNodeIds, ref int maxElementId, ref List additionalElementKeywords, ref HashSet additionalElementSetNames, ref List additionalSectionData) { double aSum; double nodalMassFactor; double nodalMass; string name; List elementIds; FeElement element; FeNodeSet nodeSet; FeElementSet elementSet; FeSurface surface; FeReferencePoint referencePoint; MassSectionData massSectionData; Dictionary nodalValues; CalElement calElement; HashSet reservedElementSetNames = model.Mesh.GetReservedElementSetNames(); // foreach (var entry in model.Sections) { if (entry.Value is MassSection ms) { if (ms is PointMassSection pms) { if (pms.RegionType == RegionTypeEnum.NodeSetName) { elementIds = new List(); nodeSet = model.Mesh.NodeSets[pms.RegionName]; nodalMass = pms.Mass.Value; // foreach (var nodeId in nodeSet.Labels) { // Name name = pms.Name + "_NID_" + nodeId; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // Element keyword maxElementId++; element = new MassElement(maxElementId, new int[] { nodeId }); calElement = new CalElement(FeElementType0D.Mass.ToString(), name, new List { element }); additionalElementKeywords.Add(calElement); elementIds.Add(maxElementId); // Mass section massSectionData = new MassSectionData("NID_" + nodeId, name, nodalMass); additionalSectionData.Add(massSectionData); } // Add elements in sets name = pms.Name + "_All"; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // elementSet = new FeElementSet(name, elementIds.ToArray()); model.Mesh.ElementSets.Add(elementSet.Name, elementSet); additionalElementSetNames.Add(elementSet.Name); // pms.ElementSetName = name; // temporary storage } else if (pms.RegionType == RegionTypeEnum.ReferencePointName) { elementIds = new List(); referencePoint = model.Mesh.ReferencePoints[pms.RegionName]; int nodeId = referencePointsNodeIds[referencePoint.Name][0]; nodalMass = pms.Mass.Value; // Name name = pms.Name + "_RP_" + referencePoint.Name; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // Element keyword maxElementId++; element = new MassElement(maxElementId, new int[] { nodeId }); calElement = new CalElement(FeElementType0D.Mass.ToString(), name, new List { element }); additionalElementKeywords.Add(calElement); elementIds.Add(maxElementId); // Mass section massSectionData = new MassSectionData("NID_" + nodeId, name, nodalMass); additionalSectionData.Add(massSectionData); // Add elements in sets pms.ElementSetName = name; // temporary storage } else throw new NotSupportedException(); } else if (ms is DistributedMassSection dms) { elementIds = new List(); surface = model.Mesh.Surfaces[dms.RegionName]; nodeSet = model.Mesh.NodeSets[surface.NodeSetName]; model.GetDistributedNodalValuesFromSurface(surface.Name, out nodalValues, out aSum); nodalMassFactor = dms.Mass.Value / aSum; // foreach (var nodeId in nodeSet.Labels) { // Name name = dms.Name + "_NID_" + nodeId; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // Element keyword maxElementId++; element = new MassElement(maxElementId, new int[] { nodeId }); calElement = new CalElement(FeElementType0D.Mass.ToString(), name, new List { element }); additionalElementKeywords.Add(calElement); elementIds.Add(maxElementId); // Mass section nodalMass = nodalValues[nodeId] * nodalMassFactor; massSectionData = new MassSectionData("NID_" + nodeId, name, nodalMass); additionalSectionData.Add(massSectionData); } // Add elements in sets name = dms.Name + "_All"; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // elementSet = new FeElementSet(name, elementIds.ToArray()); model.Mesh.ElementSets.Add(elementSet.Name, elementSet); additionalElementSetNames.Add(elementSet.Name); // dms.ElementSetName = name; // temporary storage } else throw new NotSupportedException(); } } } private static void GetPointSprings(FeModel model, Dictionary referencePointsNodeIds, ref int maxElementId, ref List additionalElementKeywords, ref HashSet additionalElementSetNames, ref List additionalSectionData) { if (model.Mesh != null) { bool twoD = model.Properties.ModelSpace.IsTwoD(); int count; int[] elementIds; int[] refPointIds; int[] directions; double[] stiffnesses; string name; int elementId = maxElementId; FeNodeSet nodeSet; FeElementSet elementSet; List newElements; List oneSpringElements; // Collect point and surface springs Dictionary activeSprings = new Dictionary(); foreach (var entry in model.Constraints) { if (entry.Value is PointSpring ps && ps.Active) activeSprings.Add(ps.Name, new PointSpringData[] { new PointSpringData(ps) }); else if (entry.Value is SurfaceSpring ss && ss.Active) activeSprings.Add(ss.Name, model.GetPointSpringsFromSurfaceSpring(ss)); } // HashSet reservedElementSetNames = model.Mesh.GetReservedElementSetNames(); // foreach (var entry in activeSprings) { oneSpringElements = new List(); // foreach (PointSpringData psd in entry.Value) { directions = psd.GetSpringDirections(); stiffnesses = psd.GetSpringStiffnessValues(); // if (directions.Length == 0) continue; // for (int i = 0; i < directions.Length; i++) { // Name name = psd.Name + "_DOF_" + directions[i]; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // newElements = new List(); // Node id if (psd.RegionType == RegionTypeEnum.NodeId) { newElements.Add(new LinearSpringElement(elementId + 1, new int[] { psd.NodeId })); elementId++; } // Node set else if (psd.RegionType == RegionTypeEnum.NodeSetName) { if (model.Mesh.NodeSets.TryGetValue(psd.RegionName, out nodeSet)) { foreach (var label in nodeSet.Labels) { newElements.Add(new LinearSpringElement(elementId + 1, new int[] { label })); elementId++; } } } // Reference point else if (psd.RegionType == RegionTypeEnum.ReferencePointName) { if (referencePointsNodeIds.TryGetValue(psd.RegionName, out refPointIds)) { newElements.Add(new LinearSpringElement(elementId + 1, new int[] { refPointIds[0] })); elementId++; } } else throw new NotSupportedException(); // Get element ids count = 0; elementIds = new int[newElements.Count]; foreach (var element in newElements) elementIds[count++] = element.Id; // Add items elementSet = new FeElementSet(name, elementIds); model.Mesh.ElementSets.Add(elementSet.Name, elementSet); additionalElementSetNames.Add(elementSet.Name); additionalSectionData.Add(new LinearSpringSectionData("LinearSpringSection", name, directions[i], stiffnesses[i])); oneSpringElements.AddRange(newElements); } } // Add elements in sets name = entry.Key + "_All"; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); additionalElementKeywords.Add(new CalElement(FeElementTypeSpring.SPRING1.ToString(), name, oneSpringElements)); } // maxElementId = elementId; } } private static void GetCompressionOnlyConstraintData(FeModel model, ref int maxNodeId, ref int maxElementId, ref List additionalNodes, ref List additionalNodeSets, ref List additionalElementKeywords, ref HashSet additionalElementSetNames, ref List additionalSectionData, ref List additionalMaterials, ref List additionalBoundaryConditions, ref List equationParameters) { HashSet elementIdsHash = new HashSet(); // bool twoD = model.Properties.ModelSpace.IsTwoD(); bool shellEdgeFace; bool shellElement; bool nonLinear = false; double[] faceNormal; FeElement element; FeElementSet elementSet; FeSurface surface; Vec3D normalVec; List nodeNormals; Dictionary> nodeIdNodeNormals = new Dictionary>(); // double[] normal; Dictionary nodeIdNormal = new Dictionary(); int count; int newNodeId = maxNodeId; int newElementId = maxElementId; List elementIds; string name; // FeNode node1; FeNode node2; List bcNodeIds = new List(); LinearGapElement gapElement; List elementsToAdd = new List(); double clearance; double area; double nodeStiffness; double nodeForce; double offset; double nodeStiffnessPerArea; double nodeForcePerArea; Dictionary nodeIdNodeWeight; HashSet reservedElementSetNames = model.Mesh.GetReservedElementSetNames(); // Get all nodes and their normals foreach (var constraintEntry in model.Constraints) { if (constraintEntry.Value is CompressionOnly co) { if (co.Active && co.Valid) { clearance = co.Clearance.Value; // nodeIdNodeNormals.Clear(); surface = model.Mesh.Surfaces[co.MasterRegionName]; model.GetDistributedNodalValuesFromSurface(surface.Name, out nodeIdNodeWeight, out area); // nodeStiffnessPerArea = co.SpringStiffness.Value; if (double.IsNaN(nodeStiffnessPerArea)) nodeStiffnessPerArea = GapSectionData.InitialSpringStiffness; nodeStiffnessPerArea = nodeStiffnessPerArea / area; // nodeForcePerArea = co.TensileForceAtNegativeInfinity.Value; if (double.IsNaN(nodeForcePerArea)) nodeForcePerArea = GapSectionData.InitialTensileForceAtNegativeInfinity; nodeForcePerArea = nodeForcePerArea / area; // offset = co.Offset.Value; // foreach (var entry in surface.ElementFaces) { elementSet = model.Mesh.ElementSets[entry.Value]; foreach (var elementId in elementSet.Labels) { if (elementIdsHash.Contains(entry.Key.ToString() + "_" + elementId)) throw new CaeException("Element id: " + elementId + " has more than one compression only constraint defined."); // element = model.Mesh.Elements[elementId]; elementIdsHash.Add(entry.Key.ToString() + "_" + elementId); // model.Mesh.GetElementFaceCenterAndNormal(elementId, entry.Key, out _, out faceNormal, out shellElement); // Invert normal shellEdgeFace = shellElement && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2; if (shellElement && !shellEdgeFace) { faceNormal[0] *= -1; faceNormal[1] *= -1; faceNormal[2] *= -1; } normalVec = new Vec3D(faceNormal); // foreach (var nodeId in element.GetNodeIdsFromFaceName(entry.Key)) { if (nodeIdNodeNormals.TryGetValue(nodeId, out nodeNormals)) nodeNormals.Add(normalVec); else nodeIdNodeNormals.Add(nodeId, new List() { normalVec }); } } } // Get a dictionary of all node ids that have the same normal nodeIdNormal.Clear(); foreach (var entry in nodeIdNodeNormals) { normalVec = new Vec3D(); foreach (var normalEntry in entry.Value) normalVec += normalEntry; normalVec.Normalize(); // nodeIdNormal.Add(entry.Key, normalVec.Coor); } // Get nodes, elements, element sets, gap sections, boundary conditions count = 1; foreach (var entry in nodeIdNormal) { if (nodeIdNodeWeight[entry.Key] != 0) { normal = entry.Value; elementIds = new List(); name = co.Name + "_ElementSet-" + count++; if (reservedElementSetNames.Contains(name)) name = reservedElementSetNames.GetNextNumberedKey(name); reservedElementSetNames.Add(name); // Node 1 newNodeId++; bcNodeIds.Add(newNodeId); // node1 = new FeNode(newNodeId, model.Mesh.Nodes[entry.Key].Coor); node1.X -= offset * normal[0]; node1.Y -= offset * normal[1]; node1.Z -= offset * normal[2]; additionalNodes.Add(node1); // Node 2 newNodeId++; // node2 = new FeNode(newNodeId, model.Mesh.Nodes[entry.Key].Coor); additionalNodes.Add(node2); // newElementId++; gapElement = new LinearGapElement(newElementId, new int[] { node1.Id, node2.Id }); elementIds.Add(newElementId); elementsToAdd.Add(gapElement); // Equations equationParameters.Add(new double[] { node2.Id, 1, 1, entry.Key, 1, -1 }); equationParameters.Add(new double[] { node2.Id, 2, 1, entry.Key, 2, -1 }); equationParameters.Add(new double[] { node2.Id, 3, 1, entry.Key, 3, -1 }); // elementSet = new FeElementSet(name, elementIds.ToArray()); model.Mesh.ElementSets.Add(elementSet.Name, elementSet); additionalElementSetNames.Add(elementSet.Name); // Scale to nodal area nodeStiffness = nodeStiffnessPerArea * nodeIdNodeWeight[entry.Key]; nodeForce = nodeForcePerArea * nodeIdNodeWeight[entry.Key]; // Gap section additionalSectionData.Add(new GapSectionData("GapSectionData", name, clearance, normal, nodeStiffness, nodeForce)); } } // if (co.NonLinear) nonLinear = true; } } } // Add all elements if (elementsToAdd.Count > 0) additionalElementKeywords.Add(new CalElement(FeElementTypeGap.GAPUNI.ToString(), null, elementsToAdd)); // Boundary conditions if (bcNodeIds.Count > 0) { name = "Internal_All_Compression_Only_Constraints_NodeSet"; additionalNodeSets.Add(new FeNodeSet(name, bcNodeIds.ToArray())); DisplacementRotation dr = new DisplacementRotation("Compression_Only_BC", name, RegionTypeEnum.NodeSetName, twoD, false, 0); dr.U1.SetEquationFromValue(0); dr.U2.SetEquationFromValue(0); dr.U3.SetEquationFromValue(0); additionalBoundaryConditions.Add(dr); } // Materials if (nonLinear) { Material material = new Material(model.Materials.GetNextNumberedKey("Internal_compression_only")); material.AddProperty(new Density(new double[][] { new double[] { 1, 0 } })); material.AddProperty(new Elastic(new double[][] { new double[] { 1, 0, 0 } })); material.AddProperty(new Plastic(new double[][] { new double[] { 0, 0, 0 } })); additionalMaterials.Add(material); } // maxNodeId = newNodeId; maxElementId = newElementId; } public static bool AddUserKeywordByIndices(List keywords, int[] indices, CalculixKeyword userKeyword) { if (indices.Length == 1) { keywords.Insert(indices[0], userKeyword); } else { bool deactivated = false; CalculixKeyword keywordParent = keywords[indices[0]]; if (keywordParent is CalDeactivated) deactivated = true; // Find a parent for (int i = 1; i < indices.Length - 1; i++) { if (indices[i] < keywordParent.Keywords.Count) { keywordParent = keywordParent.Keywords[indices[i]]; if (keywordParent is CalDeactivated) deactivated = true; } else return false; } // Add the keyword if (keywordParent.Keywords.Count < indices[indices.Length - 1]) return false; if (!deactivated) keywordParent.Keywords.Insert(indices[indices.Length - 1], userKeyword); else keywordParent.Keywords.Insert(indices[indices.Length - 1], new CalDeactivated("User keyword")); } return true; } // public static void RemoveLostUserKeywords(FeModel model) { List keywords = GetModelKeywords(model, ConvertPyramidsToEnum.Wedges, null, true); // Add user keywords List keywordKeysToRemove = new List(); if (model.CalculixUserKeywords != null) { foreach (var entry in model.CalculixUserKeywords) { if (!AddUserKeywordByIndices(keywords, entry.Key, entry.Value.DeepClone())) keywordKeysToRemove.Add(entry.Key); } } // Remove lost user keywords foreach (var indices in keywordKeysToRemove) { model.CalculixUserKeywords.Remove(indices); } } // public static string GetShortKeywordData(CalculixKeyword keyword, bool useHiding) { StringBuilder sb = new StringBuilder(); sb.Append(keyword.GetKeywordString()); if (!(keyword is CalNode) && !(keyword is CalElement) && !(keyword is CalNodeSet) && !(keyword is CalElementSet) && !(keyword is CalInitialTemperature it && it.CanHideData) && !(keyword is CalTemperatureBC tbc && tbc.CanHideData) && !(keyword is CalVariablePressureLoad) && !(keyword is CalImportedPressureLoad) && !(keyword is CalSTLoad) && !(keyword is CalDefinedTemperature dt && dt.CanHideData) && !(keyword is CalAdditional)) { sb.Append(keyword.GetDataString()); } else { // //int n = 10; // //string[] lines = keyword.GetDataString().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); // //for (int i = 0; i < Math.Min(n, lines.Length); i++) sb.AppendLine(lines[i]); // //if (lines.Length > n) sb.AppendLine("... hidden data ..."); if (useHiding) sb.AppendLine("... hidden data ..."); else sb.Append(keyword.GetDataString()); } // string text = sb.ToString(); if (text.EndsWith(Environment.NewLine)) text = text.Substring(0, text.Length - Environment.NewLine.Length); return text; } private static void WriteKeywordRecursively(StringBuilder sb, CalculixKeyword keyword) { sb.Append(keyword.GetKeywordString()); sb.Append(keyword.GetDataString()); // foreach (var childKeyword in keyword.Keywords) { WriteKeywordRecursively(sb, childKeyword); } } // private static string[] GetAllSubmodelNodeSetNames(FeModel model) { List nodeSetNames = new List(); foreach (var step in model.StepCollection.StepsList) { foreach (var entry in step.BoundaryConditions) { if (entry.Value is SubmodelBC sm && sm.Active) { if (sm.RegionType == RegionTypeEnum.SurfaceName) nodeSetNames.Add(model.Mesh.Surfaces[sm.RegionName].NodeSetName); else nodeSetNames.Add(sm.RegionName); } } } return nodeSetNames.ToArray(); } // private static void AppendHeading(FeModel model, CalculixKeyword parent) { CalHeading heading = new CalHeading(model.Name, model.HashName, model.UnitSystem.UnitSystemType); parent.AddKeyword(heading); } private static void AppendSubmodel(FeModel model, string[] nodeSetNames, CalculixKeyword parent) { //*Submodel, TYPE = NODE, INPUT = Model.frd CalSubmodel submodel = new CalSubmodel(model.Properties.GlobalResultsFileName, nodeSetNames); parent.AddKeyword(submodel); } private static void AppendNodes(FeModel model, List additionalNodes, Dictionary referencePointsNodeIds, Dictionary deformations, CalculixKeyword parent) { if (model.Mesh != null) { CalNode node = new CalNode(model, additionalNodes, referencePointsNodeIds, deformations); parent.AddKeyword(node); } } private static void AppendElements(FeModel model, List additionalElementKeywords, CalculixKeyword parent, ConvertPyramidsToEnum convertPyramidsTo) { if (model.Mesh != null) { Dictionary> elementTypes = new Dictionary>(); List elements; // string type; FeElement element; MeshPart part; CalElement elementKeyword; // foreach (var entry in model.Mesh.Parts) { elementTypes.Clear(); part = (MeshPart)entry.Value; // Labels中存当前Part的所有单元编号,根据其类型加入到对应单元类型中,然后按照类型输出 foreach (int elementId in part.Labels) { element = model.Mesh.Elements[elementId]; if (part.LinearTriaType != FeElementTypeLinearTria.None && element is LinearTriangleElement) { type = part.LinearTriaType.ToString(); } else if (part.LinearQuadType != FeElementTypeLinearQuad.None && element is LinearQuadrilateralElement) { type = part.LinearQuadType.ToString(); } else if (part.LinearTetraType != FeElementTypeLinearTetra.None && element is LinearTetraElement) { type = part.LinearTetraType.ToString(); } else if (part.LinearPyramidType != FeElementTypeLinearPyramid.None && element is LinearPyramidElement) { type = part.LinearPyramidType.ToString(); } else if (part.LinearWedgeType != FeElementTypeLinearWedge.None && element is LinearWedgeElement) { type = part.LinearWedgeType.ToString(); } else if (part.LinearWedgeType == FeElementTypeLinearWedge.None && // element is LinearWedgeElement) // converted pyramids { type = FeElementTypeLinearWedge.C3D6.ToString(); // } else if (part.LinearHexaType == FeElementTypeLinearHexa.None && // element is LinearHexaElement) // converted pyramids { type = FeElementTypeLinearHexa.C3D8.ToString(); // } else if (part.LinearHexaType != FeElementTypeLinearHexa.None && element is LinearHexaElement) { type = part.LinearHexaType.ToString(); } else if (part.ParabolicTriaType != FeElementTypeParabolicTria.None && element is ParabolicTriangleElement) { type = part.ParabolicTriaType.ToString(); } else if (part.ParabolicQuadType != FeElementTypeParabolicQuad.None && element is ParabolicQuadrilateralElement) { type = part.ParabolicQuadType.ToString(); } else if (part.ParabolicTetraType != FeElementTypeParabolicTetra.None && element is ParabolicTetraElement) { type = part.ParabolicTetraType.ToString(); } else if (part.ParabolicPyramidType != FeElementTypeParabolicPyramid.None && element is ParabolicPyramidElement) { type = part.ParabolicPyramidType.ToString(); } else if (part.ParabolicWedgeType != FeElementTypeParabolicWedge.None && element is ParabolicWedgeElement) { type = part.ParabolicWedgeType.ToString(); } else if (part.ParabolicWedgeType == FeElementTypeParabolicWedge.None && // element is ParabolicWedgeElement) // converted pyramids { type = FeElementTypeParabolicWedge.C3D15.ToString(); // } else if (part.ParabolicHexaType == FeElementTypeParabolicHexa.None && // element is ParabolicHexaElement) // converted pyramids { type = FeElementTypeParabolicHexa.C3D20.ToString(); // } else if (part.ParabolicHexaType != FeElementTypeParabolicHexa.None && element is ParabolicHexaElement) { type = part.ParabolicHexaType.ToString(); } else { throw new NotImplementedException(); } // Add element to the corresponding type if (elementTypes.TryGetValue(type, out elements)) { elements.Add(element); } else { elementTypes.Add(type, new List() { element }); } } // 按照类型输出 foreach (var typeEntry in elementTypes) { elementKeyword = new CalElement(typeEntry.Key, part.Name, typeEntry.Value, convertPyramidsTo); parent.AddKeyword(elementKeyword); } } // Additional elements AppendAdditionalElements(additionalElementKeywords, parent); } } private static void AppendAdditionalElements(List additionalElementKeywords, CalculixKeyword parent) { List keywords = new List(); foreach (var item in additionalElementKeywords) { keywords.Add(item); } CalAdditional calAdditionalElements = new CalAdditional("Additional elements", keywords); if (calAdditionalElements.GetDataString().Length > 0) { parent.AddKeyword(calAdditionalElements); } } private static void AppendNodeSets(FeModel model, List additionalNodeSets, CalculixKeyword parent) { if (model.Mesh != null) { HashSet nodeSetNames = new HashSet(); // foreach (var entry in model.Mesh.NodeSets) AppendNodeSet(entry.Value, parent); nodeSetNames.UnionWith(model.Mesh.NodeSets.Keys); // Get additional node set keyword CalAdditional calAdditionalNodeSets = GetAdditionalNodeSetsKeyword(additionalNodeSets, ref nodeSetNames); // Append additional node set keyword if (calAdditionalNodeSets.GetDataString().Length > 0) parent.AddKeyword(calAdditionalNodeSets); } } private static void AppendNodeSet(FeNodeSet nodeSet, CalculixKeyword parent) { CalNodeSet calNodeSet; if (nodeSet.Active) { calNodeSet = new CalNodeSet(nodeSet); parent.AddKeyword(calNodeSet); } else parent.AddKeyword(new CalDeactivated(nodeSet.Name)); } private static CalAdditional GetAdditionalNodeSetsKeyword(List additionalNodeSets, ref HashSet nodeSetNames) { CalculixKeyword keyword; List keywords = new List(); foreach (var nodeSet in additionalNodeSets) { if (nodeSet.Active) { keyword = new CalNodeSet(nodeSet); keywords.Add(keyword); // nodeSetNames.Add(nodeSet.Name); } } // CalAdditional calAdditionalNodeSets = new CalAdditional("Additional node sets", keywords); return calAdditionalNodeSets; } private static void AppendParts(FeModel model, CalculixKeyword parent) { if (model.Mesh != null) { CalElementSet part; foreach (var entry in model.Mesh.Parts) { if (entry.Value.Active) { part = new CalElementSet(entry.Value, model); parent.AddKeyword(part); } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } } private static void AppendElementSets(FeModel model, HashSet additionalElementSetNames, CalculixKeyword parent) { if (model.Mesh != null) { CalculixUserKeyword tmp = new CalculixUserKeyword(""); foreach (var entry in model.Mesh.ElementSets) { if (additionalElementSetNames.Contains(entry.Key)) AppendElementSet(model, entry.Value, tmp); else AppendElementSet(model, entry.Value, parent); } // CalAdditional calAdditionalElementSets = new CalAdditional("Additional element sets", tmp.Keywords); if (calAdditionalElementSets.GetDataString().Length > 0) parent.AddKeyword(calAdditionalElementSets); } } private static void AppendElementSet(FeModel model, FeElementSet elementSet, CalculixKeyword parent) { CalElementSet calElementSet; if (elementSet.Active) { calElementSet = new CalElementSet(elementSet, model); parent.AddKeyword(calElementSet); } else parent.AddKeyword(new CalDeactivated(elementSet.Name)); } private static void AppendSurfaces(FeModel model, CalculixKeyword parent) { if (model.Mesh != null) { CalSurface calSurface; foreach (var entry in model.Mesh.Surfaces) { if (entry.Value.Active && entry.Value.ElementFaces != null) { calSurface = new CalSurface(entry.Value, model.Properties.ModelSpace.IsTwoD()); parent.AddKeyword(calSurface); } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } } private static void AppendPhysicalConstants(FeModel model, CalculixKeyword parent) { if (model != null) { CalPhysicalConstants calPhysicalConstants = new CalPhysicalConstants(model.Properties); if (calPhysicalConstants.GetKeywordString().Length > 0) parent.AddKeyword(calPhysicalConstants); } } private static void AppendCoordinateSystems(Dictionary> coordinateSystemNodeSets, CalculixKeyword parent) { foreach (var entry in coordinateSystemNodeSets) { foreach (var nodeSetName in entry.Value) { parent.AddKeyword(new CalTransform(entry.Key, nodeSetName)); } } } private static void AppendMaterials(FeModel model, CalculixKeyword parent, List additionalMaterials, string[] materialNames = null, bool addAllMaterials = false) { CalMaterial calMaterial; HashSet activeMaterialNames; // if (addAllMaterials) activeMaterialNames = new HashSet(model.Materials.Keys); else activeMaterialNames = MaterialNamesUsedInActiveSections(model); // List materials = model.Materials.Values.ToList(); if (additionalMaterials != null) { foreach (var additionalMaterial in additionalMaterials) { materials.Add(additionalMaterial); activeMaterialNames.Add(additionalMaterial.Name); } } // foreach (var material in materials) { if ((material.Active && activeMaterialNames.Contains(material.Name)) || (materialNames != null && materialNames.Contains(material.Name))) { calMaterial = new CalMaterial(material); parent.AddKeyword(calMaterial); // foreach (var property in material.Properties) { if (property is Density de) { calMaterial.AddKeyword(new CalDensity(de, material.TemperatureDependent)); } else if (property is SlipWear sw) { if (materialNames != null) // must be here calMaterial.AddKeyword(new CalSlipWear(sw, material.TemperatureDependent)); } else if (property is Elastic el) { calMaterial.AddKeyword(new CalElastic(el, material.TemperatureDependent)); } else if (property is ElasticWithDensity ewd) { Density density = new Density(new double[][] { new double[] { ewd.Density.Value } }); calMaterial.AddKeyword(new CalDensity(density, material.TemperatureDependent)); // Elastic elastic = new Elastic(new double[][] { new double[] { ewd.YoungsModulus.Value, ewd.PoissonsRatio.Value } }); calMaterial.AddKeyword(new CalElastic(elastic, material.TemperatureDependent)); } else if (property is Plastic pl) { calMaterial.AddKeyword(new CalPlastic(pl, material.TemperatureDependent)); } else if (property is ThermalExpansion te) { calMaterial.AddKeyword(new CalThermalExpansion(te, material.TemperatureDependent)); } else if (property is ThermalConductivity tc) { calMaterial.AddKeyword(new CalThermalConductivity(tc, material.TemperatureDependent)); } else if (property is SpecificHeat sh) { calMaterial.AddKeyword(new CalSpecificHeat(sh, material.TemperatureDependent)); } else throw new NotImplementedException(); } } else if (materialNames == null) parent.AddKeyword(new CalDeactivated(material.Name)); } } private static void AppendSections(FeModel model, List additionalSectionData, CalculixKeyword parent) { if (model.Mesh != null) { foreach (var entry in model.Sections) AppendSection(entry.Value, parent); // AppendAdditionalSections(additionalSectionData, parent); } } private static void AppendSection(Section section, CalculixKeyword parent) { if (section.Active) { if (section is SolidSection ss) parent.AddKeyword(new CalSolidSection(ss)); else if (section is ShellSection shs) parent.AddKeyword(new CalShellSection(shs)); else if (section is MembraneSection ms) parent.AddKeyword(new CalMembraneSection(ms)); else if (section is PointMassSection pms) { } else if (section is DistributedMassSection dms) { } else throw new NotSupportedException(); } else parent.AddKeyword(new CalDeactivated(section.Name)); } private static void AppendAdditionalSections(List additionalSectionData, CalculixKeyword parent) { CalculixKeyword keyword; List keywords = new List(); // foreach (var section in additionalSectionData) { if (section.Active) { if (section is LinearSpringSectionData lssd) keyword = new CalLinearSpringSection(lssd); else if (section is GapSectionData gsd) keyword = new CalGapSection(gsd); else if (section is MassSectionData msd) keyword = new CalMassSection(msd); else throw new NotSupportedException(); // if (keyword != null) keywords.Add(keyword); } } // CalAdditional calAdditionalSections = new CalAdditional("Additional sections", keywords); if (calAdditionalSections.GetDataString().Length > 0) parent.AddKeyword(calAdditionalSections); } private static HashSet MaterialNamesUsedInActiveSections(FeModel model) { HashSet materialNames = new HashSet(); if (model.Mesh != null) { foreach (var entry in model.Sections) { if (entry.Value.Active) materialNames.Add(entry.Value.MaterialName); } } return materialNames; } private static void AppendPreTensionSections(OrderedDictionary> preTensionLoads, Dictionary referencePointsNodeIds, CalculixKeyword parent) { if (preTensionLoads != null) { int nodeId; bool atLeastOneActive; PreTensionLoad ptl; foreach (var preTensionOnSurfaceEntry in preTensionLoads) { atLeastOneActive = false; foreach (var item in preTensionOnSurfaceEntry.Value) atLeastOneActive |= item.Active; // Take the first one since all the others are the same ptl = preTensionOnSurfaceEntry.Value[0]; if (atLeastOneActive) { nodeId = referencePointsNodeIds[preTensionOnSurfaceEntry.Key][0]; CalPreTensionSection preTension; if (ptl.AutoComputeDirection) preTension = new CalPreTensionSection(ptl.SurfaceName, nodeId); else preTension = new CalPreTensionSection(ptl.SurfaceName, nodeId, ptl.X.Value, ptl.Y.Value, ptl.Z.Value); parent.AddKeyword(preTension); } else parent.AddKeyword(new CalDeactivated("Pre-tension " + ptl.SurfaceName)); } } } private static void AppendConstraints(FeModel model, Dictionary referencePointsNodeIds, List equationParameters, CalculixKeyword parent) { if (model.Mesh != null) { foreach (var entry in model.Constraints) { if (entry.Value.Active) { if (entry.Value is PointSpring) { } // this constraint is split into elements and a section else if (entry.Value is SurfaceSpring) { } // this constraint is split into point springs else if (entry.Value is CompressionOnly) { } // this constraint is split into GAPUNI elements and GAP section else if (entry.Value is RigidBody rb) { string surfaceNodeSetName = null; if (rb.RegionType == RegionTypeEnum.SurfaceName) surfaceNodeSetName = model.Mesh.Surfaces[rb.RegionName].NodeSetName; CalRigidBody calRigidBody = new CalRigidBody(rb, referencePointsNodeIds, surfaceNodeSetName); parent.AddKeyword(calRigidBody); } else if (entry.Value is Tie tie) { CalTie calTie = new CalTie(tie); parent.AddKeyword(calTie); } else throw new NotImplementedException(); } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } // Equations foreach (var equationParameter in equationParameters) { parent.AddKeyword(new CalEquation(equationParameter)); } } } private static void AppendSurfaceInteractions(FeModel model, CalculixKeyword parent) { CalSurfaceInteraction surfaceInteraction; foreach (var entry in model.SurfaceInteractions) { if (entry.Value.Active) { surfaceInteraction = new CalSurfaceInteraction(entry.Value); parent.AddKeyword(surfaceInteraction); // foreach (var property in entry.Value.Properties) { if (property is SurfaceBehavior sb) surfaceInteraction.AddKeyword(new CalSurfaceBehavior(sb)); else if (property is Friction fr) surfaceInteraction.AddKeyword(new CalFriction(fr)); else if (property is GapConductance gc) surfaceInteraction.AddKeyword(new CalGapConductance(gc)); else throw new NotImplementedException(); } } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } private static void AppendContactPairs(FeModel model, CalculixKeyword parent) { if (model.Mesh != null) { foreach (var entry in model.ContactPairs) { if (entry.Value.Active) { CalContactPair calContactPair = new CalContactPair(entry.Value); parent.AddKeyword(calContactPair); } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } } private static void AppendAmplitudes(FeModel model, CalculixKeyword parent) { if (model.Mesh != null) { foreach (var entry in model.Amplitudes) { if (entry.Value.Active) { if (entry.Value is Amplitude a) { CalAmplitude calAmplitude = new CalAmplitude(a); parent.AddKeyword(calAmplitude); } } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } } private static void AppendInitialConditions(FeModel model, Dictionary referencePointsNodeIds, CalculixKeyword parent) { if (model.Mesh != null) { foreach (var entry in model.InitialConditions) { if (entry.Value.Active) { if (entry.Value is InitialTemperature it) { CalInitialTemperature calInitialTemperature = new CalInitialTemperature(model, it); parent.AddKeyword(calInitialTemperature); } else if (entry.Value is InitialTranslationalVelocity itv) { CalInitialTranslationalVelocity calInitialVelocity = new CalInitialTranslationalVelocity(model, itv, referencePointsNodeIds); parent.AddKeyword(calInitialVelocity); } else if (entry.Value is InitialAngularVelocity iav) { CalInitialAngularVelocity calInitialVelocity = new CalInitialAngularVelocity(model, iav, referencePointsNodeIds); parent.AddKeyword(calInitialVelocity); } else throw new NotSupportedException(); } else parent.AddKeyword(new CalDeactivated(entry.Value.Name)); } } } // private static void AppendSteps(FeModel model, List additionalBoundaryConditions, Dictionary referencePointsNodeIds, CalculixKeyword parent) { CalTitle title; HashSet loadTypes = model.StepCollection.GetAllLoadTypes(); // foreach (var step in model.StepCollection.StepsList) { if (step is InitialStep) continue; else if (step is BoundaryDisplacementStep boundaryDisplacementStep) continue; // title = new CalTitle(step.Name, ""); parent.AddKeyword(title); // CalculixKeyword calStepHeader; if (step.Active) calStepHeader = new CalStepHeader(step); else calStepHeader = new CalDeactivated(step.Name); title.AddKeyword(calStepHeader); // Step type if (step.Active) { if (step.GetType() == typeof(StaticStep) || step is SlipWearStep) { StaticStep staticStep = step as StaticStep; CalStaticStep calStaticStep = new CalStaticStep(staticStep); calStepHeader.AddKeyword(calStaticStep); } else if (step is FrequencyStep frequencyStep) { CalFrequencyStep calFrequencyStep = new CalFrequencyStep(frequencyStep); calStepHeader.AddKeyword(calFrequencyStep); } else if (step is ComplexFrequencyStep complexFrequencyStep) { CalComplexFrequencyStep calComplexFrequencyStep = new CalComplexFrequencyStep(complexFrequencyStep); calStepHeader.AddKeyword(calComplexFrequencyStep); } else if (step is BuckleStep buckleStep) { CalBuckleStep calBuckleStep = new CalBuckleStep(buckleStep); calStepHeader.AddKeyword(calBuckleStep); } else if (step is ModalDynamicsStep modalStep) { CalModalDynamicsStep calModalStep = new CalModalDynamicsStep(modalStep); calStepHeader.AddKeyword(calModalStep); // Damping if (modalStep.ModalDamping.DampingType != ModalDampingTypeEnum.Off) { CalTitle damping = new CalTitle("Damping", ""); CalModalDamping calModalDamping = new CalModalDamping(modalStep.ModalDamping); damping.AddKeyword(calModalDamping); calStepHeader.AddKeyword(damping); } } else if (step is SteadyStateDynamicsStep steadyStep) { CalSteadyStateDynamicsStep calSteadyStep = new CalSteadyStateDynamicsStep(steadyStep); calStepHeader.AddKeyword(calSteadyStep); // Damping if (steadyStep.ModalDamping.DampingType != ModalDampingTypeEnum.Off) { CalTitle damping = new CalTitle("Damping", ""); CalModalDamping calModalDamping = new CalModalDamping(steadyStep.ModalDamping); damping.AddKeyword(calModalDamping); calStepHeader.AddKeyword(damping); } } else if (step.GetType() == typeof(DynamicStep)) { DynamicStep dynamicStep = step as DynamicStep; CalDynamicStep calDynamicStep = new CalDynamicStep(dynamicStep); calStepHeader.AddKeyword(calDynamicStep); // Damping if (dynamicStep.Damping.DampingType != DampingTypeEnum.Off) { CalTitle damping = new CalTitle("Damping", ""); CalDamping calDamping = new CalDamping(dynamicStep.Damping); damping.AddKeyword(calDamping); calStepHeader.AddKeyword(damping); } } else if (step.GetType() == typeof(HeatTransferStep)) { HeatTransferStep heatTransferStep = step as HeatTransferStep; CalHeatTransferStep calHeatTransferStep = new CalHeatTransferStep(heatTransferStep); calStepHeader.AddKeyword(calHeatTransferStep); } else if (step.GetType() == typeof(UncoupledTempDispStep)) { UncoupledTempDispStep uncoupledTempDispStep = step as UncoupledTempDispStep; CalUncoupledTempDispStep calUncoupledTempDispStep = new CalUncoupledTempDispStep(uncoupledTempDispStep); calStepHeader.AddKeyword(calUncoupledTempDispStep); } else if (step.GetType() == typeof(CoupledTempDispStep)) { CoupledTempDispStep coupledTempDispStep = step as CoupledTempDispStep; CalCoupledTempDispStep calCoupledTempDispStep = new CalCoupledTempDispStep(coupledTempDispStep); calStepHeader.AddKeyword(calCoupledTempDispStep); } else throw new NotImplementedException(); // Controls title = new CalTitle("Controls", ""); calStepHeader.AddKeyword(title); CalculixKeyword calParameter; foreach (var parameter in step.StepControls.Parameters) { if (parameter is ResetStepControlParameter rscp) calParameter = new CalResetParameter(rscp); else if (parameter is TimeIncrementationStepControlParameter tiscp) calParameter = new CalTimeIncrementationParameter(tiscp); else if (parameter is FieldStepControlParameter fscp) calParameter = new CalFieldParameter(fscp); else if (parameter is ContactStepControlParameter cscp) calParameter = new CalContactParameter(cscp); else throw new NotImplementedException(); // title.AddKeyword(calParameter); } // Frequency title = new CalTitle("Output frequency", ""); calStepHeader.AddKeyword(title); CalOutputFrequency calOutputFrequency = new CalOutputFrequency(step.OutputFrequency); if (!calOutputFrequency.IsDefault()) title.AddKeyword(calOutputFrequency); } else calStepHeader.AddKeyword(new CalDeactivated(step.GetType().ToString())); // Boundary conditions title title = new CalTitle("Boundary conditions", ""); calStepHeader.AddKeyword(title); // Boundary conditions op if (step.Active && !(step is ModalDynamicsStep)) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Boundary, OpTypeEnum.New)); } // Boundary conditions foreach (var bcEntry in step.BoundaryConditions) { if (step.Active && bcEntry.Value.Active) AppendBoundaryCondition(model, step, bcEntry.Value, referencePointsNodeIds, title); else title.AddKeyword(new CalDeactivated(bcEntry.Value.Name)); } // Additional boundary conditions AppendAdditionalBoundaryConditions(model, step, additionalBoundaryConditions, referencePointsNodeIds, title); // Loads title title = new CalTitle("Loads", ""); calStepHeader.AddKeyword(title); // Load op if (step.Active) { if (step.IsLoadTypeSupported(typeof(CLoad))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Cload, OpTypeEnum.New)); } if (step.IsLoadTypeSupported(typeof(DLoad))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Dload, OpTypeEnum.New)); } if (step.IsLoadTypeSupported(typeof(CFlux))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Cflux, OpTypeEnum.New)); } if (step.IsLoadTypeSupported(typeof(DFlux)) && loadTypes.Contains(typeof(DFlux))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Dflux, OpTypeEnum.New)); } if (step.IsLoadTypeSupported(typeof(FilmHeatTransfer)) && loadTypes.Contains(typeof(FilmHeatTransfer))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Film, OpTypeEnum.New)); } if (step.IsLoadTypeSupported(typeof(RadiationHeatTransfer)) && loadTypes.Contains(typeof(RadiationHeatTransfer))) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Radiate, OpTypeEnum.New)); } } // Loads foreach (var loadEntry in step.Loads) { if (step.Active && loadEntry.Value.Active) AppendLoad(model, step, loadEntry.Value, referencePointsNodeIds, title); else title.AddKeyword(new CalDeactivated(loadEntry.Value.Name)); } // Defined fields title title = new CalTitle("Defined fields", ""); calStepHeader.AddKeyword(title); // Defined fields op if (step.Active && step.DefinedFields.Count > 0) { title.AddKeyword(new CalOpParameter(OpKeywordEnum.Temperature, OpTypeEnum.New)); } // Defined fields foreach (var definedFieldEntry in step.DefinedFields) { if (step.Active && definedFieldEntry.Value.Active) AppendDefinedField(model, definedFieldEntry.Value, title); else title.AddKeyword(new CalDeactivated(definedFieldEntry.Value.Name)); } // History outputs title = new CalTitle("History outputs", ""); calStepHeader.AddKeyword(title); // foreach (var historyOutputEntry in step.HistoryOutputs) { if (step.Active && historyOutputEntry.Value.Active) AppendHistoryOutput(model, step, historyOutputEntry.Value, title); else title.AddKeyword(new CalDeactivated(historyOutputEntry.Value.Name)); } // Field outputs title = new CalTitle("Field outputs", ""); calStepHeader.AddKeyword(title); // foreach (var fieldOutputEntry in step.FieldOutputs) { if (step.Active && fieldOutputEntry.Value.Active) AppendFieldOutput(model, step, fieldOutputEntry.Value, title); else title.AddKeyword(new CalDeactivated(fieldOutputEntry.Value.Name)); } // title = new CalTitle("End step", ""); calStepHeader.AddKeyword(title); if (step.Active) { CalEndStep endStep = new CalEndStep(); title.AddKeyword(endStep); } else title.AddKeyword(new CalDeactivated(step.Name)); } } private static void AppendBoundaryCondition(FeModel model, Step step, BoundaryCondition boundaryCondition, Dictionary referencePointsNodeIds, CalculixKeyword parent) { ComplexLoadTypeEnum complexLoadType; if (boundaryCondition.Complex) complexLoadType = ComplexLoadTypeEnum.Real; else complexLoadType = ComplexLoadTypeEnum.None; // AppendBoundaryCondition(model, boundaryCondition, referencePointsNodeIds, complexLoadType, parent); // Load case=2 - Imaginary component if (step is SteadyStateDynamicsStep && boundaryCondition.Complex && boundaryCondition.PhaseDeg.Value != 0) AppendBoundaryCondition(model, boundaryCondition, referencePointsNodeIds, ComplexLoadTypeEnum.Imaginary, parent); } private static void AppendBoundaryCondition(FeModel model, BoundaryCondition boundaryCondition, Dictionary referencePointsNodeIds, ComplexLoadTypeEnum complexLoadType, CalculixKeyword parent) { if (model.Mesh != null) { if (boundaryCondition is FixedBC fix) { string nodeSetNameOfSurface = null; if (fix.RegionType == RegionTypeEnum.SurfaceName) nodeSetNameOfSurface = model.Mesh.Surfaces[fix.RegionName].NodeSetName; CalFixedBC calFixedBC = new CalFixedBC(fix, referencePointsNodeIds, nodeSetNameOfSurface); parent.AddKeyword(calFixedBC); } else if (boundaryCondition is DisplacementRotation dispRot) { string nodeSetNameOfSurface = null; if (dispRot.RegionType == RegionTypeEnum.SurfaceName) nodeSetNameOfSurface = model.Mesh.Surfaces[dispRot.RegionName].NodeSetName; CalDisplacementRotation calDisplacementRotation = new CalDisplacementRotation(dispRot, referencePointsNodeIds, nodeSetNameOfSurface, complexLoadType); parent.AddKeyword(calDisplacementRotation); } else if (boundaryCondition is SubmodelBC sm) { string surfaceNodeSetName = null; if (sm.RegionType == RegionTypeEnum.SurfaceName) surfaceNodeSetName = model.Mesh.Surfaces[sm.RegionName].NodeSetName; CalSubmodelBC calSubmodelBC = new CalSubmodelBC(sm, surfaceNodeSetName); parent.AddKeyword(calSubmodelBC); } else if (boundaryCondition is TemperatureBC tmp) { string surfaceNodeSetName = null; if (tmp.RegionType == RegionTypeEnum.SurfaceName) surfaceNodeSetName = model.Mesh.Surfaces[tmp.RegionName].NodeSetName; CalTemperatureBC calTemperatureBC = new CalTemperatureBC(model, tmp, surfaceNodeSetName); parent.AddKeyword(calTemperatureBC); } else throw new NotImplementedException(); } } private static void AppendAdditionalBoundaryConditions(FeModel model, Step step, List additionalBoundaryConditions, Dictionary referencePointsNodeIds, CalculixKeyword parent) { CalculixUserKeyword tmp = new CalculixUserKeyword(""); // foreach (var additionalBoundaryCondition in additionalBoundaryConditions) { if (step.Active && additionalBoundaryCondition.Active) AppendBoundaryCondition(model, step, additionalBoundaryCondition, referencePointsNodeIds, tmp); else tmp.AddKeyword(new CalDeactivated(additionalBoundaryCondition.Name)); } // CalAdditional calAdditionalBoundaryConditions = new CalAdditional("Additional boundary conditions", tmp.Keywords); if (calAdditionalBoundaryConditions.GetDataString().Length > 0) parent.AddKeyword(calAdditionalBoundaryConditions); } private static void AppendLoad(FeModel model, Step step, Load load, Dictionary referencePointsNodeIds, CalculixKeyword parent) { ComplexLoadTypeEnum complexLoadType; if (load.Complex) complexLoadType = ComplexLoadTypeEnum.Real; else complexLoadType = ComplexLoadTypeEnum.None; // AppendLoad(model, load, referencePointsNodeIds, complexLoadType, parent); // Load case=2 - Imaginary component if (step is SteadyStateDynamicsStep && load.Complex && load.PhaseDeg.Value != 0) AppendLoad(model, load, referencePointsNodeIds, ComplexLoadTypeEnum.Imaginary, parent); } private static void AppendLoad(FeModel model, Load load, Dictionary referencePointsNodeIds, ComplexLoadTypeEnum complexLoadType, CalculixKeyword parent) { if (model.Mesh != null) { if (load is CLoad cl) { CalCLoad cLoad = new CalCLoad(cl, referencePointsNodeIds, complexLoadType); parent.AddKeyword(cLoad); } else if (load is MomentLoad ml) { CalMomentLoad mLoad = new CalMomentLoad(ml, referencePointsNodeIds, complexLoadType); parent.AddKeyword(mLoad); } else if (load is DLoad dl) { if (dl.DistributionName == Distribution.DefaultDistributionName) { CalDLoad dLoad = new CalDLoad(dl, model.Mesh.Surfaces[dl.RegionName], complexLoadType); parent.AddKeyword(dLoad); } else { CalVariablePressureLoad vpLoad = new CalVariablePressureLoad(model, dl, complexLoadType); parent.AddKeyword(vpLoad); } } else if (load is HydrostaticPressure hpl) { CalVariablePressureLoad vpLoad = new CalVariablePressureLoad(model, hpl, complexLoadType); parent.AddKeyword(vpLoad); } else if (load is ImportedPressure ipl) { CalImportedPressureLoad ipLoad = new CalImportedPressureLoad(model, ipl, complexLoadType); parent.AddKeyword(ipLoad); } else if (load is STLoad stl) { CalSTLoad stLoad = new CalSTLoad(model, stl, complexLoadType); parent.AddKeyword(stLoad); } else if (load is ImportedSTLoad istl) { CalImportedSTLoad istLoad = new CalImportedSTLoad(model, istl, complexLoadType); parent.AddKeyword(istLoad); } else if (load is ShellEdgeLoad sel) { CalShellEdgeLoad seLoad = new CalShellEdgeLoad(sel, model.Mesh.Surfaces[sel.SurfaceName], complexLoadType); parent.AddKeyword(seLoad); } else if (load is GravityLoad gl) { MassSection massSection; GravityLoad glClone = gl.DeepClone(); if (gl.RegionType == RegionTypeEnum.MassSection) { massSection = (MassSection)model.Sections[glClone.RegionName]; glClone.RegionName = massSection.ElementSetName; } // CalGravityLoad gLoad = new CalGravityLoad(glClone, complexLoadType); parent.AddKeyword(gLoad); } else if (load is CentrifLoad cfl) { MassSection massSection; CentrifLoad cflClone = cfl.DeepClone(); if (cfl.RegionType == RegionTypeEnum.MassSection) { massSection = (MassSection)model.Sections[cflClone.RegionName]; cflClone.RegionName = massSection.ElementSetName; } // CalCentrifLoad cLoad = new CalCentrifLoad(cflClone, complexLoadType); parent.AddKeyword(cLoad); } else if (load is PreTensionLoad ptl) { string name = ptl.SurfaceName; if (!ptl.AutoComputeDirection) name += "_" + ptl.X.ToString() + ptl.Y.ToString() + ptl.Z.ToString(); // CalculixKeyword calKey; if (ptl.Type == PreTensionLoadType.Force) { int nodeId = referencePointsNodeIds[name][0]; CLoad cLoad = new CLoad(ptl.Name, nodeId, ptl.GetMagnitudeValue(), 0, 0, ptl.TwoD, ptl.Complex, ptl.PhaseDeg.Value); cLoad.AmplitudeName = ptl.AmplitudeName; calKey = new CalCLoad(cLoad, referencePointsNodeIds, complexLoadType); } else if (ptl.Type == PreTensionLoadType.Displacement) { DisplacementRotation dr = new DisplacementRotation(ptl.Name, name, RegionTypeEnum.ReferencePointName, ptl.TwoD, ptl.Complex, ptl.PhaseDeg.Value); dr.U1.SetEquationFromValue(ptl.GetMagnitudeValue()); dr.AmplitudeName = ptl.AmplitudeName; calKey = new CalDisplacementRotation(dr, referencePointsNodeIds, null, complexLoadType); } else throw new NotSupportedException(); // parent.AddKeyword(calKey); } // Thermo else if (load is CFlux cf) { CalCFlux cFlux = new CalCFlux(cf); parent.AddKeyword(cFlux); } else if (load is DFlux df) { CalDFlux dFlux = new CalDFlux(df); parent.AddKeyword(dFlux); } else if (load is BodyFlux bf) { CalBodyFlux bFlux = new CalBodyFlux(bf); parent.AddKeyword(bFlux); } else if (load is FilmHeatTransfer fht) { CalFilmHeatTransfer filmHeatTransfer = new CalFilmHeatTransfer(fht, model.Mesh.Surfaces[fht.SurfaceName]); parent.AddKeyword(filmHeatTransfer); } else if (load is RadiationHeatTransfer rht) { CalRadiationHeatTransfer radiationHeatTransfer = new CalRadiationHeatTransfer(rht, model.Mesh.Surfaces[rht.SurfaceName]); parent.AddKeyword(radiationHeatTransfer); } else throw new NotImplementedException(); } } private static void AppendDefinedField(FeModel model, DefinedField definedField, CalculixKeyword parent) { if (definedField is DefinedTemperature dt) { CalDefinedTemperature definedTemperature = new CalDefinedTemperature(model, dt); parent.AddKeyword(definedTemperature); } else throw new NotImplementedException(); } private static void AppendHistoryOutput(FeModel model, Step step, HistoryOutput historyOutput, CalculixKeyword parent) { if (historyOutput is NodalHistoryOutput nho) { CalNodePrint nodePrint; if (nho.RegionType == RegionTypeEnum.ReferencePointName) { FeReferencePoint rp = model.Mesh.ReferencePoints[nho.RegionName]; nodePrint = new CalNodePrint(nho, rp.RefNodeSetName, step.OutputFrequency); parent.AddKeyword(nodePrint); nodePrint = new CalNodePrint(nho, rp.RotNodeSetName, step.OutputFrequency); parent.AddKeyword(nodePrint); } else { nodePrint = new CalNodePrint(model, nho, step.OutputFrequency); parent.AddKeyword(nodePrint); } } else if (historyOutput is ElementHistoryOutput eho) { CalElPrint elPrint = new CalElPrint(eho, step.OutputFrequency); parent.AddKeyword(elPrint); } else if (historyOutput is ContactHistoryOutput cho) { ContactPair cp = model.ContactPairs[cho.RegionName]; CalContactPrint contactPrint = new CalContactPrint(cho, cp.MasterRegionName, cp.SlaveRegionName, model.Mesh.Surfaces[cp.MasterRegionName].NodeSetName, model.Mesh.Surfaces[cp.SlaveRegionName].NodeSetName, step.OutputFrequency); parent.AddKeyword(contactPrint); } else throw new NotImplementedException(); } private static void AppendFieldOutput(FeModel model, Step step, FieldOutput fieldOutput, CalculixKeyword parent) { if (fieldOutput is NodalFieldOutput nfo) { CalNodeFile nodeFile = new CalNodeFile(nfo, step.OutputFrequency); parent.AddKeyword(nodeFile); } else if (fieldOutput is ElementFieldOutput efo) { CalElFile elFile = new CalElFile(efo, step.OutputFrequency); parent.AddKeyword(elFile); } else if (fieldOutput is ContactFieldOutput cfo) { CalContactFile conFile = new CalContactFile(cfo); parent.AddKeyword(conFile); } else throw new NotImplementedException(); } // static void AppendTitle(StringBuilder sb, string title) { sb.AppendLine("************************************************************"); sb.AppendLine("** " + title); sb.AppendLine("************************************************************"); } } }