freecad-cam/Mod/Fem/femtools/membertools.py
2026-02-01 01:59:24 +01:00

292 lines
13 KiB
Python

# ***************************************************************************
# * Copyright (c) 2017 Markus Hovorka <m.hovorka@live.de> *
# * Copyright (c) 2018 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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)