using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CaeMesh; using CaeGlobals; using System.Runtime.Serialization; using Calculix = FileInOut.Output.Calculix; using System.IO; using System.Drawing; using System.Data; using System.Security.Cryptography; using System.Runtime.InteropServices; using static System.Collections.Specialized.BitVector32; using System.Net.NetworkInformation; using System.Xml.Linq; using FileInOut.Input; using CaeResults; using System.CodeDom; using System.Collections.Concurrent; namespace CaeModel { [Serializable] public class FeModel : ISerializable { // Variables private string _hashName; //ISerializable private FeMesh _geometry; //ISerializable private FeMesh _mesh; //ISerializable private EquationParameterCollection _parameters; //ISerializable private OrderedDictionary _materials; //ISerializable private OrderedDictionary _sections; //ISerializable private OrderedDictionary _constraints; //ISerializable private OrderedDictionary _surfaceInteractions; //ISerializable private OrderedDictionary _contactPairs; //ISerializable private OrderedDictionary _distributions; //ISerializable private OrderedDictionary _amplitudes; //ISerializable private OrderedDictionary _initialConditions; //ISerializable private StepCollection _stepCollection; //ISerializable private OrderedDictionary _calculixUserKeywords; //ISerializable private ModelProperties _properties; //ISerializable private UnitSystem _unitSystem; //ISerializable // Properties public string Name { get; set; } public string HashName { get { return _hashName; } } public FeMesh Geometry { get { return _geometry; } } public FeMesh Mesh { get { return _mesh; } } public EquationParameterCollection Parameters { get { return _parameters; } } public OrderedDictionary Materials { get { return _materials; } } public OrderedDictionary Sections { get { return _sections; } } public OrderedDictionary Constraints { get { return _constraints; } } public OrderedDictionary SurfaceInteractions { get { return _surfaceInteractions; } } public OrderedDictionary ContactPairs { get { return _contactPairs; } } public OrderedDictionary Distributions { get { return _distributions; } } public OrderedDictionary Amplitudes { get { return _amplitudes; } } public OrderedDictionary InitialConditions { get { return _initialConditions; } } public StepCollection StepCollection { get { return _stepCollection; } } public OrderedDictionary CalculixUserKeywords { get { return _calculixUserKeywords; } set { _calculixUserKeywords = value; } } public ModelProperties Properties { get { return _properties; } set { _properties = value; } } public UnitSystem UnitSystem { get { return _unitSystem; } set { _unitSystem = value; } } // Constructors public FeModel(string name, UnitSystem unitSystem, OrderedDictionary overriddenParameters = null) { StringComparer sc = StringComparer.OrdinalIgnoreCase; // Name = name; _hashName = Tools.GetRandomString(8); _geometry = new FeMesh(MeshRepresentation.Geometry); _mesh = new FeMesh(MeshRepresentation.Mesh); _parameters = new EquationParameterCollection(); _materials = new OrderedDictionary("Materials", sc); _sections = new OrderedDictionary("Sections", sc); _constraints = new OrderedDictionary("Constraints", sc); _surfaceInteractions = new OrderedDictionary("Surface Tractions", sc); _contactPairs = new OrderedDictionary("Contact Pairs", sc); _initialConditions = new OrderedDictionary("Initial Conditions", sc); _distributions = new OrderedDictionary("Distributions", sc); _amplitudes = new OrderedDictionary("Amplitudes", sc); _stepCollection = new StepCollection(); _properties = new ModelProperties(); if (unitSystem == null) _unitSystem = new UnitSystem(); else _unitSystem = unitSystem; // Set overridden parameters if (overriddenParameters != null) { foreach (var entry in overriddenParameters) _parameters.AddOverriddenParameter(entry.Key, entry.Value); } // UpdateNCalcParameters(); } public FeModel(SerializationInfo info, StreamingContext context) { StringComparer sc = StringComparer.OrdinalIgnoreCase; // Compatibility for version v.0.6.0 _surfaceInteractions = new OrderedDictionary("Surface Tractions", sc); _contactPairs = new OrderedDictionary("Contact Pairs", sc); // Compatibility for version v.0.7.0 _unitSystem = new UnitSystem(); // Compatibility for version v.0.8.0 _hashName = Tools.GetRandomString(8); // Compatibility for version v.1.0.0 _initialConditions = new OrderedDictionary("Initial Conditions", sc); // Compatibility for version v.2.3.3 _distributions = new OrderedDictionary("Distributions", sc); // Compatibility for version v.1.2.1 _amplitudes = new OrderedDictionary("Amplitudes", sc); // Compatibility for version v.1.4.0 _parameters = new EquationParameterCollection(); // foreach (SerializationEntry entry in info) { switch (entry.Name) { case "k__BackingField": // Compatibility for version v.0.5.1 case "_name": Name = (string)entry.Value; break; case "_geometry": _geometry = (FeMesh)entry.Value; break; case "_mesh": _mesh = (FeMesh)entry.Value; break; case "_parameters": // Compatibility for version v.2.1.11 if (entry.Value is OrderedDictionary dic) { dic.OnDeserialization(null); _parameters = new EquationParameterCollection(dic); } else _parameters = (EquationParameterCollection)entry.Value; break; case "_materials": if (entry.Value is Dictionary md) { // Compatibility for version v.0.5.1 md.OnDeserialization(null); _materials = new OrderedDictionary("Materials", md, sc); } else if (entry.Value is OrderedDictionary mod) _materials = mod; else if (entry.Value == null) _materials = null; else throw new NotSupportedException(); break; case "_sections": if (entry.Value is Dictionary sd) { // Compatibility for version v.0.5.1 sd.OnDeserialization(null); _sections = new OrderedDictionary("Sections", sd, sc); } else if (entry.Value is OrderedDictionary sod) _sections = sod; else if (entry.Value == null) _sections = null; else throw new NotSupportedException(); break; case "_constraints": if (entry.Value is Dictionary cd) { // Compatibility for version v.0.5.1 cd.OnDeserialization(null); _constraints = new OrderedDictionary("Constraints", cd, sc); } else if (entry.Value is OrderedDictionary cod) _constraints = cod; else if (entry.Value == null) _constraints = null; else throw new NotSupportedException(); break; case "_surfaceInteractions": _surfaceInteractions = (OrderedDictionary)entry.Value; break; case "_contactPairs": _contactPairs = (OrderedDictionary)entry.Value; break; case "_distributions": _distributions = (OrderedDictionary)entry.Value; break; case "_amplitudes": _amplitudes = (OrderedDictionary)entry.Value; break; case "_initialConditions": _initialConditions = (OrderedDictionary)entry.Value; break; case "_stepCollection": _stepCollection = (StepCollection)entry.Value; break; case "_calculixUserKeywords": if (entry.Value is Dictionary cukd) { // Compatibility for version v.0.5.1 cukd.OnDeserialization(null); _calculixUserKeywords = new OrderedDictionary("Keywords", cukd); } else if (entry.Value is OrderedDictionary cukod) _calculixUserKeywords = cukod; else if (entry.Value == null) _calculixUserKeywords = null; else throw new NotSupportedException(); break; case "_properties": _properties = (ModelProperties)entry.Value; break; case "_unitSystem": _unitSystem = (UnitSystem)entry.Value; break; case "_hashName": _hashName = (string)entry.Value; break; default: throw new NotSupportedException(); } } // _unitSystem.SetConverterUnits(); // // Call it to load the dictionary immediately //_parameters.OnDeserialization(null); //_geometry.Parts.OnDeserialization(null); //_mesh.Parts.OnDeserialization(null); //UpdateNCalcParameters(); // is called after the data is read from binary reader } // Methods public static void WriteToBinaryWriter(FeModel model, BinaryWriter bw) { // Write geometry if (model == null || model.Geometry == null) { bw.Write((int)0); } else { bw.Write((int)1); FeMesh.WriteToBinaryWriter(model.Geometry, bw); } // Write mesh if (model == null || model.Mesh == null) { bw.Write((int)0); } else { bw.Write((int)1); FeMesh.WriteToBinaryWriter(model.Mesh, bw); } } public static void ReadFromBinaryReader(FeModel model, BinaryReader br, int version) { // Read geometry int geometryExists = br.ReadInt32(); if (geometryExists == 1) { FeMesh.ReadFromBinaryReader(model.Geometry, br, version); } // Read mesh int meshExists = br.ReadInt32(); if (meshExists == 1) { FeMesh.ReadFromBinaryReader(model.Mesh, br, version); } } // Check public string[] CheckValidity(List> items) { // Tuple ... Tuple if (_mesh == null) return new string[0]; // List invalidItems = new List(); bool valid = false; invalidItems.AddRange(_geometry.CheckValidity(items, IsMeshSetupItemProperlyDefined)); invalidItems.AddRange(_mesh.CheckValidity(items, IsMeshSetupItemProperlyDefined)); // Materials Material material; foreach (var entry in _materials) { material = entry.Value; valid = true; foreach (var property in material.Properties) { // Check equations valid &= property.TryCheckEquations(); } // SetItemValidity(null, material, valid, items); if (!valid && material.Active) invalidItems.Add("Material: " + material.Name); } // Sections Section section; foreach (var entry in _sections) { section = entry.Value; // Region valid = IsSectionRegionValid(section); // if (section is SolidSection || section is ShellSection || section is MembraneSection) valid &= _materials.ContainsValidKey(section.MaterialName); else if (section is PointMassSection || section is DistributedMassSection) { } else throw new NotSupportedException(); // Check equations valid &= section.TryCheckEquations(); // SetItemValidity(null, section, valid, items); if (!valid && section.Active) invalidItems.Add("Section: " + section.Name); } // Constraints Constraint constraint; foreach (var entry in _constraints) { constraint = entry.Value; // Region valid = IsConstraintRegionValid(constraint); // Check equations valid &= constraint.TryCheckEquations(); // SetItemValidity(null, constraint, valid, items); if (!valid && constraint.Active) invalidItems.Add("Constraint: " + constraint.Name); } // Contact pairs ContactPair contactPair; foreach (var entry in _contactPairs) { contactPair = entry.Value; valid = _surfaceInteractions.ContainsValidKey(contactPair.SurfaceInteractionName) && _mesh.Surfaces.ContainsValidKey(contactPair.SlaveRegionName) && _mesh.Surfaces.ContainsValidKey(contactPair.MasterRegionName); // SetItemValidity(null, contactPair, valid, items); if (!valid && contactPair.Active) invalidItems.Add("Contact pair: " + contactPair.Name); } // Distributions Distribution distribution; foreach (var entry in _distributions) { distribution = entry.Value; valid = true; // Coordinate system if (distribution.CoordinateSystemName != CaeMesh.CoordinateSystem.DefaultCoordinateSystemName && !_mesh.CoordinateSystems.ContainsValidKey(distribution.CoordinateSystemName)) valid = false; // SetItemValidity(null, distribution, valid, items); if (!valid && distribution.Active) invalidItems.Add("Distribution: " + distribution.Name); } // Initial conditions InitialCondition initialCondition; foreach (var entry in _initialConditions) { initialCondition = entry.Value; // Region valid = IsInitialConditionRegionValid(initialCondition); // Distribution if (initialCondition is IDistribution icd) { if (icd.DistributionName != Distribution.DefaultDistributionName && !_distributions.ContainsValidKey(icd.DistributionName)) valid = false; } // Check equations valid &= initialCondition.TryCheckEquations(); // SetItemValidity(null, initialCondition, valid, items); if (!valid && initialCondition.Active) invalidItems.Add("Initial condition: " + initialCondition.Name); } // Steps HistoryOutput historyOutput; BoundaryCondition bc; Load load; DefinedField definedField; // foreach (var step in _stepCollection.StepsList) { // History output foreach (var hoEntry in step.HistoryOutputs) { historyOutput = hoEntry.Value; // Region valid = IsHistoryOutputRegionValid(historyOutput); // SetItemValidity(step.Name, historyOutput, valid, items); if (!valid && historyOutput.Active) invalidItems.Add("History output: " + step.Name + ", " + historyOutput.Name); } // Boundary conditions foreach (var bcEntry in step.BoundaryConditions) { bc = bcEntry.Value; // Region valid = IsBoundaryConditionRegionValid(bc); // Distribution if (bc is IDistribution bcd) { if (bcd.DistributionName != Distribution.DefaultDistributionName && !_distributions.ContainsValidKey(bcd.DistributionName)) valid = false; } // Amplitude if (bc.AmplitudeName != Amplitude.DefaultAmplitudeName && !_amplitudes.ContainsValidKey(bc.AmplitudeName)) valid = false; // Coordinate system if (bc.CoordinateSystemName != CaeMesh.CoordinateSystem.DefaultCoordinateSystemName && !_mesh.CoordinateSystems.ContainsValidKey(bc.CoordinateSystemName)) valid = false; // Check equations valid &= bc.TryCheckEquations(); // SetItemValidity(step.Name, bc, valid, items); if (!valid && bc.Active) invalidItems.Add("Boundary condition: " + step.Name + ", " + bc.Name); } // Loads foreach (var loadEntry in step.Loads) { load = loadEntry.Value; // Region valid = IsLoadRegionValid(load); // D2 vs axisymmetric if (valid && load is CentrifLoad cf) { if (_properties.ModelSpace == ModelSpaceEnum.PlaneStress || _properties.ModelSpace == ModelSpaceEnum.PlaneStrain) { if (cf.Axisymmetric == true) valid = false; } else if (_properties.ModelSpace == ModelSpaceEnum.Axisymmetric) { if (cf.Axisymmetric == false) valid = false; } } // Distribution if (load is IDistribution lwd) { if (lwd.DistributionName != Distribution.DefaultDistributionName && !_distributions.ContainsValidKey(lwd.DistributionName)) valid = false; } // Amplitude if (load.AmplitudeName != Amplitude.DefaultAmplitudeName && !_amplitudes.ContainsValidKey(load.AmplitudeName)) valid = false; // Coordinate system if (load.CoordinateSystemName != CoordinateSystem.DefaultCoordinateSystemName && !_mesh.CoordinateSystems.ContainsValidKey(load.CoordinateSystemName)) valid = false; // Check equations valid &= load.TryCheckEquations(); // SetItemValidity(step.Name, load, valid, items); if (!valid && load.Active) invalidItems.Add("Load: " + step.Name + ", " + load.Name); } // Defined fields foreach (var fieldEntry in step.DefinedFields) { definedField = fieldEntry.Value; // Region valid = IsDefinedFieldRegionValid(definedField); // Distribution if (definedField is IDistribution dfd) { if (dfd.DistributionName != Distribution.DefaultDistributionName && !_distributions.ContainsValidKey(dfd.DistributionName)) valid = false; } // Check equations valid &= definedField.TryCheckEquations(); // SetItemValidity(step.Name, definedField, valid, items); if (!valid && definedField.Active) invalidItems.Add("Defined field: " + step.Name + ", " + definedField.Name); } } // return invalidItems.ToArray(); } private void Check2D(FeMesh mesh) { // Check for 2D geometry - the same check in ImportGeometry if (_properties.ModelSpace.IsTwoD()) { if (!mesh.BoundingBox.Is2D()) throw new CaeException("The selected file does not contain 2D geometry in x-y plane."); else if (!Check2DSurfaceNormals(mesh)) { MessageBoxes.ShowWarning("The imported geometry contains faces oriented in the wrong direction (negative Z). " + "To use them in the analysis, change their orientation."); } } } private bool Check2DSurfaceNormals(FeMesh mesh) { int cellId; int[] cell; FeNode normal; foreach (var entry in mesh.Parts) { for (int i = 0; i < entry.Value.Visualization.CellIdsByFace.Length; i++) { if (entry.Value.Visualization.CellIdsByFace[i].Length > 0) { cellId = entry.Value.Visualization.CellIdsByFace[i][0]; cell = entry.Value.Visualization.Cells[cellId]; normal = mesh.ComputeNormalFromFaceCellIndices(cell); if (normal.Z < 0) return false; } } } return true; } public bool IsSectionRegionValid(Section section) { bool valid; // if (section is SolidSection ss) { valid = (ss.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(ss.RegionName)) || (ss.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(ss.RegionName)); } else if (section is ShellSection shs) { valid = (shs.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(shs.RegionName)) || (shs.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(shs.RegionName)); } else if (section is MembraneSection ms) { valid = (ms.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(ms.RegionName)) || (ms.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(ms.RegionName)); } else if (section is PointMassSection pms) { valid = (pms.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(pms.RegionName)) || (pms.RegionType == RegionTypeEnum.ReferencePointName && _mesh.ReferencePoints.ContainsValidKey(pms.RegionName)); } else if (section is DistributedMassSection dms) { valid = dms.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(dms.RegionName); } else throw new NotSupportedException(); // return valid; } public bool IsInitialConditionRegionValid(InitialCondition initialCondition) { bool valid; // if (initialCondition is InitialTemperature it) { valid = (it.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(it.RegionName)) || (it.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(it.RegionName)); } else if (initialCondition is InitialTranslationalVelocity itv) { valid = (itv.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(itv.RegionName)) || (itv.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(itv.RegionName)) || (itv.RegionType == RegionTypeEnum.ReferencePointName && _mesh.ReferencePoints.ContainsValidKey(itv.RegionName)); } else if (initialCondition is InitialAngularVelocity iav) { valid = (iav.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(iav.RegionName)) || (iav.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(iav.RegionName)) || (iav.RegionType == RegionTypeEnum.ReferencePointName && _mesh.ReferencePoints.ContainsValidKey(iav.RegionName)); } else throw new NotSupportedException(); // return valid; } public bool IsHistoryOutputRegionValid(HistoryOutput historyOutput) { bool valid; // if (historyOutput is NodalHistoryOutput nho) { valid = (nho.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(nho.RegionName)) || (nho.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(nho.RegionName)) || (nho.RegionType == RegionTypeEnum.ReferencePointName && _mesh.ReferencePoints.ContainsValidKey(nho.RegionName)); } else if (historyOutput is ElementHistoryOutput eho) { valid = _mesh.ElementSets.ContainsValidKey(eho.RegionName); } else if (historyOutput is ContactHistoryOutput cho) { valid = _contactPairs.ContainsValidKey(cho.RegionName); } else throw new NotSupportedException(); // return valid; } public bool IsConstraintRegionValid(Constraint constraint) { bool valid; // if (constraint is PointSpring ps) { valid = (ps.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(ps.RegionName)) || (ps.RegionType == RegionTypeEnum.ReferencePointName && _mesh.ReferencePoints.ContainsValidKey(ps.RegionName)); } else if (constraint is SurfaceSpring ss) { valid = ss.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(ss.RegionName); } else if (constraint is CompressionOnly co) { valid = co.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(co.RegionName); } else if (constraint is RigidBody rb) { valid = (rb.ReferencePointName != null && _mesh.ReferencePoints.ContainsValidKey(rb.ReferencePointName)) && ((rb.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(rb.RegionName)) || (rb.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(rb.RegionName))); } else if (constraint is Tie t) { valid = _mesh.Surfaces.ContainsValidKey(t.SlaveRegionName) && _mesh.Surfaces.ContainsValidKey(t.MasterRegionName) && (t.SlaveRegionName != t.MasterRegionName); } else throw new NotSupportedException(); // return valid; } public bool IsBoundaryConditionRegionValid(BoundaryCondition bc) { bool valid; // if (bc is FixedBC fix) { valid = (fix.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(fix.RegionName)) || (fix.RegionType == RegionTypeEnum.SurfaceName && (_mesh.Surfaces.ContainsValidKey(fix.RegionName))) || (fix.RegionType == RegionTypeEnum.ReferencePointName && (_mesh.ReferencePoints.ContainsValidKey(fix.RegionName))); } else if (bc is DisplacementRotation dr) { valid = (dr.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(dr.RegionName)) || (dr.RegionType == RegionTypeEnum.SurfaceName && (_mesh.Surfaces.ContainsValidKey(dr.RegionName))) || (dr.RegionType == RegionTypeEnum.ReferencePointName && (_mesh.ReferencePoints.ContainsValidKey(dr.RegionName))); } else if (bc is SubmodelBC sm) { valid = (sm.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(sm.RegionName)) || (sm.RegionType == RegionTypeEnum.SurfaceName && (_mesh.Surfaces.ContainsValidKey(sm.RegionName))); } else if (bc is TemperatureBC tmp) { valid = (tmp.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(tmp.RegionName)) || (tmp.RegionType == RegionTypeEnum.SurfaceName && (_mesh.Surfaces.ContainsValidKey(tmp.RegionName))); } else throw new NotSupportedException(); // return valid; } public bool IsLoadRegionValid(Load load) { bool valid; FeSurface s; // if (load is CLoad cl) { valid = (cl.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(cl.RegionName)) || (cl.RegionType == RegionTypeEnum.ReferencePointName && (_mesh.ReferencePoints.ContainsValidKey(cl.RegionName))); } else if (load is MomentLoad ml) { valid = (ml.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(ml.RegionName)) || (ml.RegionType == RegionTypeEnum.ReferencePointName && (_mesh.ReferencePoints.ContainsValidKey(ml.RegionName))); } else if (load is DLoad dl) { valid = (_mesh.Surfaces.TryGetValue(dl.RegionName, out s) && s.Valid); } else if (load is HydrostaticPressure hpl) { valid = (_mesh.Surfaces.TryGetValue(hpl.SurfaceName, out s) && s.Valid); } else if (load is ImportedPressure ip) { valid = (_mesh.Surfaces.TryGetValue(ip.SurfaceName, out s) && s.Valid); } else if (load is STLoad stl) { valid = (_mesh.Surfaces.TryGetValue(stl.SurfaceName, out s) && s.Valid); } else if (load is ImportedSTLoad istl) { valid = (_mesh.Surfaces.TryGetValue(istl.SurfaceName, out s) && s.Valid); } else if (load is ShellEdgeLoad sel) { valid = (_mesh.Surfaces.TryGetValue(sel.SurfaceName, out s) && s.Valid); } else if (load is GravityLoad gl) { valid = (gl.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(gl.RegionName)) || (gl.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(gl.RegionName)) || (gl.RegionType == RegionTypeEnum.MassSection && _sections.ContainsValidKey(gl.RegionName)) || (gl.RegionType == RegionTypeEnum.Selection && _mesh.GetPartNamesFromPartIds(gl.CreationIds) != null && _mesh.GetPartNamesFromPartIds(gl.CreationIds).Length == gl.CreationIds.Length); } else if (load is CentrifLoad cf) { valid = (cf.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(cf.RegionName)) || (cf.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(cf.RegionName)) || (cf.RegionType == RegionTypeEnum.MassSection && _sections.ContainsValidKey(cf.RegionName)) || (cf.RegionType == RegionTypeEnum.Selection && _mesh.GetPartNamesFromPartIds(cf.CreationIds) != null && _mesh.GetPartNamesFromPartIds(cf.CreationIds).Length == cf.CreationIds.Length); } else if (load is PreTensionLoad ptl) { valid = (_mesh.Surfaces.TryGetValue(ptl.SurfaceName, out s) && s.Valid && s.Type == FeSurfaceType.Element); } // Thermal else if (load is CFlux cfl) { valid = (cfl.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(cfl.RegionName)); } else if (load is DFlux df) { valid = (_mesh.Surfaces.TryGetValue(df.SurfaceName, out s) && s.Valid); } else if (load is BodyFlux bf) { valid = (bf.RegionType == RegionTypeEnum.PartName && _mesh.Parts.ContainsValidKey(bf.RegionName)) || (bf.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsValidKey(bf.RegionName) || (bf.RegionType == RegionTypeEnum.Selection && _mesh.GetPartNamesFromPartIds(bf.CreationIds) != null && _mesh.GetPartNamesFromPartIds(bf.CreationIds).Length == bf.CreationIds.Length)); } else if (load is FilmHeatTransfer fht) { valid = (_mesh.Surfaces.TryGetValue(fht.SurfaceName, out s) && s.Valid); } else if (load is RadiationHeatTransfer rht) { valid = (_mesh.Surfaces.TryGetValue(rht.SurfaceName, out s) && s.Valid); } else throw new NotSupportedException(); // return valid; } public bool IsDefinedFieldRegionValid(DefinedField definedField) { bool valid; // if (definedField is DefinedTemperature dt) { if (dt.Type == DefinedTemperatureTypeEnum.ByValue) { valid = (dt.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsValidKey(dt.RegionName)) || (dt.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsValidKey(dt.RegionName)); } else if (dt.Type == DefinedTemperatureTypeEnum.FromFile) { // Defined field created from file needs no selection valid = true; } else throw new NotSupportedException(); } else throw new NotSupportedException(); // return valid; } private void SetItemValidity(string stepName, NamedClass item, bool validity, List> items) { if (item.Valid != validity) { item.Valid = validity; items.Add(new Tuple(item, stepName)); } } public bool RegionValid(IMultiRegion multiRegion) { if (multiRegion.RegionType == RegionTypeEnum.NodeSetName && _mesh.NodeSets.ContainsKey(multiRegion.RegionName)) return _mesh.NodeSets[multiRegion.RegionName].Valid; else if (multiRegion.RegionType == RegionTypeEnum.ElementSetName && _mesh.ElementSets.ContainsKey(multiRegion.RegionName)) return _mesh.ElementSets[multiRegion.RegionName].Valid; else if (multiRegion.RegionType == RegionTypeEnum.SurfaceName && _mesh.Surfaces.ContainsKey(multiRegion.RegionName)) return _mesh.Surfaces[multiRegion.RegionName].Valid; // return false; } // public int[] GetSectionAssignments(out Dictionary elementIdSectionId) { int sectionId = 0; elementIdSectionId = new Dictionary(); // foreach (var entry in _sections) { if (entry.Value is MassSection) continue; // if (entry.Value.RegionType == RegionTypeEnum.PartName) { foreach (var elementId in _mesh.Parts[entry.Value.RegionName].Labels) { if (elementIdSectionId.ContainsKey(elementId)) elementIdSectionId[elementId] = sectionId; else elementIdSectionId.Add(elementId, sectionId); } } else if (entry.Value.RegionType == RegionTypeEnum.ElementSetName) { if (entry.Value is SolidSection) { FeElementSet elementSet = _mesh.ElementSets[entry.Value.RegionName]; if (elementSet.CreatedFromParts) { string[] partNames = _mesh.GetPartNamesFromPartIds(elementSet.Labels); foreach (var partName in partNames) { foreach (var elementId in _mesh.Parts[partName].Labels) { if (elementIdSectionId.ContainsKey(elementId)) elementIdSectionId[elementId] = sectionId; else elementIdSectionId.Add(elementId, sectionId); } } } else { foreach (var elementId in elementSet.Labels) { if (elementIdSectionId.ContainsKey(elementId)) elementIdSectionId[elementId] = sectionId; else elementIdSectionId.Add(elementId, sectionId); } } } else if (entry.Value is ShellSection || entry.Value is MembraneSection) { FeElementSet elementSet = _mesh.ElementSets[entry.Value.RegionName]; foreach (var elementId in elementSet.Labels) { if (elementIdSectionId.ContainsKey(elementId)) elementIdSectionId[elementId] = sectionId; else elementIdSectionId.Add(elementId, sectionId); } } else throw new NotSupportedException(); } else throw new NotSupportedException(); // sectionId++; } // Not assigned IEnumerable unAssignedElementIds = _mesh.Elements.Keys.Except(elementIdSectionId.Keys); int[] unAssignedElementIdsArray = new int[unAssignedElementIds.Count()]; int count = 0; foreach (var elementId in unAssignedElementIds) { elementIdSectionId.Add(elementId, -1); unAssignedElementIdsArray[count++] = elementId; } // return unAssignedElementIdsArray; } public void GetMaterialAssignments(out Dictionary elementIdMaterialId) { // Get element section ids Dictionary elementIdSectionId; GetSectionAssignments(out elementIdSectionId); // Get material ids int count = 0; Dictionary materialId = new Dictionary(); foreach (var entry in _materials) materialId.Add(entry.Value.Name, count++); // Get a map of section materials count = 0; Dictionary sectionIdMaterialId = new Dictionary(); sectionIdMaterialId.Add(-1, -1); // add missing section foreach (var entry in _sections) sectionIdMaterialId.Add(count++, materialId[entry.Value.MaterialName]); // Use the map elementIdMaterialId = new Dictionary(); foreach (var entry in elementIdSectionId) elementIdMaterialId.Add(entry.Key, sectionIdMaterialId[entry.Value]); } public void GetNodalSafetyFactorLimits() { Dictionary elementIdMaterialId; GetMaterialAssignments(out elementIdMaterialId); // int count = 0; Dictionary materialIdSafetyFactor = new Dictionary(); foreach (var entry in _materials) { //if (safetyFactor != null) materialIdSafetyFactor.Add(count++, safetyFactor.SafetyFactorLimitValue); //else materialIdSafetyFactor.Add(count++, double.NaN); } // Dictionary nodeIdSafetyFactorLimit = new Dictionary(); } public bool AreSlipWearCoefficientsDefined(out Dictionary materialIdCoefficient) { int count = 0; bool containsWear = false; double coefficient; materialIdCoefficient = new Dictionary(); // For each material check if the material has wear coefficients defined foreach (var entry in _materials) { coefficient = 0; foreach (var property in entry.Value.Properties) { if (property is SlipWear sw) { coefficient = sw.WearCoefficient.Value / sw.Hardness.Value * _properties.CyclesIncrement; containsWear = true; break; } } // materialIdCoefficient.Add(count++, coefficient); } return containsWear; } public Dictionary GetNodalSlipWearCoefficients() { double coefficient; Dictionary materialIdCoefficient; bool containsWear = AreSlipWearCoefficientsDefined(out materialIdCoefficient); // If wear coefficients are defined if (containsWear) { Dictionary elementIdMaterialId; GetMaterialAssignments(out elementIdMaterialId); // Get wear coefficient for each element Dictionary elementIdCoefficient = new Dictionary(); foreach (var entry in elementIdMaterialId) { elementIdCoefficient.Add(entry.Key, materialIdCoefficient[entry.Value]); } // Get wear coefficients for each node HashSet allCoefficients; Dictionary> nodeIdAllCoefficients = new Dictionary>(); FeElement element; foreach (var entry in elementIdCoefficient) { element = _mesh.Elements[entry.Key]; foreach (var nodeId in element.NodeIds) { if (nodeIdAllCoefficients.TryGetValue(nodeId, out allCoefficients)) allCoefficients.Add(entry.Value); else nodeIdAllCoefficients.Add(nodeId, new HashSet() { entry.Value }); } } // Compute the average Dictionary nodeIdCoefficient = new Dictionary(); foreach (var entry in nodeIdAllCoefficients) { coefficient = 0; foreach (var value in entry.Value) coefficient += value; coefficient /= entry.Value.Count(); // nodeIdCoefficient.Add(entry.Key, coefficient); } // return nodeIdCoefficient; } else return null; } public void GetSectionThicknessAssignments(out Dictionary elementIdSectionThicknessId) { // Get element section ids Dictionary elementIdSectionId; GetSectionAssignments(out elementIdSectionId); // Get thicknesses int count = 0; double thickness; List sectionIds; Dictionary> thicknessSectionIds = new Dictionary>(); foreach (var entry in _sections) { thickness = GetSectionThickness(entry.Value); // if (thicknessSectionIds.TryGetValue(thickness, out sectionIds)) sectionIds.Add(count); else thicknessSectionIds.Add(thickness, new List() { count }); count++; } double[] sortedThicknesses = thicknessSectionIds.Keys.ToArray(); Array.Sort(sortedThicknesses); // Get a map of section thicknesses Dictionary sectionIdSectionThicknessId = new Dictionary(); sectionIdSectionThicknessId.Add(-1, -1); if (sortedThicknesses.Length > 0 && sortedThicknesses[0] == -1) count = -1; else count = 0; foreach (var sortedThickness in sortedThicknesses) { foreach (var sectionId in thicknessSectionIds[sortedThickness]) { sectionIdSectionThicknessId.Add(sectionId, count); } count++; } // Use the map elementIdSectionThicknessId = new Dictionary(); foreach (var entry in elementIdSectionId) elementIdSectionThicknessId.Add(entry.Key, sectionIdSectionThicknessId[entry.Value]); } public double GetSectionThickness(Section section) { if (_properties.ModelSpace.IsTwoD() && section is SolidSection sos) return sos.Thickness.Value; else if (section is ShellSection shs) return shs.Thickness.Value; else if (section is MembraneSection ms) return ms.Thickness.Value; else return -1; } // public void RemoveLostUserKeywords(Action SetNumberOfUserKeywords) { try { FileInOut.Output.CalculixFileWriter.RemoveLostUserKeywords(this); SetNumberOfUserKeywords?.Invoke(_calculixUserKeywords.Count); } catch { } } // Import public string[] ImportGeometryFromStlFile(string fileName) { FeMesh mesh = StlFileReader.Read(fileName); // Shading foreach (var entry in mesh.Parts) entry.Value.SmoothShaded = true; // string[] addedPartNames = ImportGeometry(mesh, GetReservedPartNames()); // return addedPartNames; } public string[] ImportGeometryFromBrepFile(string visFileName, string brepFileName) { FeMesh mesh = VisFileReader.Read(visFileName); // if (mesh.Parts.GetValueByIndex(0) is GeometryPart gp) { gp.CADFileDataFromFile(brepFileName); gp.SmoothShaded = true; } // string[] addedPartNames = ImportGeometry(mesh, GetReservedPartNames()); // return addedPartNames; } public void ImportMeshFromVolFile(string fileName) { FeMesh mesh = VolFileReader.Read(fileName, ElementsToImport.Shell | ElementsToImport.Solid); // ImportMesh(mesh, GetReservedPartNames(), true, false); } public bool ImportMeshFromMmgFile(string fileName, ElementsToImport elementsToImport = ElementsToImport.All, bool convertToSecondOrder = false) { FeMesh mesh = MmgFileReader.Read3D(fileName, elementsToImport, MeshRepresentation.Mesh, convertToSecondOrder); // bool noErrors = true; foreach (var entry in mesh.Parts) { if (entry.Value is GeometryPart gp && gp.HasErrors) { noErrors = false; break; } } // ImportMesh(mesh, GetReservedPartNames(), true, false); // return noErrors; } public void ImportGeneratedMeshFromMeshFile(string fileName, BasePart part, bool convertToSecondOrder, bool splitCompoundMesh, bool mergeCompoundParts) { ElementsToImport elementsToImport; if (part.PartType == PartType.SolidAsShell) { elementsToImport = ElementsToImport.Solid; } else if (part.PartType == PartType.Shell) { elementsToImport = ElementsToImport.Shell; } else if (part.PartType == PartType.Compound) { var subPart = _geometry.Parts[((CompoundGeometryPart)part).SubPartNames[0]] as GeometryPart; if (subPart != null && subPart.PartType == PartType.SolidAsShell) { elementsToImport = ElementsToImport.Solid; } else if (subPart != null && subPart.PartType == PartType.Shell) { elementsToImport = ElementsToImport.Shell; } else { throw new NotSupportedException(); } } else { throw new NotSupportedException(); } // Get part names - determine, if one part or multiple parts are needed string[] prevPartNames; if (part is CompoundGeometryPart cgp) { if (mergeCompoundParts) { prevPartNames = new string[] { part.Name }; } else { prevPartNames = cgp.SubPartNames.ToArray(); } } else { prevPartNames = new string[] { part.Name }; } // Called after meshing in PrePoMax - the parts are sorted by id FeMesh mesh; if (Path.GetExtension(fileName) == ".vol") { mesh = VolFileReader.Read(fileName, elementsToImport, convertToSecondOrder); } else if (Path.GetExtension(fileName) == ".mesh") { mesh = MmgFileReader.Read(fileName, elementsToImport, MeshRepresentation.Mesh, convertToSecondOrder); } else if (Path.GetExtension(fileName) == ".inp") { mesh = InpFileReader.ReadMesh(fileName, elementsToImport, convertToSecondOrder); } else { throw new NotSupportedException(); } // Split compound mesh if (splitCompoundMesh) { mesh.SplitSolidCompoundMesh(); } // Merge parts if only one part is expected string[] partNames = mesh.Parts.Keys.ToArray(); if (prevPartNames.Length != partNames.Length) { if (prevPartNames.Length == 1 && partNames.Length > 1) { mesh.MergeMeshParts(mesh.Parts.Keys.ToArray(), out _, out _); partNames = mesh.Parts.Keys.ToArray(); } else { throw new NotSupportedException(); } } // Rename the imported part/s BasePart[] importedParts = new BasePart[partNames.Length]; for (int i = 0; i < partNames.Length; i++) { importedParts[i] = mesh.Parts[partNames[i]]; importedParts[i].Name = prevPartNames[i]; } mesh.Parts.Clear(); for (int i = 0; i < partNames.Length; i++) { mesh.Parts.Add(importedParts[i].Name, importedParts[i]); } // ImportMesh(mesh, null, false); // Recolor parts at the end of the import foreach (var importedPart in importedParts) { if (_geometry.Parts.ContainsKey(importedPart.Name) && _mesh.Parts.ContainsKey(importedPart.Name)) { _mesh.Parts[importedPart.Name].Color = _geometry.Parts[importedPart.Name].Color; } } } public static bool DeepCompare(object obj, object another) { if (ReferenceEquals(obj, another)) return true; if ((obj == null) || (another == null)) return false; //Compare two object's class, return false if they are difference if (obj.GetType() != another.GetType()) return false; var result = true; //Get all properties of obj //And compare each other foreach (var property in obj.GetType().GetProperties()) { var objValue = property.GetValue(obj); var anotherValue = property.GetValue(another); if (!objValue.Equals(anotherValue)) result = false; } return result; } public static bool CompareEx(object obj, object another) { if (ReferenceEquals(obj, another)) return true; if ((obj == null) || (another == null)) return false; if (obj.GetType() != another.GetType()) return false; //properties: int, double, DateTime, etc, not class if (!obj.GetType().IsClass) return obj.Equals(another); var result = true; foreach (var property in obj.GetType().GetProperties()) { var objValue = property.GetValue(obj); var anotherValue = property.GetValue(another); //Recursion if (!DeepCompare(objValue, anotherValue)) result = false; } return result; } public void ImportGeneratedRemeshFromMeshFile(string fileName, int[] elementIds, BasePart part, bool convertToSecondOrder, Dictionary midNodes) { // Remove elements from the mesh HashSet possiblyUnrefNodeIds = new HashSet(); foreach (var elId in elementIds) possiblyUnrefNodeIds.UnionWith(_mesh.Elements[elId].NodeIds); // contains midside nodes HashSet removedNodeIds = _mesh.RemoveElementsByIds(new HashSet(elementIds), possiblyUnrefNodeIds, false, false, true); HashSet borderNodeIds = new HashSet(possiblyUnrefNodeIds.Except(removedNodeIds)); // contains midside nodes Dictionary borderNodes = new Dictionary(); foreach (var ndId in borderNodeIds) borderNodes.Add(ndId, _mesh.Nodes[ndId]); // contains midside nodes HashSet remainingNodeIds = new HashSet(_mesh.Nodes.Keys.Except(removedNodeIds)); // Read the mmg file and renumber nodes and elements double epsilon = 1E-6; double max = part.BoundingBox.GetDiagonal(); Dictionary> partNameNewSurfIdOldSurfId = new Dictionary>(); Dictionary> partNameNewEdgeIdOldEdgeId = new Dictionary>(); FeMesh mmgMesh = MmgFileReader.Read(fileName, ElementsToImport.Shell, MeshRepresentation.Mesh, convertToSecondOrder, _mesh.MaxNodeId + 1, _mesh.MaxElementId + 1, borderNodes, midNodes, epsilon * max, partNameNewSurfIdOldSurfId, partNameNewEdgeIdOldEdgeId); // Get surface nodes before modification Dictionary> surfaceIdNodeIds = part.Visualization.GetSurfaceIdNodeIds(); foreach (var entry in surfaceIdNodeIds) entry.Value.ExceptWith(removedNodeIds); // Get edge nodes before modification Dictionary> edgeIdNodeIds = part.Visualization.GetEdgeIdNodeIds(); foreach (var entry in edgeIdNodeIds) entry.Value.ExceptWith(removedNodeIds); // Add elements to mesh FeElement element; HashSet elementTypes = new HashSet(); foreach (var entry in mmgMesh.Elements) { element = entry.Value; element.PartId = part.PartId; elementTypes.Add(element.GetType()); _mesh.Elements.Add(entry.Key, element); } // Add elements to part HashSet newPartElementIds = new HashSet(part.Labels); newPartElementIds.UnionWith(mmgMesh.Elements.Keys); part.Labels = newPartElementIds.ToArray(); Array.Sort(part.Labels); // Add element types to part if (part is MeshPart mp) mp.AddElementTypes(elementTypes.ToArray()); // Add nodes to mesh foreach (var entry in mmgMesh.Nodes) { if (!_mesh.Nodes.ContainsKey(entry.Key)) _mesh.Nodes.Add(entry.Key, entry.Value); } // Add nodes to part HashSet newPartNodeIds = new HashSet(part.NodeLabels); newPartNodeIds.UnionWith(mmgMesh.Nodes.Keys); part.NodeLabels = newPartNodeIds.ToArray(); Array.Sort(part.NodeLabels); // Update node ids _mesh.UpdateMaxNodeAndElementIds(); _mesh.UpdateNodeIdElementIds(); // Model vertices HashSet vertexNodeIds = new HashSet(); // Get vertices from part - only those that were not removed foreach (var nodeId in part.Visualization.VertexNodeIds) { if (!removedNodeIds.Contains(nodeId)) vertexNodeIds.Add(nodeId); } // Get vertices from mmgPart foreach (var entry in mmgMesh.Parts) vertexNodeIds.UnionWith(entry.Value.Visualization.VertexNodeIds); // Model edges int elementId = mmgMesh.MaxElementId + 1; LinearBeamElement beamElement; List edgeElements = new List(); // Get model edges from part - only edges that are not completely removed int[] key; CompareIntArray comparer = new CompareIntArray(); HashSet edgeKeys = new HashSet(comparer); // foreach (var edgeCell in part.Visualization.EdgeCells) { if (remainingNodeIds.Contains(edgeCell[0]) && remainingNodeIds.Contains(edgeCell[1])) { key = Tools.GetSortedKey(edgeCell[0], edgeCell[1]); if (!edgeKeys.Contains(key)) { beamElement = new LinearBeamElement(elementId++, key); edgeElements.Add(beamElement); edgeKeys.Add(key); } } } // Get model edges from mmgPart foreach (var entry in mmgMesh.Parts) { foreach (var edgeCell in entry.Value.Visualization.EdgeCells) { key = Tools.GetSortedKey(edgeCell[0], edgeCell[1]); if (!edgeKeys.Contains(key)) { beamElement = new LinearBeamElement(elementId++, key); edgeElements.Add(beamElement); edgeKeys.Add(key); } } } // Add edge elements to mesh foreach (var edgeElement in edgeElements) _mesh.Elements.Add(edgeElement.Id, edgeElement); // Extract visualization _mesh.ExtractShellPartVisualization(part, false, -1); // _mesh.ConvertLineFeElementsToEdges(vertexNodeIds, false, part.Name); // Renumber surfaces BasePart mmgPart; Dictionary> itemIdNodeIds; foreach (var partNewSurfIdOldSurfId in partNameNewSurfIdOldSurfId) { mmgPart = mmgMesh.Parts[partNewSurfIdOldSurfId.Key]; itemIdNodeIds = mmgPart.Visualization.GetSurfaceIdNodeIds(); // foreach (var newSurfIdOldSurfId in partNewSurfIdOldSurfId.Value) { surfaceIdNodeIds[newSurfIdOldSurfId.Value].UnionWith(itemIdNodeIds[newSurfIdOldSurfId.Key]); surfaceIdNodeIds[newSurfIdOldSurfId.Value].IntersectWith(part.NodeLabels); } } _mesh.RenumberVisualizationSurfaces(part, surfaceIdNodeIds); // Renumber edges foreach (var partNewEdgeIdOldEdgeId in partNameNewEdgeIdOldEdgeId) { if (mmgMesh.Parts.TryGetValue(partNewEdgeIdOldEdgeId.Key, out mmgPart)) { itemIdNodeIds = mmgPart.Visualization.GetEdgeIdNodeIds(); // foreach (var newEdgeIdOldEdgeId in partNewEdgeIdOldEdgeId.Value) { edgeIdNodeIds[newEdgeIdOldEdgeId.Value].UnionWith(itemIdNodeIds[newEdgeIdOldEdgeId.Key]); edgeIdNodeIds[newEdgeIdOldEdgeId.Value].IntersectWith(part.NodeLabels); } } } _mesh.RenumberPartVisualizationEdges(part, edgeIdNodeIds); // _mesh.RemoveElementsByType(); // _mesh.ComputeVolumeArea(part); // UpdateMeshPartsElementTypes(false); } public List ImportModelFromInpFile(string fileName, Action WriteDataToOutput) { OrderedDictionary indexedUserKeywords; InpFileReader.Read(fileName, ElementsToImport.Solid | ElementsToImport.Shell, this, WriteDataToOutput, out indexedUserKeywords); // CalculixUserKeywords = indexedUserKeywords; // return InpFileReader.Errors; } public List ImportMaterialsFromInpFile(string fileName, Action WriteDataToOutput) { FeModel model = new FeModel("Imported Materials", _unitSystem); model.Properties.ModelSpace = _properties.ModelSpace; // Add existing model materials to account for indexing of material user keywords string existingMaterialName; foreach (var entry in _materials) { existingMaterialName = "_internal_for_indices_" + entry.Key; model.Materials.Add(existingMaterialName, entry.Value.DeepClone()); } List existingMaterialNames = model.Materials.Keys.ToList(); // InpFileReader.Read(fileName, ElementsToImport.Solid | ElementsToImport.Shell, model, WriteDataToOutput, out OrderedDictionary indexedUserKeywords); // CalculixUserKeywords = indexedUserKeywords; // Remove existing model materials foreach (var materialName in existingMaterialNames) model.Materials.Remove(materialName); // string name; foreach (var entry in model.Materials) { name = entry.Key; if (_materials.ContainsKey(name)) { name += "_Imported"; if (_materials.ContainsKey(name)) { name = _materials.GetNextNumberedKey(name); } } entry.Value.Name = name; _materials.Add(name, entry.Value); } // return InpFileReader.Errors; } public void ImportMeshFromUnvFile(string fileName) { FeMesh mesh = UnvFileReader.Read(fileName, ElementsToImport.Shell | ElementsToImport.Solid); // ImportMesh(mesh, GetReservedPartNames(), true, false); } public void ImportMeshFromObjFile(string fileName) { FeMesh mesh = ObjFileReader.Read(fileName); // ImportMesh(mesh, GetReservedPartNames(), true, false); } // private string[] ImportGeometry(FeMesh mesh, ICollection reservedPartNames) { Check2D(mesh); // if (_geometry == null) { _geometry = new FeMesh(MeshRepresentation.Geometry); mesh.ResetPartsColor(); } // string[] addedPartNames = _geometry.AddMesh(mesh, reservedPartNames, GetReservedPartIds()); return addedPartNames; } public void ImportMesh(FeMesh mesh, ICollection reservedPartNames, bool forceRenameParts = true, bool renumberNodesAndElements = true) { Check2D(mesh); // if (_mesh == null) { _mesh = new FeMesh(MeshRepresentation.Mesh); mesh.ResetPartsColor(); } _mesh.AddMesh(mesh, reservedPartNames, GetReservedPartIds(), forceRenameParts, renumberNodesAndElements); } // Update public void UpdateGeometryPartMassPropertiesFromVisFile(string visFileName, string partName) { FeMesh mesh = VisFileReader.Read(visFileName); // if (mesh.Parts.Count == 1) { BasePart part = _geometry.Parts[partName]; BasePart updatedPart = mesh.Parts.First().Value; //part.Visualization = updatedPart.Visualization; part.MassProperties = updatedPart.MassProperties; } } // Setters public void SetMesh(FeMesh mesh) { _mesh = mesh; } // Getters public string[] GetAllMeshEntityNames() { if (_mesh != null) return _mesh.GetAllMeshEntityNames(); return new string[0]; } public HashSet GetReservedPartNames() { HashSet reservedPartNames = new HashSet(); if (_geometry != null && _geometry.Parts != null) reservedPartNames.UnionWith(_geometry.Parts.Keys); reservedPartNames.UnionWith(GetAllMeshEntityNames()); return reservedPartNames; } public HashSet GetReservedPartIds() { HashSet reservedPartIds = new HashSet(); if (_geometry != null && _geometry.Parts != null) reservedPartIds.UnionWith(_geometry.GetAllPartIds()); if (_mesh != null && _mesh.Parts != null) reservedPartIds.UnionWith(_mesh.GetAllPartIds()); return reservedPartIds; } // Mesh setup items public string IsMeshSetupItemProperlyDefined(MeshSetupItem meshSetupItem) { if (meshSetupItem is MeshingParameters) return null; else if (meshSetupItem is FeMeshRefinement) return null; else if (meshSetupItem is ShellGmsh sg) return IsShellGmshProperlyDefined(sg); else if (meshSetupItem is ThickenShellMesh tsm) return IsThickenShellMeshProperlyDefined(tsm); else if (meshSetupItem is TetrahedralGmsh tg) return IsTetrahedralGmshProperlyDefined(tg); else if (meshSetupItem is TransfiniteMesh tm) return IsTransfiniteMeshProperlyDefined(tm); else if (meshSetupItem is ExtrudeMesh em) return IsExtrudeMeshProperlyDefined(em); else if (meshSetupItem is SweepMesh sm) return IsSweepMeshProperlyDefined(sm); else if (meshSetupItem is RevolveMesh rm) return IsRevolveMeshProperlyDefined(rm); else throw new NotSupportedException("MeshSetupItemTypeException"); } private string IsShellGmshProperlyDefined(ShellGmsh shellGmsh) { BasePart part; int[] partIds = FeMesh.GetPartIdsFromGeometryIds(shellGmsh.CreationIds); // foreach (var partId in partIds) { part = _geometry.GetPartFromId(partId); // if (part.PartType != PartType.Shell) return "The shell gmsh setup item can only be defined on shell parts."; } return null; } private string IsThickenShellMeshProperlyDefined(ThickenShellMesh thickenShellMesh) { if (thickenShellMesh.PartNames != null && thickenShellMesh.PartNames.Length > 0) { BasePart part; foreach (var partName in thickenShellMesh.PartNames) { _geometry.Parts.TryGetValue(partName, out part); // Is mesh setup item defined on the mesh part if (part == null) part = _mesh.Parts[partName]; if (part == null) return "The part " + partName + " cannot be found neither in geometry parts neither in model parts."; // if (part.PartType != PartType.Shell) return "The thicken shell feature can only be used on shell parts."; if (part.Visualization.IsNonManifold()) return "The thicken shell feature can only be used on manifold shell parts."; } } else return "No parts are defined for the thicken shell mesh setup item."; // return null; } private string IsTetrahedralGmshProperlyDefined(TetrahedralGmsh tetrahedralGmsh) { BasePart part; int[] partIds = FeMesh.GetPartIdsFromGeometryIds(tetrahedralGmsh.CreationIds); // foreach (var partId in partIds) { part = _geometry.GetPartFromId(partId); // if (part.PartType != PartType.Solid && part.PartType != PartType.SolidAsShell) return "The tetrahedral gmsh setup item can only be defined on solid parts."; } return null; } private string IsTransfiniteMeshProperlyDefined(TransfiniteMesh transfiniteMesh) { GeometryPart part; int[] partIds = FeMesh.GetPartIdsFromGeometryIds(transfiniteMesh.CreationIds); // int num3sided; int num4sided; HashSet triSurfaceEdgeIds = new HashSet(); foreach (var partId in partIds) { part = (GeometryPart)_geometry.GetPartFromId(partId); // if (!part.IsCADPart) return "The transfinite gmsh setup item cannot be defined on a stl based part."; if (part.PartType != PartType.Solid && part.PartType != PartType.SolidAsShell) return "The transfinite gmsh setup item can only be defined on solid parts."; // //if (System.Diagnostics.Debugger.IsAttached || transfiniteMesh.AllowPrismElements) return null; if (transfiniteMesh.AllowPyramidElements) return null; else { if (part.Visualization.FaceCount == 5 || part.Visualization.FaceCount == 6) { num3sided = 0; num4sided = 0; triSurfaceEdgeIds.Clear(); for (int i = 0; i < part.Visualization.FaceCount; i++) { if (part.Visualization.FaceEdgeIds[i].Length == 3) { num3sided++; triSurfaceEdgeIds.UnionWith(part.Visualization.FaceEdgeIds[i]); } else if (part.Visualization.FaceEdgeIds[i].Length == 4) num4sided++; } if (!(num4sided == 6 || (num4sided == 3 && num3sided == 2))) return "The transfinite gmsh setup item can only be defined on solid parts with 3-sided and " + "4-sided faces."; if (num4sided == 3 && num3sided == 2 && triSurfaceEdgeIds.Count != 6) return "The transfinite gmsh setup item can only be defined on solid parts with non touching " + "3-sided faces."; } else return "The transfinite gmsh setup item can only be defined on solid parts with 5 or 6 faces."; } } return null; } private string IsExtrudeMeshProperlyDefined(ExtrudeMesh extrudeMesh) { string error = null; extrudeMesh.Direction = null; extrudeMesh.ExtrudeCenter = null; // if (extrudeMesh.AlgorithmMesh2D == CaeMesh.Meshing.GmshAlgorithmMesh2DEnum.QuasiStructuredQuad) return "The extrude mesh setup item cannot use the quasi-structured quad algorithm."; // if (extrudeMesh.ElementSizeType == CaeMesh.Meshing.ElementSizeTypeEnum.MultiLayerd && (extrudeMesh.LayerSizes.Length != extrudeMesh.NumOfElementsPerLayer.Length)) return "The number of layers must be equal for layer sizes and number of elements per layer."; // int[] selectedPartIds = FeMesh.GetPartIdsFromGeometryIds(extrudeMesh.CreationIds); // if (selectedPartIds.Length == 1) { // Get part int partId = selectedPartIds[0]; GeometryPart part = (GeometryPart)_geometry.GetPartFromId(partId); // if (IsPartCompoundSubPart(part.Name)) return "The extrude mesh setup item cannot be defined on a compound part."; if (!part.IsCADPart) return "The extrude mesh setup item cannot be defined on a stl based part."; if (part.PartType != PartType.Solid && part.PartType != PartType.SolidAsShell) return "The extrude mesh setup item cannot be defined on a shell part."; // VisualizationData vis = part.Visualization; // Get surface ids HashSet surfaceIds = new HashSet(); for (int i = 0; i < extrudeMesh.CreationIds.Length; i++) surfaceIds.Add(FeMesh.GetItemIdFromGeometryId(extrudeMesh.CreationIds[i])); // Do selected surfaces form a connected surface if (vis.AreSurfacesConnected(surfaceIds.ToArray())) { Dictionary> vertexIdEdgeId = vis.GetVertexIdEdgeIds(); HashSet surfaceVertices = vis.GetVertexNodeIdsForSurfaceIds(surfaceIds.ToArray()); HashSet surfaceEdgeIds = vis.GetEdgeIdsForSurfaceIds(surfaceIds.ToArray()); // HashSet directionEdgeIds = new HashSet(); foreach (var vertexId in surfaceVertices) directionEdgeIds.UnionWith(vertexIdEdgeId[vertexId].Except(surfaceEdgeIds)); // double directionLength = vis.GetEqualEdgeLengthOrNegative(directionEdgeIds); if (directionLength > 0) { bool straightEdges = false; if (vis.EdgeTypes != null) { HashSet edgeTypes = new HashSet(); foreach (var directionEdgeId in directionEdgeIds) edgeTypes.Add(vis.EdgeTypes[directionEdgeId]); // if (edgeTypes.Count() == 1 && edgeTypes.First() == GeomCurveType.Line) straightEdges = true; } if (!straightEdges) { straightEdges = true; double curvature; foreach (var directionEdgeId in directionEdgeIds) { curvature = vis.GetMaxEdgeCurvature(directionEdgeId, _geometry.Nodes); if (curvature > 0.001) { straightEdges = false; break; } } } if (straightEdges) { int[] edgeNodes; HashSet nodeIds; Vec3D normalizedDirection = null; BoundingBox bb = new BoundingBox(); foreach (var directionEdgeId in directionEdgeIds) { // Get all edge node ids nodeIds = vis.GetNodeIdsForEdgeId(directionEdgeId); // Reduce edge node ids to vertices edgeNodes = nodeIds.Intersect(vis.VertexNodeIds).ToArray(); if (edgeNodes.Length != 2) throw new NotSupportedException(); // First node must be on the selected surface if (!surfaceVertices.Contains(edgeNodes[0])) (edgeNodes[0], edgeNodes[1]) = (edgeNodes[1], edgeNodes[0]); // Compute the extrude direction normalizedDirection = _geometry.ComputeDirectionFromEdgeCellIndices(edgeNodes, edgeNodes[0]); bb.IncludeCoor(normalizedDirection.Coor); } // if (normalizedDirection != null && bb.GetDiagonal() < 0.0017) // approximately 0.1° difference { extrudeMesh.Direction = (directionLength * normalizedDirection).Coor; // bb = _geometry.GetBoundingBoxForNodeIds(surfaceVertices.ToArray()); extrudeMesh.ExtrudeCenter = bb.GetCenter(); // // Round double d = part.BoundingBox.GetDiagonal(); int digits = (int)Math.Log10(d) - 6; if (digits > 0) digits = 0; else if (digits < 0) digits *= -1; // extrudeMesh.Direction[0] = Math.Round(extrudeMesh.Direction[0], digits); extrudeMesh.Direction[1] = Math.Round(extrudeMesh.Direction[1], digits); extrudeMesh.Direction[2] = Math.Round(extrudeMesh.Direction[2], digits); // extrudeMesh.ExtrudeCenter[0] = Math.Round(extrudeMesh.ExtrudeCenter[0], digits); extrudeMesh.ExtrudeCenter[1] = Math.Round(extrudeMesh.ExtrudeCenter[1], digits); extrudeMesh.ExtrudeCenter[2] = Math.Round(extrudeMesh.ExtrudeCenter[2], digits); // } else error = "The selected surfaces have direction edges pointing in different direction."; } else error = "The selected surfaces have a direction edge that is not a straight line."; } else error = "The selected surfaces have direction edges of different lengths."; } else error = "The selected surfaces are not connected."; } else error = "The surfaces of more than one part are selected."; // return error == null ? null : error + " The extruded mesh cannot be created."; } private string IsSweepMeshProperlyDefined(SweepMesh sweepMesh) { string error = null; sweepMesh.Direction = null; sweepMesh.SweepCenter = null; // if (sweepMesh.ElementSizeType == CaeMesh.Meshing.ElementSizeTypeEnum.MultiLayerd && (sweepMesh.LayerSizes.Length != sweepMesh.NumOfElementsPerLayer.Length)) return "The number of layers must be equal for layer sizes and number of elements per layer."; // int[] selectedPartIds = FeMesh.GetPartIdsFromGeometryIds(sweepMesh.CreationIds); // if (selectedPartIds.Length == 1) { // Get part int partId = selectedPartIds[0]; GeometryPart part = (GeometryPart)_geometry.GetPartFromId(partId); // if (IsPartCompoundSubPart(part.Name)) return "The sweep mesh setup item cannot be defined on a compound part."; if (!part.IsCADPart) return "The sweep mesh setup item cannot be defined on a stl based part."; if (part.PartType != PartType.Solid && part.PartType != PartType.SolidAsShell) return "The sweep mesh setup item cannot be defined on a shell part."; // VisualizationData vis = part.Visualization; // Get surface ids HashSet sourceSurfaceIds = new HashSet(); for (int i = 0; i < sweepMesh.CreationIds.Length; i++) sourceSurfaceIds.Add(FeMesh.GetItemIdFromGeometryId(sweepMesh.CreationIds[i])); // Do selected surfaces form a connected surface Dictionary> surfaceIdSurfaceNeighbourIds = vis.GetSurfaceIdSurfaceNeighbourIds(); if (vis.AreSurfacesConnected(sourceSurfaceIds.ToArray(), surfaceIdSurfaceNeighbourIds)) { // Are there any free edge loops with a single edge - cylinder with a single seam line int singleEdgeLoops = 0; HashSet[] freeEdgeLoops = vis.GetFreeEdgeLoops(sourceSurfaceIds.ToArray()); for (int i = 0; i < freeEdgeLoops.Length; i++) { if (freeEdgeLoops[i].Count == 1) singleEdgeLoops++; } if (singleEdgeLoops == 0) { bool loop = true; HashSet neighbours; HashSet neighbourSurfaceIds; List layerSideSurfaceIds = new List(); HashSet visitedSurfaceIds = new HashSet(sourceSurfaceIds); // Node node; Graph connections; Dictionary> surfaceIdNode; List> surfaceLoops; // while (true) { // New neighbours neighbourSurfaceIds = new HashSet(); // Find next neighbours foreach (var visitedSurfaceId in visitedSurfaceIds) { neighbourSurfaceIds.UnionWith(surfaceIdSurfaceNeighbourIds[visitedSurfaceId]); } neighbourSurfaceIds.ExceptWith(visitedSurfaceIds); // Get neighbours of neighbours neighbours = new HashSet(); foreach (var id in neighbourSurfaceIds) neighbours.UnionWith(surfaceIdSurfaceNeighbourIds[id]); neighbours.ExceptWith(visitedSurfaceIds); // remove visited neighbours.ExceptWith(neighbourSurfaceIds); // remove self // Are neighbours creating a closed surface compound if (neighbours.Count == 0) loop = false; // Check that neighbours form a loop else { // Split surfaces into connected groups connections = new Graph(); surfaceIdNode = new Dictionary>(); // foreach (var neighbourSurfaceId in neighbourSurfaceIds) { node = new Node(neighbourSurfaceId); connections.AddNode(node); surfaceIdNode.Add(neighbourSurfaceId, node); } foreach (var neighbour1Id in neighbourSurfaceIds) { foreach (var neighbour2Id in surfaceIdSurfaceNeighbourIds[neighbour1Id]) { if (neighbourSurfaceIds.Contains(neighbour2Id)) connections.AddUndirectedEdge(surfaceIdNode[neighbour1Id], surfaceIdNode[neighbour2Id]); } } surfaceLoops = connections.GetConnectedSubgraphs(); // if (surfaceLoops.Count() != freeEdgeLoops.Count()) loop = false; else { foreach (var surfaceLoop in surfaceLoops) { // One cylindrical face if (surfaceLoop.Count == 1) loop = false; // Two cylindrical faces else if (surfaceLoop.Count == 2) { foreach (var id in surfaceLoop.GetValues()) { neighbours = surfaceIdSurfaceNeighbourIds[id].Intersect(neighbourSurfaceIds).ToHashSet(); if (neighbours.Count() != 1) { loop = false; break; } } } else { foreach (var id in surfaceLoop.GetValues()) { neighbours = surfaceIdSurfaceNeighbourIds[id].Intersect(neighbourSurfaceIds).ToHashSet(); // if (neighbours.Count() != 2) { loop = false; break; } } } } } } // if (!loop) break; // layerSideSurfaceIds.Add(neighbourSurfaceIds.ToArray()); visitedSurfaceIds.UnionWith(neighbourSurfaceIds); } // int[] targetSurfaceIds = surfaceIdSurfaceNeighbourIds.Keys.Except(visitedSurfaceIds).ToArray(); if (targetSurfaceIds.Length == 1) { int[] sideSurfaceIds = visitedSurfaceIds.Except(sourceSurfaceIds).ToArray(); // if (sideSurfaceIds.Length > 0) { // Are all side surfaces 4-sided bool fourSided = true; foreach (var surfaceId in sideSurfaceIds) { if (vis.FaceEdgeIds[surfaceId].Length != 4 && !vis.IsSurfaceACylinderLike(surfaceId, out _)) { fourSided = false; break; } } // if (fourSided) { Dictionary> vertexIdEdgeId = vis.GetVertexIdEdgeIds(); HashSet surfaceEdgeIds = vis.GetEdgeIdsForSurfaceIds(sourceSurfaceIds.ToArray()); HashSet surfaceVertices = vis.GetVertexNodeIdsForSurfaceIds(sourceSurfaceIds.ToArray()); // HashSet directionEdgeIds = new HashSet(); foreach (var vertexId in surfaceVertices) directionEdgeIds.UnionWith(vertexIdEdgeId[vertexId].Except(surfaceEdgeIds)); // int[] edgeNodes; HashSet nodeIds; Vec3D normalizedDirection; Vec3D averageDirection = new Vec3D(); BoundingBox bb; int edgeCellId; int[] edgeCell; foreach (var directionEdgeId in directionEdgeIds) { // Get all edge node ids nodeIds = vis.GetNodeIdsForEdgeId(directionEdgeId); // Reduce edge node ids to vertices edgeNodes = nodeIds.Intersect(vis.VertexNodeIds).ToArray(); if (edgeNodes.Length != 2) throw new NotSupportedException(); // First node must be on the selected surface if (!surfaceVertices.Contains(edgeNodes[0])) (edgeNodes[0], edgeNodes[1]) = (edgeNodes[1], edgeNodes[0]); // Find the first edge cell for direction for (int i = 0; i < vis.EdgeCellIdsByEdge[directionEdgeId].Length; i++) { edgeCellId = vis.EdgeCellIdsByEdge[directionEdgeId][i]; edgeCell = vis.EdgeCells[edgeCellId]; if (edgeNodes[0] == edgeCell[0]) { edgeNodes[1] = edgeCell[1]; break; } else if (edgeNodes[0] == edgeCell[1]) { edgeNodes[1] = edgeCell[0]; break; } } // Compute the sweep direction normalizedDirection = _geometry.ComputeDirectionFromEdgeCellIndices(edgeNodes, edgeNodes[0]); averageDirection += normalizedDirection; } // averageDirection.Normalize(); sweepMesh.Direction = averageDirection.Coor; // bb = _geometry.GetBoundingBoxForNodeIds(surfaceVertices.ToArray()); sweepMesh.SweepCenter = bb.GetCenter(); // Round double d = part.BoundingBox.GetDiagonal(); int digits = (int)Math.Log10(d) - 6; if (digits > 0) digits = 0; else if (digits < 0) digits *= -1; // sweepMesh.Direction[0] = Math.Round(sweepMesh.Direction[0], digits); sweepMesh.Direction[1] = Math.Round(sweepMesh.Direction[1], digits); sweepMesh.Direction[2] = Math.Round(sweepMesh.Direction[2], digits); // sweepMesh.SweepCenter[0] = Math.Round(sweepMesh.SweepCenter[0], digits); sweepMesh.SweepCenter[1] = Math.Round(sweepMesh.SweepCenter[1], digits); sweepMesh.SweepCenter[2] = Math.Round(sweepMesh.SweepCenter[2], digits); // int[][][] layerGroupEdgeIds = GetDirectionEdges(vis, surfaceIdSurfaceNeighbourIds, sideSurfaceIds, layerSideSurfaceIds); // Gmsh numbering for (int i = 0; i < sideSurfaceIds.Length; i++) { sideSurfaceIds[i] = FeMesh.GmshTopologyId(sideSurfaceIds[i], partId); } sweepMesh.SideSurfaceIds = sideSurfaceIds; // for (int i = 0; i < layerGroupEdgeIds.Length; i++) { for (int j = 0; j < layerGroupEdgeIds[i].Length; j++) { for (int z = 0; z < layerGroupEdgeIds[i][j].Length; z++) { layerGroupEdgeIds[i][j][z] = FeMesh.GmshTopologyId(layerGroupEdgeIds[i][j][z], partId); } } } sweepMesh.LayerGroupEdgeIds = layerGroupEdgeIds; } else error = "The sweep side surfaces are not 4-sided surfaces."; } else error = "The sweep side surfaces do not form a closed loop."; } else error = "There are more than 1 target surfaces."; // Get target surfaces } else error = "The selected surface/s contain free edge loop/s with a single edge (a hole or an extrusion)."; } else error = "The selected surfaces are not connected."; } else error = "The surfaces of more than one part are selected."; // return error == null ? null : error + " The swept mesh cannot be created."; } private string IsRevolveMeshProperlyDefined(RevolveMesh revolveMesh) { string error = null; revolveMesh.AxisDirection = null; revolveMesh.AxisCenter = null; revolveMesh.AngleDeg = -1; revolveMesh.MiddleR = -1; // if (revolveMesh.AlgorithmMesh2D == CaeMesh.Meshing.GmshAlgorithmMesh2DEnum.QuasiStructuredQuad) return "The revolve mesh setup item cannot use the quasi-structured quad algorithm."; // if (revolveMesh.ElementSizeType == CaeMesh.Meshing.ElementSizeTypeEnum.MultiLayerd && (revolveMesh.LayerSizes.Length != revolveMesh.NumOfElementsPerLayer.Length)) return "The number of layers must be equal for layer sizes and number of elements per layer."; // int[] selectedPartIds = FeMesh.GetPartIdsFromGeometryIds(revolveMesh.CreationIds); // if (selectedPartIds.Length == 1) { // Get part int partId = selectedPartIds[0]; GeometryPart part = (GeometryPart)_geometry.GetPartFromId(partId); if (IsPartCompoundSubPart(part.Name)) return "The revolve mesh setup item cannot be defined on a compound part."; if (!part.IsCADPart) return "The revolve mesh setup item cannot be defined on a stl based part."; if (part.PartType != PartType.Solid && part.PartType != PartType.SolidAsShell) return "The revolve mesh setup item cannot be defined on a shell part."; // VisualizationData vis = part.Visualization; // Get surface ids HashSet surfaceIds = new HashSet(); for (int i = 0; i < revolveMesh.CreationIds.Length; i++) surfaceIds.Add(FeMesh.GetItemIdFromGeometryId(revolveMesh.CreationIds[i])); // Do selected surfaces form a connected surface if (vis.AreSurfacesConnected(surfaceIds.ToArray())) { Dictionary> vertexIdEdgeId = vis.GetVertexIdEdgeIds(); HashSet surfaceVertices = vis.GetVertexNodeIdsForSurfaceIds(surfaceIds.ToArray()); HashSet surfaceEdgeIds = vis.GetEdgeIdsForSurfaceIds(surfaceIds.ToArray()); // HashSet directionEdgeIds = new HashSet(); foreach (var vertexId in surfaceVertices) directionEdgeIds.UnionWith(vertexIdEdgeId[vertexId].Except(surfaceEdgeIds)); // bool arcEdges = false; if (vis.EdgeTypes != null) { HashSet edgeTypes = new HashSet(); foreach (var directionEdgeId in directionEdgeIds) edgeTypes.Add(vis.EdgeTypes[directionEdgeId]); // if (edgeTypes.Count() == 1 && edgeTypes.First() == GeomCurveType.Circle) arcEdges = true; } if (!arcEdges) { arcEdges = vis.IsEdgeRadiusConstant(directionEdgeIds, _geometry.Nodes); } if (arcEdges) { double r; double arcAngleDeg; double[] axisCenter; double[] axisDirection; vis.GetArcEdgeDataForEdgeIds(directionEdgeIds, surfaceVertices, _geometry.Nodes, out r, out arcAngleDeg, out axisCenter, out axisDirection); if (r > 0 && arcAngleDeg > 0) { revolveMesh.AxisDirection = axisDirection; revolveMesh.AxisCenter = axisCenter; revolveMesh.AngleDeg = arcAngleDeg; revolveMesh.MiddleR = r; // Round double d = part.BoundingBox.GetDiagonal(); int digits = (int)Math.Log10(d) - 6; if (digits > 0) digits = 0; else if (digits < 0) digits *= -1; // revolveMesh.AxisDirection[0] = Math.Round(revolveMesh.AxisDirection[0], digits); revolveMesh.AxisDirection[1] = Math.Round(revolveMesh.AxisDirection[1], digits); revolveMesh.AxisDirection[2] = Math.Round(revolveMesh.AxisDirection[2], digits); // revolveMesh.AxisCenter[0] = Math.Round(revolveMesh.AxisCenter[0], digits); revolveMesh.AxisCenter[1] = Math.Round(revolveMesh.AxisCenter[1], digits); revolveMesh.AxisCenter[2] = Math.Round(revolveMesh.AxisCenter[2], digits); // revolveMesh.AngleDeg = Math.Round(revolveMesh.AngleDeg, 4); // revolveMesh.MiddleR = Math.Round(revolveMesh.MiddleR, digits); } else error = "The selected surfaces have direction edges with different arc angles or axes."; } else error = "The selected surfaces have direction edges of different arc radii."; } else error = "The selected surfaces are not connected."; } else error = "The surfaces of more than one part are selected."; // return error == null ? null : error + " The revolve mesh cannot be created."; } public bool IsPartCompoundSubPart(string partName) { if (_geometry == null) return false; // foreach (var entry in _geometry.Parts) { if (entry.Value is CompoundGeometryPart cgp) { if (cgp.SubPartNames.Contains(partName)) return true; } } return false; } private int[][][] GetDirectionEdges(VisualizationData vis, Dictionary> surfaceIdSurfaceNeighbourIds, int[] surfaceIds, List layerSurfaceIds) { // Split into groups Node node; Graph connections = new Graph(); Dictionary> surfaceIdNode = new Dictionary>(); // foreach (var surfaceId in surfaceIds) { node = new Node(surfaceId); connections.AddNode(node); surfaceIdNode.Add(surfaceId, node); } HashSet surfaceIdsHash = surfaceIds.ToHashSet(); foreach (var surfaceId in surfaceIds) { foreach (var neighbourId in surfaceIdSurfaceNeighbourIds[surfaceId]) { if (surfaceIdsHash.Contains(neighbourId)) connections.AddUndirectedEdge(surfaceIdNode[surfaceId], surfaceIdNode[neighbourId]); } } List> subGraphs = connections.GetConnectedSubgraphs(); // int count = 0; HashSet[] groupSurfaceId = new HashSet[subGraphs.Count]; foreach (var subGraph in subGraphs) groupSurfaceId[count++] = subGraph.GetValues().ToHashSet(); // Create group mask Dictionary surfaceIdGroupId = new Dictionary(); for (int i = 0; i < groupSurfaceId.Length; i++) { foreach (var surfaceId in groupSurfaceId[i]) { surfaceIdGroupId.Add(surfaceId, i); } } // Create layer mask Dictionary surfaceIdLayerId = new Dictionary(); count = 0; foreach (var layer in layerSurfaceIds) { for (int i = 0; i < layer.Length; i++) { surfaceIdLayerId.Add(layer[i], count); } count++; } // HashSet[][] layerGroupSurfaceIds = new HashSet[layerSurfaceIds.Count][]; for (int i = 0; i < layerGroupSurfaceIds.Length; i++) { layerGroupSurfaceIds[i] = new HashSet[groupSurfaceId.Length]; for (int j = 0; j < layerGroupSurfaceIds[i].Length; j++) layerGroupSurfaceIds[i][j] = new HashSet(); } // int groupId; int layerId; for (int i = 0; i < surfaceIds.Length; i++) { groupId = surfaceIdGroupId[surfaceIds[i]]; layerId = surfaceIdLayerId[surfaceIds[i]]; layerGroupSurfaceIds[layerId][groupId].Add(surfaceIds[i]); } // int[][][] layerGroupEdgeIds = new int[layerSurfaceIds.Count][][]; for (int i = 0; i < layerGroupEdgeIds.Length; i++) { layerGroupEdgeIds[i] = new int[groupSurfaceId.Length][]; for (int j = 0; j < layerGroupEdgeIds[i].Length; j++) layerGroupEdgeIds[i][j] = GetSharedEdgeIds(vis, layerGroupSurfaceIds[i][j]); } // return layerGroupEdgeIds; } private int[] GetSharedEdgeIds(VisualizationData vis, HashSet surfaceIds) { int directionEdgeId; Dictionary edgeIdCount = new Dictionary(); foreach (var surfaceId in surfaceIds) { if (vis.IsSurfaceACylinderLike(surfaceId, out directionEdgeId)) { if (edgeIdCount.ContainsKey(directionEdgeId)) edgeIdCount[directionEdgeId] += 2; else edgeIdCount[directionEdgeId] = 2; } else { foreach (var edgeId in vis.FaceEdgeIds[surfaceId]) { if (edgeIdCount.ContainsKey(edgeId)) edgeIdCount[edgeId]++; else edgeIdCount[edgeId] = 1; } } } List edgeIds = new List(); foreach (var entry in edgeIdCount) { if (entry.Value == 2) edgeIds.Add(entry.Key); } return edgeIds.ToArray(); } // Springs public PointSpringData[] GetPointSpringsFromSurfaceSpring(SurfaceSpring spring) { List springs = new List(); // if (spring.GetSpringDirections().Length != 0) { double area; Dictionary nodalStiffnesses; GetDistributedNodalValuesFromSurface(spring.RegionName, out nodalStiffnesses, out area); // if (spring.StiffnessPerArea) area = 1; // account for the stiffness type // double k1ByArea = spring.K1.Value / area; double k2ByArea = spring.K2.Value / area; double k3ByArea = spring.K3.Value / area; // foreach (var entry in nodalStiffnesses) { if (entry.Value != 0) { springs.Add(new PointSpringData(spring.Name + "_" + entry.Key.ToString(), entry.Key, k1ByArea * entry.Value, k2ByArea * entry.Value, k3ByArea * entry.Value)); } } } // return springs.ToArray(); } // Initial conditions public InitialTemperature[] GetNodalTemperaturesFromVariableInitialTemperature(InitialTemperature initialTemperature) { if (initialTemperature.DistributionName == Distribution.DefaultDistributionName) return null; // Node set FeNodeSet nodeSet; if (initialTemperature.RegionType == RegionTypeEnum.NodeSetName) { nodeSet = _mesh.NodeSets[initialTemperature.RegionName]; } else if (initialTemperature.RegionType == RegionTypeEnum.SurfaceName) { FeSurface surface = _mesh.Surfaces[initialTemperature.RegionName]; nodeSet = _mesh.NodeSets[surface.NodeSetName]; } else throw new NotSupportedException(); // double[][] coor = new double[nodeSet.Labels.Length][]; // Parallel Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; coor[i] = _mesh.Nodes[nodeId].Coor; }); // Temperature double[] temperatures; initialTemperature.GetTemperaturesAndDistancesForPoints(this, coor, out _, out temperatures); // Parallel ConcurrentBag initialTemperatures = new ConcurrentBag(); Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; // Temperature conditions InitialTemperature it = new InitialTemperature("NodeID_" + nodeId.ToString(), nodeId, temperatures[i], true); initialTemperatures.Add(it); }); // return initialTemperatures.ToArray(); } // Boundary conditions public TemperatureBC[] GetNodalTemperaturesFromVariableTemperatureBC(TemperatureBC temperatureBC) { if (temperatureBC.DistributionName == Distribution.DefaultDistributionName) return null; // Node set FeNodeSet nodeSet; if (temperatureBC.RegionType == RegionTypeEnum.NodeSetName) { nodeSet = _mesh.NodeSets[temperatureBC.RegionName]; } else if (temperatureBC.RegionType == RegionTypeEnum.SurfaceName) { FeSurface surface = _mesh.Surfaces[temperatureBC.RegionName]; nodeSet = _mesh.NodeSets[surface.NodeSetName]; } else throw new NotSupportedException(); // double[][] coor = new double[nodeSet.Labels.Length][]; // Parallel Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; coor[i] = _mesh.Nodes[nodeId].Coor; }); // Temperature double[] temperatures; temperatureBC.GetTemperaturesAndDistancesForPoints(this, coor, out _, out temperatures); // Parallel ConcurrentBag temperatureBCs = new ConcurrentBag(); Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; // Temperature bcs TemperatureBC tbc = new TemperatureBC("NodeID_" + nodeId.ToString(), nodeId, temperatures[i], true); tbc.AmplitudeName = temperatureBC.AmplitudeName; temperatureBCs.Add(tbc); }); // return temperatureBCs.ToArray(); } // Loads public double GetAreaForSTLoad(STLoad load) { int sectionId = 0; double A; double thickness; double area = 0; FeElement element; Dictionary elementIdSectionId; Dictionary sectionIdThickness = new Dictionary(); // Get element thicknesses GetSectionAssignments(out elementIdSectionId); foreach (var entry in _sections) { thickness = entry.Value.Thickness.Value; sectionIdThickness.Add(sectionId++, thickness); } // FeSurface surface = _mesh.Surfaces[load.SurfaceName]; if (surface.ElementFaces == null) return 0; // foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; A = element.GetArea(entry.Key, _mesh.Nodes); // Is shell edge face if (element is FeElement2D element2D && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2) { sectionId = elementIdSectionId[elementId]; if (sectionId == -1) throw new CaeException("Missing section assignment at element " + elementId + " from part " + _mesh.GetPartFromId(element.PartId) + "."); thickness = sectionIdThickness[sectionId]; A *= thickness; } area += A; } } return area; } public CLoad[] GetNodalCLoadsFromSurfaceTraction(STLoad load) { if (load.DistributionName == Distribution.DefaultDistributionName) return GetNodalCLoadsFromConstantSurfaceTraction(load); else return GetNodalCLoadsFromSurfaceTractionByDistribution(load); } public CLoad[] GetNodalCLoadsFromConstantSurfaceTraction(STLoad load) { List loads = new List(); // if (load.FMagnitude.Value != 0) { double area; Dictionary nodalForces; GetDistributedNodalValuesFromSurface(load.SurfaceName, out nodalForces, out area); // double f1ByArea = load.F1.Value / area; double f2ByArea = load.F2.Value / area; double f3ByArea = load.F3.Value / area; // CLoad cLoad; double phaseDeg = load.PhaseDeg.Value; foreach (var entry in nodalForces) { if (entry.Value != 0) { cLoad = new CLoad("_CLoad_" + entry.Key.ToString(), entry.Key, f1ByArea * entry.Value, f2ByArea * entry.Value, f3ByArea * entry.Value, load.TwoD, load.Complex, phaseDeg, true); cLoad.AmplitudeName = load.AmplitudeName; loads.Add(cLoad); } } } // return loads.ToArray(); } public CLoad[] GetNodalCLoadsFromSurfaceTractionByDistribution(STLoad load) { Distribution distribution = _distributions[load.DistributionName]; Dictionary elementIdSectionId; double[] sectionIdThickness = new double[_sections.Count]; // Get element thicknesses GetSectionAssignments(out elementIdSectionId); // int sectionId = 0; double thickness; string surfaceName = load.SurfaceName; foreach (var entry in _sections) { thickness = entry.Value.Thickness.Value; sectionIdThickness[sectionId++] = thickness; } // Surface FeSurface surface = _mesh.Surfaces[surfaceName]; if (surface.ElementFaces == null) return null; // int nodeId; int[] nodeIds; double A; double area = 0; double[] magnitude; double[] force; double[] nodalForce; double[] faceNormal; double[][] magnitudeByComponent; double[][] nodalForceMagnitudes; FeElement element; Dictionary nodeIdForce = new Dictionary(); // Collect all node ids - speed up HashSet allNodeIdsHash = new HashSet(); foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; allNodeIdsHash.UnionWith(element.GetNodeIdsFromFaceName(entry.Key)); } } // Collect all points - speed up int[] allNodeIds = allNodeIdsHash.ToArray(); double[][] points = new double[allNodeIds.Length][]; for (int i = 0; i < allNodeIds.Length; i++) { nodeId = allNodeIds[i]; points[i] = _mesh.Nodes[nodeId].Coor; } // Get all nodal values double[][] values; distribution.GetMagnitudesAndDistancesForPoints(this, points, out values, out _); // Get all nodal values as dictionary - speed up Dictionary nodeIdValues = new Dictionary(); for (int i = 0; i < allNodeIds.Length; i++) nodeIdValues.Add(allNodeIds[i], values[i]); // foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; // Node ids nodeIds = element.GetNodeIdsFromFaceName(entry.Key); // _mesh.GetElementFaceCenterAndNormal(elementId, entry.Key, out double[] faceCenter, out faceNormal, out bool shellElement); // A = element.GetArea(entry.Key, _mesh.Nodes); // Account for 2D area when an edge is selected if (element is FeElement2D element2D && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2) { sectionId = elementIdSectionId[elementId]; if (sectionId == -1) throw new CaeException("Missing section assignment at element " + elementId + " from part " + _mesh.GetPartFromId(element.PartId) + "."); thickness = sectionIdThickness[sectionId]; A *= thickness; } // Force magnitude magnitudeByComponent = new double[distribution.NumOfComponents][]; for (int i = 0; i < nodeIds.Length; i++) { nodeId = nodeIds[i]; magnitude = nodeIdValues[nodeId]; // for (int j = 0; j < magnitudeByComponent.Length; j++) { if (magnitudeByComponent[j] == null) magnitudeByComponent[j] = new double[nodeIds.Length]; magnitudeByComponent[j][i] = magnitude[j]; } } // Force magnitudes without area nodalForceMagnitudes = new double[distribution.NumOfComponents][]; for (int i = 0; i < nodalForceMagnitudes.Length; i++) { nodalForceMagnitudes[i] = element.GetEquivalentForcesFromFaceName(entry.Key, magnitudeByComponent[i]); } // Force vectors for (int i = 0; i < nodeIds.Length; i++) { if (distribution.NumOfComponents == 1) { force = new double[] { A * nodalForceMagnitudes[0][i], A * nodalForceMagnitudes[0][i], A * nodalForceMagnitudes[0][i] }; } else if (distribution.NumOfComponents == 3) { force = new double[] { A * nodalForceMagnitudes[0][i], A * nodalForceMagnitudes[1][i], A * nodalForceMagnitudes[2][i] }; } else throw new NotSupportedException(); // if (!nodeIdForce.TryGetValue(nodeIds[i], out nodalForce)) { nodalForce = new double[3]; nodeIdForce.Add(nodeIds[i], nodalForce); } nodalForce[0] += force[0]; nodalForce[1] += force[1]; nodalForce[2] += force[2]; } // area += A; } } // Concentrated loads CLoad cLoad; List loads = new List(); double phaseDeg = load.PhaseDeg.Value; double p1ByArea = load.P1.Value; double p2ByArea = load.P2.Value; double p3ByArea = load.P3.Value; foreach (var entry in nodeIdForce) { if (entry.Value[0] != 0 || entry.Value[1] != 0 || entry.Value[2] != 0) { cLoad = new CLoad("_CLoad_" + entry.Key.ToString(), entry.Key, p1ByArea * entry.Value[0], p2ByArea * entry.Value[1], p3ByArea * entry.Value[2], load.TwoD, load.Complex, phaseDeg, true); // cLoad.AmplitudeName = load.AmplitudeName; // loads.Add(cLoad); } } // return loads.ToArray(); } public void GetDistributedNodalValuesFromSurface(string surfaceName, out Dictionary nodalValues, out double area) { nodalValues = new Dictionary(); area = 0; // int nodeId; int sectionId = 0; int[] nodeIds; double A; double thickness; double[] equValue; FeElement element; Dictionary elementIdSectionId; Dictionary sectionIdThickness = new Dictionary(); // Get element thicknesses GetSectionAssignments(out elementIdSectionId); foreach (var entry in _sections) { thickness = entry.Value.Thickness.Value; sectionIdThickness.Add(sectionId++, thickness); } // FeSurface surface = _mesh.Surfaces[surfaceName]; if (surface.ElementFaces == null) return; // foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; A = element.GetArea(entry.Key, _mesh.Nodes); // Is shell edge face if (element is FeElement2D element2D && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2) { sectionId = elementIdSectionId[elementId]; if (sectionId == -1) throw new CaeException("Missing section assignment at element " + elementId + " from part " + _mesh.GetPartFromId(element.PartId) + "."); thickness = sectionIdThickness[sectionId]; A *= thickness; } area += A; nodeIds = element.GetNodeIdsFromFaceName(entry.Key); equValue = element.GetEquivalentForcesFromFaceName(entry.Key); // for (int i = 0; i < nodeIds.Length; i++) { nodeId = nodeIds[i]; if (nodalValues.ContainsKey(nodeId)) nodalValues[nodeId] += A * equValue[i]; else nodalValues.Add(nodeId, A * equValue[i]); } } } } public CLoad[] GetNodalCLoadsFromImportedSurfaceTraction(ImportedSTLoad load) { Dictionary elementIdSectionId; double[] sectionIdThickness = new double[_sections.Count]; // Get element thicknesses GetSectionAssignments(out elementIdSectionId); // int sectionId = 0; double thickness; string surfaceName = load.SurfaceName; foreach (var entry in _sections) { thickness = entry.Value.Thickness.Value; sectionIdThickness[sectionId++] = thickness; } // Surface FeSurface surface = _mesh.Surfaces[surfaceName]; if (surface.ElementFaces == null) return null; // int nodeId; int[] nodeIds; double A; double[] forcePerArea; double[] force; double[] nodalForce; double[] faceNormal; double[][] forcePerAreaByValueId; double[][] nodalForceMagnitudes; FeElement element; Dictionary nodeIdForcePerArea = new Dictionary(); Dictionary nodeIdForce = new Dictionary(); // foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; // Node ids nodeIds = element.GetNodeIdsFromFaceName(entry.Key); // _mesh.GetElementFaceCenterAndNormal(elementId, entry.Key, out double[] faceCenter, out faceNormal, out bool shellElement); // A = element.GetArea(entry.Key, _mesh.Nodes); // Account for 2D area when an edge is selected if (element is FeElement2D element2D && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2) { sectionId = elementIdSectionId[elementId]; if (sectionId == -1) throw new CaeException("Missing section assignment at element " + elementId + " from part " + _mesh.GetPartFromId(element.PartId) + "."); thickness = sectionIdThickness[sectionId]; A *= thickness; } // Force per area forcePerAreaByValueId = new double[load.Interpolator.NumOfValues][]; for (int i = 0; i < nodeIds.Length; i++) { nodeId = nodeIds[i]; if (!nodeIdForcePerArea.TryGetValue(nodeId, out forcePerArea)) { forcePerArea = load.GetForcePerAreaForPoint(_mesh.Nodes[nodeId].Coor); nodeIdForcePerArea.Add(nodeId, forcePerArea); } for (int j = 0; j < forcePerAreaByValueId.Length; j++) { if (forcePerAreaByValueId[j] == null) forcePerAreaByValueId[j] = new double[nodeIds.Length]; forcePerAreaByValueId[j][i] = forcePerArea[j]; } } // Force magnitudes without area nodalForceMagnitudes = new double[load.Interpolator.NumOfValues][]; for (int i = 0; i < nodalForceMagnitudes.Length; i++) { nodalForceMagnitudes[i] = element.GetEquivalentForcesFromFaceName(entry.Key, forcePerAreaByValueId[i]); } // Force vectors for (int i = 0; i < nodeIds.Length; i++) { force = new double[] { A * nodalForceMagnitudes[0][i], A * nodalForceMagnitudes[1][i], A * nodalForceMagnitudes[2][i] }; // if (!nodeIdForce.TryGetValue(nodeIds[i], out nodalForce)) { nodalForce = new double[3]; nodeIdForce.Add(nodeIds[i], nodalForce); } nodalForce[0] += force[0]; nodalForce[1] += force[1]; nodalForce[2] += force[2]; } } } // Concentrated loads CLoad cLoad; List loads = new List(); double phaseDeg = load.PhaseDeg.Value; foreach (var entry in nodeIdForce) { if (entry.Value[0] != 0 || entry.Value[1] != 0 || entry.Value[2] != 0) { cLoad = new CLoad("_CLoad_" + entry.Key.ToString(), entry.Key, entry.Value[0], entry.Value[1], entry.Value[2], load.TwoD, load.Complex, phaseDeg, true); // cLoad.AmplitudeName = load.AmplitudeName; // loads.Add(cLoad); } } // return loads.ToArray(); } public CLoad[] GetNodalCLoadsFromVariablePressureLoad(VariablePressure load) { Dictionary elementIdSectionId; double[] sectionIdThickness = new double[_sections.Count]; // Get element thicknesses GetSectionAssignments(out elementIdSectionId); // int sectionId = 0; double thickness; string surfaceName = load.SurfaceName; foreach (var entry in _sections) { thickness = entry.Value.Thickness.Value; sectionIdThickness[sectionId++] = thickness; } // Surface FeSurface surface = _mesh.Surfaces[surfaceName]; if (surface.ElementFaces == null) return null; // int nodeId = -1; int[] nodeIds; double A; double sign; double pressure; double[] force; double[] nodalForce; double[] faceNormal; double[] nodalPressures; double[] nodalForceMagnitudes; FeElement element; Dictionary nodeIdPressure = new Dictionary(); Dictionary nodeIdForce = new Dictionary(); // FeFaceName faceName; FeElement expandedElement; int[] expandedNodeIds; Dictionary expandedNodes; // foreach (var entry in surface.ElementFaces) { foreach (var elementId in _mesh.ElementSets[entry.Value].Labels) { element = _mesh.Elements[elementId]; // Node ids nodeIds = element.GetNodeIdsFromFaceName(entry.Key); // _mesh.GetElementFaceCenterAndNormal(elementId, entry.Key, out double[] faceCenter, out faceNormal, out bool shellElement); // if (Properties.ModelSpace == ModelSpaceEnum.Axisymmetric) { GetExpandedAxisymmetricElementFromNodeIds(nodeIds, out expandedElement, out expandedNodes); expandedNodeIds = expandedElement.NodeIds; faceName = FeFaceName.S1; // A = expandedElement.GetArea(faceName, expandedNodes) * 180 / 0.01; // Pressure nodalPressures = new double[expandedNodeIds.Length]; for (int i = 0; i < nodalPressures.Length; i++) { nodeId = expandedNodeIds[i]; pressure = load.GetPressureForPoint(this, expandedNodes[nodeId].Coor); nodalPressures[i] = pressure; } // Force magnitudes without area nodalForceMagnitudes = expandedElement.GetEquivalentForcesFromFaceName(faceName, nodalPressures); // Invert face normal in case of S1 or S2 shell face sign = 1; // Force vectors for (int i = 0; i < expandedNodeIds.Length; i++) { force = new double[] { sign * A * nodalForceMagnitudes[i] * faceNormal[0], sign * A * nodalForceMagnitudes[i] * faceNormal[1], sign * A * nodalForceMagnitudes[i] * faceNormal[2]}; // if (expandedElement.Id == 31) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[1]; } else if (expandedElement.Id == 32) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[0]; } else if (expandedElement.Id == 41) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 4) nodeId = nodeIds[0]; } else if (expandedElement.Id == 61) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 4) nodeId = nodeIds[2]; else if (expandedNodeIds[i] == 5) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 6) nodeId = nodeIds[2]; } else if (expandedElement.Id == 62) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 4) nodeId = nodeIds[2]; else if (expandedNodeIds[i] == 5) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 6) nodeId = nodeIds[2]; } else if (expandedElement.Id == 81) { if (expandedNodeIds[i] == 1) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 2) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 3) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 4) nodeId = nodeIds[0]; else if (expandedNodeIds[i] == 5) nodeId = nodeIds[2]; else if (expandedNodeIds[i] == 6) nodeId = nodeIds[1]; else if (expandedNodeIds[i] == 7) nodeId = nodeIds[2]; else if (expandedNodeIds[i] == 8) nodeId = nodeIds[0]; } // if (!nodeIdForce.TryGetValue(nodeId, out nodalForce)) { nodalForce = new double[3]; nodeIdForce.Add(nodeId, nodalForce); } nodalForce[0] += force[0]; nodalForce[1] += force[1]; nodalForce[2] += force[2]; } } else { A = element.GetArea(entry.Key, _mesh.Nodes); // Account for 2D area when an edge is selected if (element is FeElement2D element2D && entry.Key != FeFaceName.S1 && entry.Key != FeFaceName.S2) { sectionId = elementIdSectionId[elementId]; if (sectionId == -1) throw new CaeException("Missing section assignment at element " + elementId + " from part " + _mesh.GetPartFromId(element.PartId) + "."); thickness = sectionIdThickness[sectionId]; A *= thickness; } // Pressure nodalPressures = new double[nodeIds.Length]; for (int i = 0; i < nodalPressures.Length; i++) { nodeId = nodeIds[i]; if (!nodeIdPressure.TryGetValue(nodeId, out pressure)) { pressure = load.GetPressureForPoint(this, _mesh.Nodes[nodeId].Coor); nodeIdPressure.Add(nodeId, pressure); } nodalPressures[i] = pressure; } // Force magnitudes without area nodalForceMagnitudes = element.GetEquivalentForcesFromFaceName(entry.Key, nodalPressures); // Invert face normal in case of S1 or S2 shell face if (shellElement && (entry.Key == FeFaceName.S1 || entry.Key == FeFaceName.S2)) sign = -1; else sign = 1; // Force vectors for (int i = 0; i < nodeIds.Length; i++) { force = new double[] { sign * A * nodalForceMagnitudes[i] * faceNormal[0], sign * A * nodalForceMagnitudes[i] * faceNormal[1], sign * A * nodalForceMagnitudes[i] * faceNormal[2]}; // if (!nodeIdForce.TryGetValue(nodeIds[i], out nodalForce)) { nodalForce = new double[3]; nodeIdForce.Add(nodeIds[i], nodalForce); } nodalForce[0] += force[0]; nodalForce[1] += force[1]; nodalForce[2] += force[2]; } } } } // Concentrated loads CLoad cLoad; List loads = new List(); double phaseDeg = load.PhaseDeg.Value; foreach (var entry in nodeIdForce) { if (entry.Value[0] != 0 || entry.Value[1] != 0 || entry.Value[2] != 0) { cLoad = new CLoad("_CLoad_" + entry.Key.ToString(), entry.Key, entry.Value[0], entry.Value[1], entry.Value[2], load.TwoD, load.Complex, phaseDeg, true); // cLoad.AmplitudeName = load.AmplitudeName; // loads.Add(cLoad); } } // return loads.ToArray(); } public void GetExpandedAxisymmetricElementFromNodeIds(int[] nodeIds, out FeElement expandedElement, out Dictionary expandedNodes) { expandedElement = null; expandedNodes = new Dictionary(); // Node coor double[][] coor = new double[nodeIds.Length][]; for (int i = 0; i < nodeIds.Length; i++) coor[i] = _mesh.Nodes[nodeIds[i]].Coor; // double cos = Math.Cos(Math.PI / 180 * 0.01); double sin = Math.Sin(Math.PI / 180 * 0.01); // if (nodeIds.Length == 2) { // Triangle if (coor[0][0] == 0) { expandedNodes.Add(1, new FeNode(1, coor[0])); expandedNodes.Add(2, new FeNode(2, coor[1][0] * cos, coor[1][1], coor[1][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[1][0] * cos, coor[1][1], -coor[1][0] * sin)); expandedElement = new LinearTriangleElement(31, new int[] { 1, 2, 3 }); } // Triangle else if (coor[1][0] == 0) { expandedNodes.Add(1, new FeNode(1, coor[1])); expandedNodes.Add(2, new FeNode(2, coor[0][0] * cos, coor[0][1], coor[0][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[0][0] * cos, coor[0][1], -coor[0][0] * sin)); expandedElement = new LinearTriangleElement(32, new int[] { 1, 2, 3 }); } // Quad else { expandedNodes.Add(1, new FeNode(1, coor[0][0] * cos, coor[0][1], coor[0][0] * sin)); expandedNodes.Add(2, new FeNode(2, coor[1][0] * cos, coor[1][1], coor[1][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[1][0] * cos, coor[1][1], -coor[1][0] * sin)); expandedNodes.Add(4, new FeNode(4, coor[0][0] * cos, coor[0][1], -coor[0][0] * sin)); expandedElement = new LinearQuadrilateralElement(41, new int[] { 1, 2, 3, 4 }); } } else if (nodeIds.Length == 3) { // Triangle if (coor[0][0] == 0) { expandedNodes.Add(1, new FeNode(1, coor[0])); expandedNodes.Add(2, new FeNode(2, coor[1][0] * cos, coor[1][1], coor[1][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[1][0] * cos, coor[1][1], -coor[1][0] * sin)); // expandedNodes.Add(4, new FeNode(4, coor[2][0] * cos, coor[2][1], coor[2][0] * sin)); expandedNodes.Add(5, new FeNode(5, coor[1])); expandedNodes.Add(6, new FeNode(6, coor[2][0] * cos, coor[2][1], -coor[2][0] * sin)); // expandedElement = new ParabolicTriangleElement(61, new int[] { 1, 2, 3, 4, 5, 6 }); } // Triangle else if (coor[1][0] == 0) { expandedNodes.Add(1, new FeNode(1, coor[1])); expandedNodes.Add(2, new FeNode(2, coor[0][0] * cos, coor[0][1], coor[0][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[0][0] * cos, coor[0][1], -coor[0][0] * sin)); // expandedNodes.Add(4, new FeNode(4, coor[2][0] * cos, coor[2][1], coor[2][0] * sin)); expandedNodes.Add(5, new FeNode(5, coor[0])); expandedNodes.Add(6, new FeNode(6, coor[2][0] * cos, coor[2][1], -coor[2][0] * sin)); // expandedElement = new ParabolicTriangleElement(62, new int[] { 1, 2, 3, 4, 5, 6 }); } // Quad else { expandedNodes.Add(1, new FeNode(1, coor[0][0] * cos, coor[0][1], coor[0][0] * sin)); expandedNodes.Add(2, new FeNode(2, coor[1][0] * cos, coor[1][1], coor[1][0] * sin)); expandedNodes.Add(3, new FeNode(3, coor[1][0] * cos, coor[1][1], -coor[1][0] * sin)); expandedNodes.Add(4, new FeNode(4, coor[0][0] * cos, coor[0][1], -coor[0][0] * sin)); // expandedNodes.Add(5, new FeNode(5, coor[2][0] * cos, coor[2][1], coor[2][0] * sin)); expandedNodes.Add(6, new FeNode(6, coor[1])); expandedNodes.Add(7, new FeNode(7, coor[2][0] * cos, coor[2][1], -coor[2][0] * sin)); expandedNodes.Add(8, new FeNode(8, coor[0])); // expandedElement = new ParabolicQuadrilateralElement(81, new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }); } } else throw new NotSupportedException(); } public DLoad[] GetElementDLoadsFromVariablePressureLoad(VariablePressure load) { // Surface FeSurface surface = _mesh.Surfaces[load.SurfaceName]; if (surface.ElementFaces == null) return null; // double[][] faceCenters; ConcurrentBag loads = new ConcurrentBag(); // foreach (var entry in surface.ElementFaces) // this are faces S1, S2, ... { // Parallel faceCenters = new double[_mesh.ElementSets[entry.Value].Labels.Length][]; Parallel.For(0, _mesh.ElementSets[entry.Value].Labels.Length, i => //for (int i = 0; i < _mesh.ElementSets[entry.Value].Labels.Length; i++) { int elementId = _mesh.ElementSets[entry.Value].Labels[i]; _mesh.GetElementFaceCenterAndNormal(elementId, entry.Key, out faceCenters[i], out _, out _); } ); // Pressure double[] pressure = load.GetPressuresForPoints(this, faceCenters); // Parallel Parallel.For(0, _mesh.ElementSets[entry.Value].Labels.Length, i => //for (int i = 0; i < _mesh.ElementSets[entry.Value].Labels.Length; i++) { int elementId = _mesh.ElementSets[entry.Value].Labels[i]; // Pressure loads if (pressure[i] != 0) { DLoad dLoad = new DLoad("ElementID_" + elementId.ToString(), elementId, entry.Key, pressure[i], load.TwoD, load.Complex, load.PhaseDeg.Value, true); dLoad.AmplitudeName = load.AmplitudeName; loads.Add(dLoad); } } ); } // return loads.ToArray(); } public InitialTranslationalVelocity[] GetTranslationalVelocities(InitialAngularVelocity initialAngularVelocity, Dictionary referencePointsNodeIds) { Dictionary nodeIdCoor = new Dictionary(); if (initialAngularVelocity.RegionType == RegionTypeEnum.NodeSetName) { FeNodeSet nodeSet = _mesh.NodeSets[initialAngularVelocity.RegionName]; for (int i = 0; i < nodeSet.Labels.Length; i++) { nodeIdCoor[nodeSet.Labels[i]] = _mesh.Nodes[nodeSet.Labels[i]].Coor; } } else if (initialAngularVelocity.RegionType == RegionTypeEnum.SurfaceName) { string nodeSetName = _mesh.Surfaces[initialAngularVelocity.RegionName].NodeSetName; FeNodeSet nodeSet = _mesh.NodeSets[nodeSetName]; for (int i = 0; i < nodeSet.Labels.Length; i++) { nodeIdCoor[nodeSet.Labels[i]] = _mesh.Nodes[nodeSet.Labels[i]].Coor; } } else if (initialAngularVelocity.RegionType == RegionTypeEnum.ReferencePointName) { FeReferencePoint rp = _mesh.ReferencePoints[initialAngularVelocity.RegionName]; nodeIdCoor[referencePointsNodeIds[rp.Name][0]] = rp.Coor(); } // Dictionary nodeIdVelocity; initialAngularVelocity.GetTranslationalVelocities(nodeIdCoor, out nodeIdVelocity); // int count = 0; int nodeId; InitialTranslationalVelocity[] translationalVelocities = new InitialTranslationalVelocity[nodeIdVelocity.Count]; foreach (var entry in nodeIdVelocity) { nodeId = entry.Key; // Is the node is on the axis if (nodeId < 0) { // If the node is a translational node of the reference point, get a rotational node instead foreach (var rpEntry in referencePointsNodeIds) { if (rpEntry.Value[0] == -nodeId) { nodeId = rpEntry.Value[1]; break; } } } // translationalVelocities[count++] = new InitialTranslationalVelocity("_iniTransVel_" + nodeId.ToString(), nodeId, entry.Value[0], entry.Value[1], entry.Value[2], initialAngularVelocity.TwoD, true); } // return translationalVelocities; } // Defined fields public DefinedTemperature[] GetNodalTemperaturesFromVariableDefinedTemperature(DefinedTemperature definedTemperature) { if (definedTemperature.Type == DefinedTemperatureTypeEnum.FromFile) return null; if (definedTemperature.DistributionName == Distribution.DefaultDistributionName) return null; // Node set FeNodeSet nodeSet; if (definedTemperature.RegionType == RegionTypeEnum.NodeSetName) { nodeSet = _mesh.NodeSets[definedTemperature.RegionName]; } else if (definedTemperature.RegionType == RegionTypeEnum.SurfaceName) { FeSurface surface = _mesh.Surfaces[definedTemperature.RegionName]; nodeSet = _mesh.NodeSets[surface.NodeSetName]; } else throw new NotSupportedException(); // double[][] coor = new double[nodeSet.Labels.Length][]; // Parallel Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; coor[i] = _mesh.Nodes[nodeId].Coor; }); // Temperature double[] temperatures; definedTemperature.GetTemperaturesAndDistancesForPoints(this, coor, out _, out temperatures); // Parallel ConcurrentBag definedTemperatures = new ConcurrentBag(); Parallel.For(0, nodeSet.Labels.Length, i => { int nodeId = nodeSet.Labels[i]; // Temperature definitions DefinedTemperature dt = new DefinedTemperature("NodeID_" + nodeId.ToString(), nodeId, temperatures[i], true); dt.AmplitudeName = definedTemperature.AmplitudeName; definedTemperatures.Add(dt); }); // return definedTemperatures.ToArray(); } // Parameters public void UpdateNCalcParameters() { try { MyNCalc.ExistingParameters = new OrderedDictionary("Parameters"); MyNCalc.ExistingParameters.AddRange(GetPropertyParameters()); foreach (var entry in _parameters) MyNCalc.ExistingParameters.Add(entry.Key, entry.Value.Value); } catch { MessageBoxes.ShowError("The parameters could not be evaluated. Check the parameter equations."); } } public Dictionary GetPropertyParameters() { double volume; double area; string prefix = "Geometry"; Dictionary propParameters = new Dictionary(); // Geometry string volumePrefix = prefix + ".Volume"; propParameters.Add(volumePrefix, 0); string areaPrefix = prefix + ".Area"; propParameters.Add(areaPrefix, 0); // volume = 0; area = 0; HashSet compoundSubpartNames = new HashSet(); foreach (var partEntry in _geometry.Parts) { if (partEntry.Value is CompoundGeometryPart cgp) compoundSubpartNames.UnionWith(cgp.SubPartNames); } foreach (var partEntry in _geometry.Parts) { if (partEntry.Value is CompoundGeometryPart cgp) { AddCompoundPartProperties(prefix, cgp, ref propParameters); volume += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Volume"]; area += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Area"]; } else if (!compoundSubpartNames.Contains(partEntry.Value.Name)) { AddNonCompoundPartProperties(prefix, partEntry.Value, ref propParameters); volume += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Volume"]; area += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Area"]; } } propParameters[volumePrefix] = volume; propParameters[areaPrefix] = area; // Mesh prefix = "Mesh"; volumePrefix = prefix + ".Volume"; propParameters.Add(volumePrefix, 0); areaPrefix = prefix + ".Area"; propParameters.Add(areaPrefix, 0); // volume = 0; area = 0; foreach (var partEntry in _mesh.Parts) { AddNonCompoundPartProperties(prefix, partEntry.Value, ref propParameters); volume += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Volume"]; area += (double)propParameters[prefix + "." + partEntry.Value.Name + ".Area"]; } propParameters[volumePrefix] = volume; propParameters[areaPrefix] = area; // return propParameters; } public string[] GetAllParameterNames() { List parameterNames = new List(); parameterNames.AddRange(_parameters.Keys); parameterNames.AddRange(GetPropertyParameters().Keys); return parameterNames.ToArray(); } private void AddCompoundPartProperties(string prefix, CompoundGeometryPart part, ref Dictionary propParameters) { // Geometry prefix += "." + part.Name; string volumePrefix = prefix + ".Volume"; propParameters.Add(volumePrefix, 0); string areaPrefix = prefix + ".Area"; propParameters.Add(areaPrefix, 0); double volume = 0; double area = 0; foreach (var subPartName in part.SubPartNames) { AddNonCompoundPartProperties(prefix, _geometry.Parts[subPartName], ref propParameters); volume += (double)propParameters[prefix + "." + subPartName + ".Volume"]; area += (double)propParameters[prefix + "." + subPartName + ".Area"]; } propParameters[volumePrefix] = volume; propParameters[areaPrefix] = area; } private void AddNonCompoundPartProperties(string prefix, BasePart part, ref Dictionary propParameters) { bool solid = part.PartType == PartType.Solid || part.PartType == PartType.SolidAsShell; if (part is CompoundGeometryPart) throw new NotSupportedException(); else { VisualizationData vis = part.Visualization; prefix += "." + part.Name; // Volume double volume = 0; if (solid) volume = part.MassProperties.Volume; propParameters.Add(prefix + ".Volume", volume); // Area string areaPrefix = prefix + ".Area"; propParameters.Add(areaPrefix, -1); // Surfaces double area = 0; double perimeter; string surfacePrefix; for (int i = 0; i < vis.FaceCount; i++) { surfacePrefix = prefix + ".Surface-" + (i + 1); propParameters.Add(surfacePrefix + ".Area", vis.FaceAreas[i]); area += vis.FaceAreas[i]; perimeter = 0; for (int j = 0; j < vis.FaceEdgeIds[i].Length; j++) perimeter += vis.EdgeLengths[vis.FaceEdgeIds[i][j]]; //propParameters.Add(surfacePrefix + ".Perimeter", perimeter); } // propParameters[areaPrefix] = area; // Edges string edgePrefix; for (int i = 0; i < vis.EdgeCount; i++) { edgePrefix = prefix + ".Edge-" + (i + 1); //propParameters.Add(edgePrefix + ".Length", vis.EdgeLengths[i]); } } } // 3D - 2D public void UpdateMeshPartsElementTypes(bool allowMixedModel) { Dictionary> elementTypeEnums = _properties.ModelSpace.GetAvailableElementTypes(allowMixedModel); if (_mesh != null) _mesh.UpdatePartsElementTypes(elementTypeEnums); } // Boundary displacement method public FeModel PrepareBdmModel(Dictionary deformations) { // Mesh FeModel bdmModel = new FeModel("BDMmodel", _unitSystem); bdmModel.Properties = _properties; bdmModel.SetMesh(_mesh.DeepCopy()); // Materials Material materialElastic = new Material("Elastic"); materialElastic.AddProperty(new Elastic(new double[][] { new double[] { 1000, 0, 0 } })); bdmModel._materials.Add(materialElastic.Name, materialElastic); // Sections Section section; foreach (var entry in _sections) { section = entry.Value.DeepClone(); section.MaterialName = materialElastic.Name; bdmModel.Sections.Add(section.Name, section); } // Constraints Constraint constraint; foreach (var entry in _constraints) { constraint = entry.Value.DeepClone(); bdmModel.Constraints.Add(constraint.Name, constraint); } // Distributions Distribution distribution; foreach (var entry in _distributions) { distribution = entry.Value.DeepClone(); bdmModel.Distributions.Add(distribution.Name, distribution); } // Amplitudes Amplitude amplitude; foreach (var entry in _amplitudes) { amplitude = entry.Value.DeepClone(); bdmModel.Amplitudes.Add(amplitude.Name, amplitude); } // Steps StaticStep staticStep = new StaticStep("Step-1"); bdmModel._stepCollection.AddStep(staticStep, false); BoundaryDisplacementStep boundaryDisplacementStep = _stepCollection.GetBoundaryDisplacementStep(); if (boundaryDisplacementStep == null) throw new CaeException("The boundary displacement step is missing."); // Add existing boundary conditions bool twoD = false; BoundaryCondition bc; foreach (var entry in boundaryDisplacementStep.BoundaryConditions) { bc = entry.Value.DeepClone(); staticStep.AddBoundaryCondition(bc); twoD = bc.TwoD; } // Create BDM boundary conditions string name; double[] xyz; FeNodeSet nodeSet; DisplacementRotation displacementRotation; // if (deformations != null) { foreach (var entry in deformations) { // Node set name = bdmModel.Mesh.NodeSets.GetNextNumberedKey("BDM", "_" + entry.Key); nodeSet = new FeNodeSet(name, new int[] { entry.Key }); bdmModel.Mesh.NodeSets.Add(nodeSet.Name, nodeSet); // Boundary condition xyz = entry.Value; name = staticStep.BoundaryConditions.GetNextNumberedKey("BDM-" + entry.Key); displacementRotation = new DisplacementRotation(name, nodeSet.Name, RegionTypeEnum.NodeSetName, twoD, false, 0); if (xyz[0] != 0) displacementRotation.U1.SetEquationFromValue(xyz[0]); if (xyz[1] != 0) displacementRotation.U2.SetEquationFromValue(xyz[1]); if (xyz[2] != 0) displacementRotation.U3.SetEquationFromValue(xyz[2]); staticStep.AddBoundaryCondition(displacementRotation); } } // return bdmModel; } // ISerialization public void GetObjectData(SerializationInfo info, StreamingContext context) { // Using typeof() works also for null fields info.AddValue("_name", Name, typeof(string)); info.AddValue("_geometry", _geometry, typeof(FeMesh)); info.AddValue("_mesh", _mesh, typeof(FeMesh)); info.AddValue("_parameters", _parameters, typeof(EquationParameterCollection)); info.AddValue("_materials", _materials, typeof(OrderedDictionary)); info.AddValue("_sections", _sections, typeof(OrderedDictionary)); info.AddValue("_constraints", _constraints, typeof(OrderedDictionary)); info.AddValue("_surfaceInteractions", _surfaceInteractions, typeof(OrderedDictionary)); info.AddValue("_contactPairs", _contactPairs, typeof(OrderedDictionary)); info.AddValue("_distributions", _distributions, typeof(OrderedDictionary)); info.AddValue("_amplitudes", _amplitudes, typeof(OrderedDictionary)); info.AddValue("_initialConditions", _initialConditions, typeof(OrderedDictionary)); info.AddValue("_stepCollection", _stepCollection, typeof(StepCollection)); info.AddValue("_calculixUserKeywords", _calculixUserKeywords, typeof(OrderedDictionary)); info.AddValue("_properties", _properties, typeof(ModelProperties)); info.AddValue("_unitSystem", _unitSystem, typeof(UnitSystem)); info.AddValue("_hashName", _hashName, typeof(string)); } } }