# *************************************************************************** # * Copyright (c) 2017 Markus Hovorka * # * Copyright (c) 2018 Bernd Hahnebach * # * * # * This file is part of the FreeCAD CAx development system. * # * * # * 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 * # * * # *************************************************************************** """ Collection of functions for the Fem module. This module contains function for managing a analysis and all the different types of objects it contains, helper for executing a simulation. """ __title__ = "FEM analysis tools" __author__ = "Markus Hovorka, Bernd Hahnebach" __url__ = "https://www.freecad.org" from . import femutils def get_member(analysis, t): """Return list of all members of *analysis* of type *t*. Search *analysis* for members of type *t*. This method checks the custom python typesystem (BaseType class property) used by the Fem module if possible. If the object does not use the python typesystem the usual isDerivedFrom from the C++ dynamic type system is used. :param analysis: only objects part of this analysis are considered :param t: only objects of this type are returned :note: Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the type is just checked for equality. If the type doesn't match ``obj.isDerivedFrom`` is called as usual. See https://forum.freecad.org/viewtopic.php?f=10&t=32625 """ if analysis is None: raise ValueError("Analysis must not be None") matching = [] for m in analysis.Group: # since is _derived_from is used the father could be used # to test too (ex. "Fem::FemMeshObject") if femutils.is_derived_from(m, t) and not ( m.hasExtension("App::SuppressibleExtension") and m.Suppressed ): matching.append(m) return matching def get_single_member(analysis, t): """Return one object of type *t* and part of *analysis*. Search *analysis* for members of type *t* and return the first one that's found. This method checks the custom python typesystem (BaseType class property) used by the Fem module if possible. If the object doesn't use the python typesystem the usual isDerivedFrom from the C++ dynamic type system is used. :param analysis: only objects part of this analysis are considered :param t: only a object of this type is returned :note: Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the type is just checked for equality. If the type doesn't match ``obj.isDerivedFrom`` is called as usual. See https://forum.freecad.org/viewtopic.php?f=10&t=32625 """ objs = get_member(analysis, t) return objs[0] if objs else None def get_several_member(analysis, t): """Get members and pack them for Calculix/Z88. Collect members by calling :py:func:`get_member` and pack them into a data structure that can be consumed by calculix and Z88 solver modules. :param analysis: see :py:func:`get_member` :param t: see :py:func:`get_member` :returns: A list containing one dict per member. Each dict has two entries: ``"Object"`` and ``"RefShapeType"``. ``dict["Object"]`` contains the member document object. ``dict["RefShapeType"]`` contains the shape type of the *References* property of the member (used by constraints) as a string ("Vertex", "Edge", "Face" or "Solid"). If the member doesn't have a *References* property ``dict["RefShapeType"]`` is the empty string ``""``. :note: Undefined behaviour if one of the members has a *References* property which is empty. :note: Undefined behaviour if the type of the references of one object are not all the same. :note: Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the type is just checked for equality. If the type doesn't match ``obj.isDerivedFrom`` is called as usual. See https://forum.freecad.org/viewtopic.php?f=10&t=32625 """ # if no member is found, an empty list is returned objs = get_member(analysis, t) members = [] for m in objs: obj_dict = {} obj_dict["Object"] = m obj_dict["RefShapeType"] = femutils.get_refshape_type(m) members.append(obj_dict) return members def get_mesh_to_solve(analysis): """Find one and only mesh object of *analysis*. :returns: A tuple ``(object, message)``. If and only if the analysis contains exactly one mesh object the first value of the tuple is the mesh document object. Otherwise the first value is ``None`` and the second value is a error message indicating what went wrong. """ mesh_to_solve = None for m in analysis.Group: if ( m.isDerivedFrom("Fem::FemMeshObject") # the next line should not be needed as the result mesh is not a analysis member and not femutils.is_of_type(m, "Fem::MeshResult") ): if not mesh_to_solve: mesh_to_solve = m else: return (None, "FEM: multiple mesh in analysis not yet supported!") if mesh_to_solve is not None: return (mesh_to_solve, "") else: return (None, "FEM: no mesh object found in analysis.") class AnalysisMember: def __init__(self, analysis): self.analysis = analysis """ # members of the analysis. All except solvers and the mesh materials: materials_linear : list of dictionaries list of nonlinear materials from the analysis. [{"Object":materials_linear}, {}, ...] materials_nonlinear : list of dictionaries list of nonlinear materials from the analysis. [{"Object":materials_nonlinear}, {}, ...] geometries: beam_sections : list of dictionaries list of beam sections from the analysis. [{"Object":beam_section_obj, "xxxxxxxx":value}, {}, ...] beam_rotations : list of dictionaries list of beam rotations from the analysis. [{"Object":beam_rotation_obj, "xxxxxxxx":value}, {}, ...] fluid_sections : list of dictionaries list of fluid sections from the analysis. [{"Object":fluid_section_obj, "xxxxxxxx":value}, {}, ...] shell_thicknesses : list of dictionaries list of shell thicknesses from the analysis. [{"Object":shell_thickness_obj, "xxxxxxxx":value}, {}, ...] constraints: constraints_centrif : list of dictionaries list of centrifs for the analysis. [{"Object":centrif_obj, "xxxxxxxx":value}, {}, ...] constraints_contact : list of dictionaries list of contact constraints from the analysis. [{"Object":contact_obj, "xxxxxxxx":value}, {}, ...] constraints_displacement : list of dictionaries list of displacements for the analysis. [{"Object":displacement_obj, "xxxxxxxx":value}, {}, ...] constraints_fixed : list of dictionaries list of fixed constraints from the analysis. [{"Object":fixed_obj, "NodeSupports":bool}, {}, ...] constraints_rigidbody : list of dictionaries list of displacements for the analysis. [{"Object":rigidbody_obj, "xxxxxxxx":value}, {}, ...] constraints_force : list of dictionaries list of force constraints from the analysis. [{"Object":force_obj, "NodeLoad":value}, {}, ... constraints_heatflux : list of dictionaries list of heatflux constraints for the analysis. [{"Object":heatflux_obj, "xxxxxxxx":value}, {}, ...] constraints_initialtemperature : list of dictionaries list of initial temperatures for the analysis. [{"Object":initialtemperature_obj, "xxxxxxxx":value}, {}, ...] constraints_planerotation : list of dictionaries list of plane rotation constraints from the analysis. [{"Object":planerotation_obj, "xxxxxxxx":value}, {}, ...] constraints_pressure : list of dictionaries list of pressure constraints from the analysis. [{"Object":pressure_obj, "xxxxxxxx":value}, {}, ...] constraints_sectionprint : list of dictionaries list of sectionprints for the analysis. [{"Object":sectionprint_obj, "xxxxxxxx":value}, {}, ...] constraints_selfweight : list of dictionaries list of selfweight constraints from the analysis. [{"Object":selfweight_obj, "xxxxxxxx":value}, {}, ...] constraints_temperature : list of dictionaries list of temperatures for the analysis. [{"Object":temperature_obj, "xxxxxxxx":value}, {}, ...] constraints_tie : list of dictionaries list of ties for the analysis. [{"Object":tie_obj, "xxxxxxxx":value}, {}, ...] constraints_transform : list of dictionaries list of transform constraints from the analysis. [{"Object":transform_obj, "xxxxxxxx":value}, {}, ...] """ # get member # constants self.cota_vacuumpermittivity = self.get_several_member("Fem::ConstantVacuumPermittivity") # materials std_mats = self.get_several_member("Fem::MaterialCommon") rei_mats = self.get_several_member("Fem::MaterialReinforced") self.mats_linear = std_mats + rei_mats self.mats_nonlinear = self.get_several_member("Fem::MaterialMechanicalNonlinear") # geometries self.geos_beamsection = self.get_several_member("Fem::ElementGeometry1D") self.geos_beamrotation = self.get_several_member("Fem::ElementRotation1D") self.geos_fluidsection = self.get_several_member("Fem::ElementFluid1D") self.geos_shellthickness = self.get_several_member("Fem::ElementGeometry2D") # constraints self.cons_centrif = self.get_several_member("Fem::ConstraintCentrif") self.cons_bodyheatsource = self.get_several_member("Fem::ConstraintBodyHeatSource") self.cons_contact = self.get_several_member("Fem::ConstraintContact") self.cons_displacement = self.get_several_member("Fem::ConstraintDisplacement") self.cons_fixed = self.get_several_member("Fem::ConstraintFixed") self.cons_rigidbody = self.get_several_member("Fem::ConstraintRigidBody") self.cons_rigidbody_step = self.get_several_member("Fem::ConstraintRigidBody") self.cons_force = self.get_several_member("Fem::ConstraintForce") self.cons_heatflux = self.get_several_member("Fem::ConstraintHeatflux") self.cons_initialtemperature = self.get_several_member("Fem::ConstraintInitialTemperature") self.cons_planerotation = self.get_several_member("Fem::ConstraintPlaneRotation") self.cons_pressure = self.get_several_member("Fem::ConstraintPressure") self.cons_sectionprint = self.get_several_member("Fem::ConstraintSectionPrint") self.cons_selfweight = self.get_several_member("Fem::ConstraintSelfWeight") self.cons_temperature = self.get_several_member("Fem::ConstraintTemperature") self.cons_tie = self.get_several_member("Fem::ConstraintTie") self.cons_transform = self.get_several_member("Fem::ConstraintTransform") def get_several_member(self, t): return get_several_member(self.analysis, t)