diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 76003ccfbe..f500c70ca6 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -1,4 +1,4 @@ - + if(BUILD_FEM_VTK) add_definitions(-DFC_USE_VTK) endif(BUILD_FEM_VTK) @@ -221,6 +221,7 @@ SET(FemTools_SRCS femtools/__init__.py femtools/membertools.py femtools/ccxtools.py + femtools/checksanalysis.py femtools/constants.py femtools/errors.py femtools/femutils.py diff --git a/src/Mod/Fem/femtools/ccxtools.py b/src/Mod/Fem/femtools/ccxtools.py index 57e04be6a3..e46965b65c 100644 --- a/src/Mod/Fem/femtools/ccxtools.py +++ b/src/Mod/Fem/femtools/ccxtools.py @@ -34,7 +34,6 @@ import subprocess import FreeCAD -from femsolver.calculix.solver import ANALYSIS_TYPES from femtools import femutils from femtools import membertools @@ -232,348 +231,27 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject): def check_prerequisites(self): FreeCAD.Console.PrintMessage("Check prerequisites.\n") - from FreeCAD import Units message = "" # analysis if not self.analysis: message += "No active Analysis\n" - if not self.working_dir: - message += "Working directory not set\n" - if not (os.path.isdir(self.working_dir)): - message += ( - "Working directory \'{}\' doesn't exist." - .format(self.working_dir) - ) # solver if not self.solver: message += "No solver object defined in the analysis\n" - else: - if self.solver.AnalysisType not in ANALYSIS_TYPES: - message += ( - "Unknown analysis type: {}\n" - .format(self.solver.AnalysisType) - ) - if self.solver.AnalysisType == "frequency": - if not hasattr(self.solver, "EigenmodeHighLimit"): - message += "Frequency analysis: Solver has no EigenmodeHighLimit.\n" - elif not hasattr(self.solver, "EigenmodeLowLimit"): - message += "Frequency analysis: Solver has no EigenmodeLowLimit.\n" - elif not hasattr(self.solver, "EigenmodesCount"): - message += "Frequency analysis: Solver has no EigenmodesCount.\n" - if hasattr(self.solver, "MaterialNonlinearity") \ - and self.solver.MaterialNonlinearity == "nonlinear": - if not self.member.mats_nonlinear: - message += ( - "Solver is set to nonlinear materials, " - "but there is no nonlinear material in the analysis.\n" - ) - if self.solver.Proxy.Type == "Fem::FemSolverCalculixCcxTools" \ - and self.solver.GeometricalNonlinearity != "nonlinear": - # nonlinear geometry --> should be set - # https://forum.freecadweb.org/viewtopic.php?f=18&t=23101&p=180489#p180489 - message += ( - "Solver CalculiX triggers nonlinear geometry for nonlinear material, " - "thus it should to be set too.\n" - ) - # mesh - if not self.mesh: - message += "No mesh object defined in the analysis\n" - if self.mesh: - if self.mesh.FemMesh.VolumeCount == 0 \ - and self.mesh.FemMesh.FaceCount > 0 \ - and not self.member.geos_shellthickness: - message += ( - "FEM mesh has no volume elements, " - "either define a shell thicknesses or " - "provide a FEM mesh with volume elements.\n" - ) - if self.mesh.FemMesh.VolumeCount == 0 \ - and self.mesh.FemMesh.FaceCount == 0 \ - and self.mesh.FemMesh.EdgeCount > 0 \ - and not self.member.geos_beamsection \ - and not self.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 self.mesh.FemMesh.VolumeCount == 0 \ - and self.mesh.FemMesh.FaceCount == 0 \ - and self.mesh.FemMesh.EdgeCount == 0: - message += ( - "FEM mesh has neither volume nor shell or edge elements. " - "Provide a FEM mesh with elements!\n" - ) - # material linear and nonlinear - if not self.member.mats_linear: - message += "No material object defined in the analysis\n" - has_no_references = False - for m in self.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 self.member.mats_linear: - ref_shty = femutils.get_refshape_type(m["Object"]) - if not mat_ref_shty: - mat_ref_shty = ref_shty - if mat_ref_shty and ref_shty and ref_shty != mat_ref_shty: - # mat_ref_shty could be empty in one material - # only the not empty ones should have the same shape type - 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 self.member.mats_linear: - mat_map = m["Object"].Material - mat_obj = m["Object"] - if mat_obj.Category == "Solid": - if "YoungsModulus" in mat_map: - # print(Units.Quantity(mat_map["YoungsModulus"]).Value) - 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: - # PoissonRatio is allowed to be 0.0 (in ccx), but it should be set anyway. - message += "No PoissonRatio defined for at least one material.\n" - if self.solver.AnalysisType == "frequency" or self.member.cons_selfweight: - if "Density" not in mat_map: - message += "No Density defined for at least one material.\n" - if self.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" # allowed to be 0.0 (in ccx) - ) - if "SpecificHeat" not in mat_map: - message += ( - "Thermomechanical analysis: No SpecificHeat " - "defined for at least one material.\n" # allowed to be 0.0 (in ccx) - ) - if femutils.is_of_type(mat_obj, "Fem::MaterialReinforced"): - # additional tests for reinforced materials, - # they are needed for result calculation not for ccx analysis - mat_map_m = mat_obj.Material - if "AngleOfFriction" in mat_map_m: - # print(Units.Quantity(mat_map_m["AngleOfFriction"]).Value) - 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: - # print(Units.Quantity(mat_map_m["CompressiveStrength"]).Value) - 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 matrinx " - "of at least one reinforced material.\n" - ) - mat_map_r = mat_obj.Reinforcement - if "YieldStrength" in mat_map_r: - # print(Units.Quantity(mat_map_r["YieldStrength"]).Value) - 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(self.member.mats_linear) == 1: - mobj = self.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 self.member.mats_linear: - has_nonlinear_material = False - for nlm in self.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" - ) - # which analysis needs which constraints - # no check in the regard of loads existence (constraint force, pressure, self weight) - # is done, because an analysis without loads at all is an valid analysis too - if self.solver.AnalysisType == "static": - if not (self.member.cons_fixed or self.member.cons_displacement): - message += ( - "Static analysis: Neither constraint fixed nor " - "constraint displacement defined.\n" - ) - if self.solver.AnalysisType == "thermomech": - if not self.member.cons_initialtemperature: - if not self.member.geos_fluidsection: - message += "Thermomechanical analysis: No initial temperature defined.\n" - if len(self.member.cons_initialtemperature) > 1: - message += "Thermomechanical analysis: Only one initial temperature is allowed.\n" - # constraints - # fixed - if self.member.cons_fixed: - for c in self.member.cons_fixed: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # displacement - if self.member.cons_displacement: - for di in self.member.cons_displacement: - if len(di["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # plane rotation - if self.member.cons_planerotation: - for c in self.member.cons_planerotation: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # contact - if self.member.cons_contact: - for c in self.member.cons_contact: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # tie - if self.member.cons_tie: - for c in self.member.cons_tie: - items = 0 - for reference in c["Object"].References: - items += len(reference[1]) - if items != 2: - message += ( - "{} doesn't references exactly two needed faces.\n" - .format(c["Object"].Name) - ) - # transform - if self.member.cons_transform: - for c in self.member.cons_transform: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # pressure - if self.member.cons_pressure: - for c in self.member.cons_pressure: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # force - if self.member.cons_force: - for c in self.member.cons_force: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # temperature - if self.member.cons_temperature: - for c in self.member.cons_temperature: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # heat flux - if self.member.cons_heatflux: - for c in self.member.cons_heatflux: - if len(c["Object"].References) == 0: - message += "{} has empty references.".format(c["Object"].Name) - # beam section - if self.member.geos_beamsection: - if self.member.geos_shellthickness: - # this needs to be checked only once either here or in shell_thicknesses - message += ( - "Beam sections and shell thicknesses in one analysis " - "is not supported at the moment.\n" - ) - if self.member.geos_fluidsection: - # this needs to be checked only once either here or in shell_thicknesses - message += ( - "Beam sections and fluid sections in one analysis " - "is not supported at the moment.\n" - ) - has_no_references = False - for b in self.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 self.mesh: - if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0: - message += ( - "Beam sections defined but FEM mesh has volume or shell elements.\n" - ) - if self.mesh.FemMesh.EdgeCount == 0: - message += ( - "Beam sections defined but FEM mesh has no edge elements.\n" - ) - if len(self.member.geos_beamrotation) > 1: - message += ( - "Multiple beam rotations in one analysis are not supported at the moment.\n" - ) - # beam rotations - if self.member.geos_beamrotation and not self.member.geos_beamsection: - message += "Beam rotations in the analysis but no beam sections defined.\n" - # shell thickness - if self.member.geos_shellthickness: - has_no_references = False - for s in self.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 self.mesh: - if self.mesh.FemMesh.VolumeCount > 0: - message += "Shell thicknesses defined but FEM mesh has volume elements.\n" - if self.mesh.FemMesh.FaceCount == 0: - message += "Shell thicknesses defined but FEM mesh has no shell elements.\n" - # fluid section - if self.member.geos_fluidsection: - if not self.member.cons_selfweight: - message += ( - "A fluid network analysis requires self weight constraint to be applied\n" - ) - if self.solver.AnalysisType != "thermomech": - message += "A fluid network analysis can only be done in a thermomech analysis\n" - has_no_references = False - for f in self.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 self.mesh: - if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0: - message += ( - "Fluid sections defined but FEM mesh has volume or shell elements.\n" - ) - if self.mesh.FemMesh.EdgeCount == 0: - message += "Fluid sections defined but FEM mesh has no edge elements.\n" + if not self.working_dir: + message += "Working directory not set\n" + if not (os.path.isdir(self.working_dir)): + message += ( + "Working directory \'{}\' doesn't exist." + .format(self.working_dir) + ) + from femtools.checksanalysis import check_analysismember + message += check_analysismember( + self.analysis, + self.solver, + self.mesh, + self.member + ) return message def set_base_name(self, base_name=None): diff --git a/src/Mod/Fem/femtools/checksanalysis.py b/src/Mod/Fem/femtools/checksanalysis.py new file mode 100644 index 0000000000..39e6af161f --- /dev/null +++ b/src/Mod/Fem/femtools/checksanalysis.py @@ -0,0 +1,378 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2020 Przemo Firszt * +# * Copyright (c) 2020 Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "Analysis Checks" +__author__ = "Przemo Firszt, Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## \addtogroup FEM +# @{ + +import FreeCAD + +from . import femutils +from femsolver.calculix.solver import ANALYSIS_TYPES + + +def check_analysismember(analysis, solver, mesh, member): + FreeCAD.Console.PrintMessage("Check prerequisites.\n") + from FreeCAD import Units + message = "" + + # solver + if solver.AnalysisType not in ANALYSIS_TYPES: + message += ( + "Unknown analysis type: {}\n" + .format(solver.AnalysisType) + ) + 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 solver.Proxy.Type == "Fem::FemSolverCalculixCcxTools" \ + and solver.GeometricalNonlinearity != "nonlinear": + # nonlinear geometry --> should be set + # https://forum.freecadweb.org/viewtopic.php?f=18&t=23101&p=180489#p180489 + message += ( + "Solver CalculiX triggers nonlinear geometry for nonlinear material, " + "thus it should to be set too.\n" + ) + + # mesh + if not mesh: + message += "No mesh object 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 a 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" + ) + + # material linear and nonlinear + 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 not mat_ref_shty: + mat_ref_shty = ref_shty + if mat_ref_shty and ref_shty and ref_shty != mat_ref_shty: + # mat_ref_shty could be empty in one material + # only the not empty ones should have the same shape type + 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: + # print(Units.Quantity(mat_map["YoungsModulus"]).Value) + 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: + # PoissonRatio is allowed to be 0.0 (in ccx), but it should be set anyway. + 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" # allowed to be 0.0 (in ccx) + ) + if "SpecificHeat" not in mat_map: + message += ( + "Thermomechanical analysis: No SpecificHeat " + "defined for at least one material.\n" # allowed to be 0.0 (in ccx) + ) + if femutils.is_of_type(mat_obj, "Fem::MaterialReinforced"): + # additional tests for reinforced materials, + # they are needed for result calculation not for ccx analysis + mat_map_m = mat_obj.Material + if "AngleOfFriction" in mat_map_m: + # print(Units.Quantity(mat_map_m["AngleOfFriction"]).Value) + 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: + # print(Units.Quantity(mat_map_m["CompressiveStrength"]).Value) + 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 matrinx " + "of at least one reinforced material.\n" + ) + mat_map_r = mat_obj.Reinforcement + if "YieldStrength" in mat_map_r: + # print(Units.Quantity(mat_map_r["YieldStrength"]).Value) + 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" + ) + + # which analysis needs which constraints + # no check in the regard of loads existence (constraint force, pressure, self weight) + # is done, because an analysis without loads at all is an valid analysis too + if solver.AnalysisType == "static": + if not (member.cons_fixed or member.cons_displacement): + message += ( + "Static analysis: Neither constraint fixed nor " + "constraint displacement 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 len(member.cons_initialtemperature) > 1: + message += "Thermomechanical analysis: Only one initial temperature is allowed.\n" + + # constraints + # fixed + if member.cons_fixed: + for c in member.cons_fixed: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # displacement + if member.cons_displacement: + for di in member.cons_displacement: + if len(di["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # plane rotation + if member.cons_planerotation: + for c in member.cons_planerotation: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # contact + if member.cons_contact: + for c in member.cons_contact: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # tie + 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 references exactly two needed faces.\n" + .format(c["Object"].Name) + ) + # transform + if member.cons_transform: + for c in member.cons_transform: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # pressure + if member.cons_pressure: + for c in member.cons_pressure: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # force + if member.cons_force: + for c in member.cons_force: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # temperature + if member.cons_temperature: + for c in member.cons_temperature: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + # heat flux + if member.cons_heatflux: + for c in member.cons_heatflux: + if len(c["Object"].References) == 0: + message += "{} has empty references.".format(c["Object"].Name) + + # geometries + # beam section + if member.geos_beamsection: + if member.geos_shellthickness: + # this needs to be checked only once either here or in shell_thicknesses + message += ( + "Beam sections and shell thicknesses in one analysis " + "is not supported at the moment.\n" + ) + if member.geos_fluidsection: + # this needs to be checked only once either here or in shell_thicknesses + message += ( + "Beam sections and fluid sections in one analysis " + "is 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 len(member.geos_beamrotation) > 1: + message += ( + "Multiple beam rotations in one analysis are not supported at the moment.\n" + ) + # beam rotations + if member.geos_beamrotation and not member.geos_beamsection: + message += "Beam rotations in the analysis but no beam sections defined.\n" + # shell thickness + 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" + # fluid section + 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 + +## @}