FEM: Add documentation to femutils module
This commit is contained in:
committed by
Bernd Hahnebach
parent
8b9dfab46d
commit
9c728a03cc
@@ -20,6 +20,13 @@
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
""" Collection of functions for the Fem module.
|
||||
|
||||
This module contains function for managing a analysis and all the differnet
|
||||
types of objects it contains, helper for executing a simulation, function for
|
||||
extracting relevant parts of geometry and a few unrelated function useful at
|
||||
various places in the Fem module.
|
||||
"""
|
||||
|
||||
|
||||
__title__ = "FEM Utilities"
|
||||
@@ -38,8 +45,23 @@ if FreeCAD.GuiUp:
|
||||
from PySide import QtGui
|
||||
|
||||
|
||||
# analysis and its members
|
||||
def createObject(doc, name, proxy, viewProxy):
|
||||
""" Add python object to document using python type string.
|
||||
|
||||
Add a document object suitable for the *proxy* and the *viewProxy* to *doc*
|
||||
and attach it to the *proxy* and the *viewProxy*. This function can only be
|
||||
used with python proxies that specify their C++ type via the BaseType class
|
||||
member (e.g. Cube.BaseType). If there already exists a object with *name* a
|
||||
suitable unique name is generated. To auto generate a name pass ``""``.
|
||||
|
||||
:param doc: document object to which the object is added
|
||||
:param name: string of the name of new object in *doc*, use
|
||||
``""`` to generate a name
|
||||
:param proxy: python proxy for new object
|
||||
:param viewProxy: view proxy for new object
|
||||
|
||||
:returns: reference to new object
|
||||
"""
|
||||
obj = doc.addObject(proxy.BaseType, name)
|
||||
proxy(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -48,6 +70,14 @@ def createObject(doc, name, proxy, viewProxy):
|
||||
|
||||
|
||||
def findAnalysisOfMember(member):
|
||||
""" Find Analysis the *member* belongs to.
|
||||
|
||||
:param member: a document object
|
||||
|
||||
:returns:
|
||||
If a analysis that contains *member* can be found a reference is returned.
|
||||
If no such object exists in the document of *member*, ``None`` is returned.
|
||||
"""
|
||||
if member is None:
|
||||
raise ValueError("Member must not be None")
|
||||
for obj in member.Document.Objects:
|
||||
@@ -69,6 +99,22 @@ def _searchGroups(member, objs):
|
||||
|
||||
|
||||
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 typesytem (BaseType class property) used by the Fem module if
|
||||
possible. If the object doens'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 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.freecadweb.org/viewtopic.php?f=10&t=32625
|
||||
"""
|
||||
if analysis is None:
|
||||
raise ValueError("Analysis must not be None")
|
||||
matching = []
|
||||
@@ -81,12 +127,58 @@ def get_member(analysis, t):
|
||||
|
||||
|
||||
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 typesytem (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.freecadweb.org/viewtopic.php?f=10&t=32625
|
||||
"""
|
||||
objs = get_member(analysis, t)
|
||||
return objs[0] if objs else None
|
||||
|
||||
|
||||
# collect analysis members used in CalculiX and Z88
|
||||
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 arn't 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.freecadweb.org/viewtopic.php?f=10&t=32625
|
||||
"""
|
||||
# if no member is found, an empty list is returned
|
||||
objs = get_member(analysis, t)
|
||||
members = []
|
||||
@@ -99,6 +191,14 @@ def get_several_member(analysis, t):
|
||||
|
||||
|
||||
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
|
||||
exactely 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") and not is_of_type(m, "Fem::FemMeshResult"):
|
||||
@@ -114,27 +214,46 @@ def get_mesh_to_solve(analysis):
|
||||
|
||||
# typeID and object type defs
|
||||
def type_of_obj(obj):
|
||||
"""returns objects TypeId (C++ objects) or Proxy.Type (Python objects)"""
|
||||
""" Return type of *obj* honoring the special typesystem of Fem.
|
||||
|
||||
Python objects of the Fem workbench define their type via a class member
|
||||
``<Class>.Type``. Return this type if the property exists. If not return
|
||||
the conventional ``TypeId`` value.
|
||||
|
||||
:para obj: a document object
|
||||
"""
|
||||
if hasattr(obj, "Proxy") and hasattr(obj.Proxy, "Type"):
|
||||
return obj.Proxy.Type
|
||||
return obj.TypeId
|
||||
|
||||
|
||||
def is_of_type(obj, ty):
|
||||
"""returns True if an object is of
|
||||
a given TypeId (C++ objects) or Proxy.Type (Python Features)"""
|
||||
# only returns true if the exact TypeId is given.
|
||||
# For FeaturPythons the Proxy.Type has to be given.
|
||||
# Keep in mind the TypeId for them is the TypeId from the C++ father class
|
||||
""" Compare type of *obj* with *ty* honoring Fems typesystem.
|
||||
|
||||
See :py:func:`type_of_obj` for more info about the special typesystem of
|
||||
the Fem module.
|
||||
|
||||
:returns:
|
||||
``True`` if *obj* is of type *ty*, ``False`` otherwise. Type must match
|
||||
exactely: Derived objects are not considered to be of type of one of their
|
||||
super classes.
|
||||
"""
|
||||
return type_of_obj(obj) == ty
|
||||
|
||||
|
||||
def is_derived_from(obj, t):
|
||||
"""returns True if an object or its inheritance chain is of a
|
||||
given TypeId (C++ objects) or Proxy.Type (Python objects)"""
|
||||
# returns true for all FEM objects if given t == "App::DocumentObject"
|
||||
# since this is a father of the given object
|
||||
# see https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
|
||||
""" Check if *obj* is derived from *t* honoring Fems typesytem.
|
||||
|
||||
Essentially just call ``obj.isDerivedFrom(t)`` and return it's value. For
|
||||
objects using Fems typesystem (see :py:func:`type_of_obj`) return always
|
||||
True if the Fem type is equal to *t*.
|
||||
|
||||
: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.freecadweb.org/viewtopic.php?f=10&t=32625
|
||||
"""
|
||||
if (hasattr(obj, "Proxy") and hasattr(obj.Proxy, "Type") and obj.Proxy.Type == t):
|
||||
return True
|
||||
return obj.isDerivedFrom(t)
|
||||
@@ -143,8 +262,16 @@ def is_derived_from(obj, t):
|
||||
# ************************************************************************************************
|
||||
# working dir
|
||||
def get_pref_working_dir(solver_obj):
|
||||
# _dirTypes from run are not used
|
||||
# be aware beside could get an error if the document has not been saved
|
||||
""" Return working directory for solver honoring user settings.
|
||||
|
||||
:throws femsolver.run.MustSaveError:
|
||||
If user setting is set to BESIDE and the document isn't saved.
|
||||
|
||||
:note:
|
||||
Not working correctely for most cases because this circumvents directory
|
||||
caching of the solver framework. For solver use getMachine from run.py
|
||||
instead.
|
||||
"""
|
||||
dir_setting = settings.get_dir_setting()
|
||||
if dir_setting == settings.TEMPORARY:
|
||||
setting_working_dir = get_temp_dir(solver_obj)
|
||||
@@ -255,6 +382,13 @@ def get_part_to_mesh(mesh_obj):
|
||||
|
||||
|
||||
def getBoundBoxOfAllDocumentShapes(doc):
|
||||
""" Calculate bounding box containing all objects inside *doc*.
|
||||
|
||||
:returns:
|
||||
A bounding box containing all objects that have a *Shape* attribute (all
|
||||
Part and PartDesign objects). If the document contains no such objects or
|
||||
no objects at all return ``None``.
|
||||
"""
|
||||
overalboundbox = None
|
||||
for o in doc.Objects:
|
||||
# netgen mesh obj has an attribute Shape which is an Document obj, which has no BB
|
||||
@@ -271,6 +405,16 @@ def getBoundBoxOfAllDocumentShapes(doc):
|
||||
|
||||
|
||||
def getSelectedFace(selectionex):
|
||||
""" Return selected face if exactly one face is selected.
|
||||
|
||||
:returns:
|
||||
The selcted face as a ``Part::TopoShape`` if exactly one face is selected.
|
||||
Otherwise return ``None``.
|
||||
|
||||
:param selectionex:
|
||||
A list of selection object like the one Gui.Selection.getSelectionEx()
|
||||
returns.
|
||||
"""
|
||||
aFace = None
|
||||
# print(selectionex)
|
||||
if len(selectionex) != 1:
|
||||
@@ -290,14 +434,27 @@ def getSelectedFace(selectionex):
|
||||
|
||||
|
||||
def get_refshape_type(fem_doc_object):
|
||||
# returns the reference shape type
|
||||
# for force object:
|
||||
# in GUI defined frc_obj all frc_obj have at least one ref_shape
|
||||
# and ref_shape have all the same shape type
|
||||
# for material object:
|
||||
# in GUI defined material_obj could have no RefShape and RefShapes could be different type
|
||||
# we're going to need the RefShapes to be the same type inside one fem_doc_object
|
||||
# TODO: check if all RefShapes inside the object really have the same type
|
||||
""" Return shape type the constraints references.
|
||||
|
||||
Determine single shape type of references of *fem_doc_object* which must be
|
||||
a constraint (=have a *References* property). All references must be of the
|
||||
same type which is than returned as a string. A type can be "Vertex",
|
||||
"Edge", "Face" or "Solid".
|
||||
|
||||
:param fem_doc_object:
|
||||
A constraint object with a *References* property.
|
||||
|
||||
:returns:
|
||||
A string representing the shape type ("Vertex", "Edge", "Face" or
|
||||
"Solid"). If *fem_doc_object* isn't a contraint ``""`` is returned.
|
||||
|
||||
:note:
|
||||
Undefined behaviour if the type of the references of one object arn't all
|
||||
the same.
|
||||
|
||||
:note:
|
||||
Undefined behaviour if constraint contains no references (empty list).
|
||||
"""
|
||||
import femmesh.meshtools as FemMeshTools
|
||||
if hasattr(fem_doc_object, "References") and fem_doc_object.References:
|
||||
first_ref_obj = fem_doc_object.References[0]
|
||||
@@ -315,6 +472,12 @@ def get_refshape_type(fem_doc_object):
|
||||
|
||||
|
||||
def pydecode(bytestring):
|
||||
""" Return *bytestring* as a unicode string for python 2 and 3.
|
||||
|
||||
For python 2 *bytestring* is converted to a string of type ``unicode``. For
|
||||
python 3 it is returned as is because it uses unicode for it's ``str`` type
|
||||
already.
|
||||
"""
|
||||
if sys.version_info.major < 3:
|
||||
return bytestring
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user