| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | __title__ = "Analysis Checks" |
| | __author__ = "Przemo Firszt, Bernd Hahnebach" |
| | __url__ = "https://www.freecad.org" |
| |
|
| | |
| | |
| |
|
| | import FreeCAD |
| |
|
| | from FreeCAD import Units |
| |
|
| | from . import femutils |
| | from femsolver.calculix.solver import ANALYSIS_TYPES |
| |
|
| |
|
| | def check_member_for_solver_calculix(analysis, solver, mesh, member): |
| |
|
| | message = "" |
| |
|
| | |
| | if solver.AnalysisType not in ANALYSIS_TYPES: |
| | message += f"Unknown analysis type: {solver.AnalysisType}\n" |
| | if solver.AnalysisType == "frequency": |
| | if not hasattr(solver, "EigenmodeHighLimit"): |
| | message += "Frequency analysis: Solver has no EigenmodeHighLimit.\n" |
| | elif not hasattr(solver, "EigenmodeLowLimit"): |
| | message += "Frequency analysis: Solver has no EigenmodeLowLimit.\n" |
| | elif not hasattr(solver, "EigenmodesCount"): |
| | message += "Frequency analysis: Solver has no EigenmodesCount.\n" |
| | if hasattr(solver, "MaterialNonlinearity") and solver.MaterialNonlinearity == "nonlinear": |
| | if not member.mats_nonlinear: |
| | message += ( |
| | "Solver is set to nonlinear materials, " |
| | "but there is no nonlinear material in the analysis.\n" |
| | ) |
| |
|
| | |
| | if not mesh: |
| | message += "A single mesh object must be defined in the analysis.\n" |
| | if mesh: |
| | if ( |
| | mesh.FemMesh.VolumeCount == 0 |
| | and mesh.FemMesh.FaceCount > 0 |
| | and not member.geos_shellthickness |
| | ): |
| | message += ( |
| | "FEM mesh has no volume elements, " |
| | "either define shell thicknesses or " |
| | "provide a FEM mesh with volume elements.\n" |
| | ) |
| | if ( |
| | mesh.FemMesh.VolumeCount == 0 |
| | and mesh.FemMesh.FaceCount == 0 |
| | and mesh.FemMesh.EdgeCount > 0 |
| | and not member.geos_beamsection |
| | and not member.geos_fluidsection |
| | ): |
| | message += ( |
| | "FEM mesh has no volume and no shell elements, " |
| | "either define a beam/fluid section or provide " |
| | "a FEM mesh with volume elements.\n" |
| | ) |
| | if ( |
| | mesh.FemMesh.VolumeCount == 0 |
| | and mesh.FemMesh.FaceCount == 0 |
| | and mesh.FemMesh.EdgeCount == 0 |
| | ): |
| | message += ( |
| | "FEM mesh has neither volume nor shell or edge elements. " |
| | "Provide a FEM mesh with elements.\n" |
| | ) |
| |
|
| | |
| | if not member.mats_linear: |
| | message += "No material object defined in the analysis.\n" |
| | has_no_references = False |
| | for m in member.mats_linear: |
| | if len(m["Object"].References) == 0: |
| | if has_no_references is True: |
| | message += ( |
| | "More than one material has an empty references list " |
| | "(Only one empty references list is allowed!).\n" |
| | ) |
| | has_no_references = True |
| | mat_ref_shty = "" |
| | for m in member.mats_linear: |
| | ref_shty = femutils.get_refshape_type(m["Object"]) |
| | if ref_shty == "Compound": |
| | ref_shty = "Solid" |
| | if not mat_ref_shty: |
| | mat_ref_shty = ref_shty |
| | if mat_ref_shty and ref_shty and ref_shty != mat_ref_shty: |
| | |
| | |
| | message += ( |
| | "Some material objects do not have the same reference shape type " |
| | "(all material objects must have the same reference shape type, " |
| | "at the moment).\n" |
| | ) |
| | for m in member.mats_linear: |
| | mat_map = m["Object"].Material |
| | mat_obj = m["Object"] |
| | if mat_obj.Category == "Solid": |
| | if "YoungsModulus" in mat_map: |
| | |
| | if not Units.Quantity(mat_map["YoungsModulus"]).Value: |
| | message += "Value of YoungsModulus is set to 0.0.\n" |
| | else: |
| | message += "No YoungsModulus defined for at least one material.\n" |
| | if "PoissonRatio" not in mat_map: |
| | |
| | message += "No PoissonRatio defined for at least one material.\n" |
| | if solver.AnalysisType == "frequency" or member.cons_selfweight: |
| | if "Density" not in mat_map: |
| | message += "No Density defined for at least one material.\n" |
| | if solver.AnalysisType == "thermomech": |
| | if "ThermalConductivity" in mat_map: |
| | if not Units.Quantity(mat_map["ThermalConductivity"]).Value: |
| | message += "Value of ThermalConductivity is set to 0.0.\n" |
| | else: |
| | message += ( |
| | "Thermomechanical analysis: No ThermalConductivity defined " |
| | "for at least one material.\n" |
| | ) |
| | if "ThermalExpansionCoefficient" not in mat_map and mat_obj.Category == "Solid": |
| | message += ( |
| | "Thermomechanical analysis: No ThermalExpansionCoefficient defined " |
| | "for at least one material.\n" |
| | ) |
| | if "SpecificHeat" not in mat_map: |
| | message += ( |
| | "Thermomechanical analysis: No SpecificHeat " |
| | "defined for at least one material.\n" |
| | ) |
| | if femutils.is_of_type(mat_obj, "Fem::MaterialReinforced"): |
| | |
| | |
| | mat_map_m = mat_obj.Material |
| | if "AngleOfFriction" in mat_map_m: |
| | |
| | if not Units.Quantity(mat_map_m["AngleOfFriction"]).Value: |
| | message += ( |
| | "Value of AngleOfFriction is set to 0.0 " |
| | "for the matrix of a reinforced material.\n" |
| | ) |
| | else: |
| | message += ( |
| | "No AngleOfFriction defined for the matrix " |
| | "of at least one reinforced material.\n" |
| | ) |
| | if "CompressiveStrength" in mat_map_m: |
| | |
| | if not Units.Quantity(mat_map_m["CompressiveStrength"]).Value: |
| | message += ( |
| | "Value of CompressiveStrength is set to 0.0 " |
| | "for the matrix of a reinforced material.\n" |
| | ) |
| | else: |
| | message += ( |
| | "No CompressiveStrength defined for the matrix " |
| | "of at least one reinforced material.\n" |
| | ) |
| | mat_map_r = mat_obj.Reinforcement |
| | if "YieldStrength" in mat_map_r: |
| | |
| | if not Units.Quantity(mat_map_r["YieldStrength"]).Value: |
| | message += ( |
| | "Value of YieldStrength is set to 0.0 " |
| | "for the reinforcement of a reinforced material.\n" |
| | ) |
| | else: |
| | message += ( |
| | "No YieldStrength defined for the reinforcement " |
| | "of at least one reinforced material.\n" |
| | ) |
| | if len(member.mats_linear) == 1: |
| | mobj = member.mats_linear[0]["Object"] |
| | if hasattr(mobj, "References") and mobj.References: |
| | FreeCAD.Console.PrintError( |
| | "Only one material object, but this one has a reference shape. " |
| | "The reference shape will be ignored.\n" |
| | ) |
| | for m in member.mats_linear: |
| | has_nonlinear_material = False |
| | for nlm in member.mats_nonlinear: |
| | if nlm["Object"].LinearBaseMaterial == m["Object"]: |
| | if has_nonlinear_material is False: |
| | has_nonlinear_material = True |
| | else: |
| | message += ( |
| | "At least two nonlinear materials use the same linear base material. " |
| | "Only one nonlinear material for each linear material allowed.\n" |
| | ) |
| |
|
| | |
| | |
| | |
| | if solver.AnalysisType == "static": |
| | if not (member.cons_fixed or member.cons_displacement or member.cons_rigidbody): |
| | message += "Static analysis: No mechanical boundary conditions defined.\n" |
| | if solver.AnalysisType == "thermomech": |
| | if not member.cons_initialtemperature: |
| | if not member.geos_fluidsection: |
| | message += "Thermomechanical analysis: No initial temperature defined.\n" |
| |
|
| | |
| | |
| | if member.cons_fixed: |
| | for c in member.cons_fixed: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_displacement: |
| | for di in member.cons_displacement: |
| | if len(di["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_planerotation: |
| | for c in member.cons_planerotation: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_contact: |
| | for c in member.cons_contact: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_tie: |
| | for c in member.cons_tie: |
| | items = 0 |
| | for reference in c["Object"].References: |
| | items += len(reference[1]) |
| | if items != 2: |
| | message += "{} doesn't reference exactly two needed faces.\n".format( |
| | c["Object"].Name |
| | ) |
| | |
| | if member.cons_sectionprint: |
| | for c in member.cons_sectionprint: |
| | items = 0 |
| | for reference in c["Object"].References: |
| | items += len(reference[1]) |
| | if items != 1: |
| | message += "{} doesn't reference exactly one needed face.\n".format( |
| | c["Object"].Name |
| | ) |
| | |
| | if member.cons_transform: |
| | for c in member.cons_transform: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_pressure: |
| | for c in member.cons_pressure: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_force: |
| | for c in member.cons_force: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_temperature: |
| | for c in member.cons_temperature: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| | |
| | if member.cons_heatflux: |
| | for c in member.cons_heatflux: |
| | if len(c["Object"].References) == 0: |
| | message += "{} has empty references.".format(c["Object"].Name) |
| |
|
| | |
| | |
| | if member.geos_beamsection: |
| | if member.geos_shellthickness: |
| | |
| | message += ( |
| | "Beam sections and shell thicknesses in one analysis " |
| | "are not supported at the moment.\n" |
| | ) |
| | if member.geos_fluidsection: |
| | |
| | message += ( |
| | "Beam sections and fluid sections in one analysis " |
| | "are not supported at the moment.\n" |
| | ) |
| | has_no_references = False |
| | for b in member.geos_beamsection: |
| | if len(b["Object"].References) == 0: |
| | if has_no_references is True: |
| | message += ( |
| | "More than one beam section has an empty references " |
| | "list (Only one empty references list is allowed!).\n" |
| | ) |
| | has_no_references = True |
| | if mesh: |
| | if mesh.FemMesh.FaceCount > 0 or mesh.FemMesh.VolumeCount > 0: |
| | message += "Beam sections defined but FEM mesh has volume or shell elements.\n" |
| | if mesh.FemMesh.EdgeCount == 0: |
| | message += "Beam sections defined but FEM mesh has no edge elements.\n" |
| | if not (hasattr(mesh, "Shape") or hasattr(mesh, "Part")): |
| | message += ( |
| | "Mesh without geometry link. " |
| | "The mesh needs to know its geometry for the beam rotations.\n" |
| | ) |
| | if len(member.geos_beamrotation) > 1: |
| | message += "Multiple beam rotations in one analysis are not supported at the moment.\n" |
| | |
| | if member.geos_beamrotation and not member.geos_beamsection: |
| | message += "Beam rotations in the analysis but no beam sections defined.\n" |
| | |
| | if member.geos_shellthickness: |
| | has_no_references = False |
| | for s in member.geos_shellthickness: |
| | if len(s["Object"].References) == 0: |
| | if has_no_references is True: |
| | message += ( |
| | "More than one shell thickness has an empty references " |
| | "list (Only one empty references list is allowed!).\n" |
| | ) |
| | has_no_references = True |
| | if mesh: |
| | if mesh.FemMesh.VolumeCount > 0: |
| | message += "Shell thicknesses defined but FEM mesh has volume elements.\n" |
| | if mesh.FemMesh.FaceCount == 0: |
| | message += "Shell thicknesses defined but FEM mesh has no shell elements.\n" |
| | |
| | if member.geos_fluidsection: |
| | if not member.cons_selfweight: |
| | message += "A fluid network analysis requires self weight constraint to be applied\n" |
| | if solver.AnalysisType != "thermomech": |
| | message += "A fluid network analysis can only be done in a thermomech analysis\n" |
| | has_no_references = False |
| | for f in member.geos_fluidsection: |
| | if len(f["Object"].References) == 0: |
| | if has_no_references is True: |
| | message += ( |
| | "More than one fluid section has an empty references list " |
| | "(Only one empty references list is allowed!).\n" |
| | ) |
| | has_no_references = True |
| | if mesh: |
| | if mesh.FemMesh.FaceCount > 0 or mesh.FemMesh.VolumeCount > 0: |
| | message += "Fluid sections defined but FEM mesh has volume or shell elements.\n" |
| | if mesh.FemMesh.EdgeCount == 0: |
| | message += "Fluid sections defined but FEM mesh has no edge elements.\n" |
| |
|
| | return message |
| |
|
| |
|
| | |
| |
|