1075 lines
49 KiB
Python
1075 lines
49 KiB
Python
# ***************************************************************************
|
|
# * Copyright (c) 2016 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 *
|
|
# * *
|
|
# ***************************************************************************
|
|
|
|
__title__ = "FreeCAD FEM solver writer base object"
|
|
__author__ = "Bernd Hahnebach"
|
|
__url__ = "https://www.freecadweb.org"
|
|
|
|
## \addtogroup FEM
|
|
# @{
|
|
|
|
import os
|
|
|
|
import FreeCAD
|
|
|
|
from femmesh import meshtools
|
|
from femtools.femutils import type_of_obj
|
|
|
|
|
|
class FemInputWriter():
|
|
def __init__(
|
|
self,
|
|
analysis_obj,
|
|
solver_obj,
|
|
mesh_obj,
|
|
member,
|
|
dir_name=None
|
|
):
|
|
# class attributes from parameter values
|
|
self.analysis = analysis_obj
|
|
self.solver_obj = solver_obj
|
|
self.analysis_type = self.solver_obj.AnalysisType
|
|
self.mesh_object = mesh_obj
|
|
self.document = self.analysis.Document
|
|
# materials
|
|
self.material_objects = member.mats_linear
|
|
self.material_nonlinear_objects = member.mats_nonlinear
|
|
# geometries
|
|
self.beamsection_objects = member.geos_beamsection
|
|
self.beamrotation_objects = member.geos_beamrotation
|
|
self.fluidsection_objects = member.geos_fluidsection
|
|
self.shellthickness_objects = member.geos_shellthickness
|
|
# constraints
|
|
self.centrif_objects = member.cons_centrif
|
|
self.contact_objects = member.cons_contact
|
|
self.displacement_objects = member.cons_displacement
|
|
self.fixed_objects = member.cons_fixed
|
|
self.force_objects = member.cons_force
|
|
self.heatflux_objects = member.cons_heatflux
|
|
self.initialtemperature_objects = member.cons_initialtemperature
|
|
self.planerotation_objects = member.cons_planerotation
|
|
self.pressure_objects = member.cons_pressure
|
|
self.sectionprint_objects = member.cons_sectionprint
|
|
self.selfweight_objects = member.cons_selfweight
|
|
self.temperature_objects = member.cons_temperature
|
|
self.tie_objects = member.cons_tie
|
|
self.transform_objects = member.cons_transform
|
|
# working dir
|
|
self.dir_name = dir_name
|
|
# if dir_name was not given or if it exists but isn't empty: create a temporary dir
|
|
# Purpose: makes sure the analysis can be run even on wired situation
|
|
if not dir_name:
|
|
FreeCAD.Console.PrintWarning(
|
|
"Error: FemInputWriter has no working_dir --> "
|
|
"we are going to make a temporary one!\n"
|
|
)
|
|
self.dir_name = self.document.TransientDir.replace(
|
|
"\\", "/"
|
|
) + "/FemAnl_" + analysis_obj.Uid[-4:]
|
|
if not os.path.isdir(self.dir_name):
|
|
os.mkdir(self.dir_name)
|
|
|
|
# new class attributes
|
|
self.fc_ver = FreeCAD.Version()
|
|
self.ccx_nall = "Nall"
|
|
self.ccx_eall = "Eall"
|
|
self.ccx_evolumes = "Evolumes"
|
|
self.ccx_efaces = "Efaces"
|
|
self.ccx_eedges = "Eedges"
|
|
self.ccx_elsets = []
|
|
if self.mesh_object:
|
|
if hasattr(self.mesh_object, "Shape"):
|
|
self.theshape = self.mesh_object.Shape
|
|
elif hasattr(self.mesh_object, "Part"):
|
|
self.theshape = self.mesh_object.Part
|
|
else:
|
|
FreeCAD.Console.PrintWarning(
|
|
"A finite mesh without a link to a Shape was given. "
|
|
"Happen on pure mesh objects. "
|
|
"Not all methods do work without this link.\n"
|
|
)
|
|
# ATM only used in meshtools.get_femelement_direction1D_set
|
|
# TODO somehow this is not smart, rare meshes might be used often
|
|
self.femmesh = self.mesh_object.FemMesh
|
|
else:
|
|
FreeCAD.Console.PrintWarning(
|
|
"No finite element mesh object was given to the writer class. "
|
|
"In rare cases this might not be an error. "
|
|
)
|
|
self.femnodes_mesh = {}
|
|
self.femelement_table = {}
|
|
self.constraint_conflict_nodes = []
|
|
self.femnodes_ele_table = {}
|
|
self.femelements_edges_only = []
|
|
self.femelements_faces_only = []
|
|
self.femelement_volumes_table = {}
|
|
self.femelement_faces_table = {}
|
|
self.femelement_edges_table = {}
|
|
self.femelement_count_test = True
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# use set for node sets to be sure all nodes are unique
|
|
# use sorted to be sure the order is the same on different runs
|
|
# be aware a sorted set returns a list, because set are not sorted by default
|
|
# - done in return value of meshtools.get_femnodes_by_femobj_with_references
|
|
# TODO FIXME might be appropriate for element sets and surfaceface sets too
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# get all known sets
|
|
def get_mesh_sets(self):
|
|
FreeCAD.Console.PrintMessage(
|
|
"Get mesh data for "
|
|
"node sets (groups), surface sets (groups) and element sets (groups)\n"
|
|
)
|
|
|
|
# materials and element geometry element sets getter
|
|
self.get_element_sets_material_and_femelement_geometry()
|
|
|
|
# constraints element sets getter
|
|
self.get_constraints_centrif_elements()
|
|
|
|
# constraints node sets getter
|
|
self.get_constraints_fixed_nodes()
|
|
self.get_constraints_displacement_nodes()
|
|
self.get_constraints_planerotation_nodes()
|
|
|
|
# constraints suface sets getter
|
|
self.get_constraints_contact_faces()
|
|
self.get_constraints_tie_faces()
|
|
self.get_constraints_sectionprint_faces()
|
|
self.get_constraints_transform_nodes()
|
|
self.get_constraints_temperature_nodes()
|
|
|
|
# constraints sets with constraint data
|
|
self.get_constraints_force_nodeloads()
|
|
self.get_constraints_pressure_faces()
|
|
self.get_constraints_heatflux_faces()
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# node sets
|
|
def get_constraints_fixed_nodes(self):
|
|
if not self.fixed_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.fixed_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
# add nodes to constraint_conflict_nodes, needed by constraint plane rotation
|
|
for node in femobj["Nodes"]:
|
|
self.constraint_conflict_nodes.append(node)
|
|
# if mixed mesh with solids the node set needs to be split
|
|
# because solid nodes do not have rotational degree of freedom
|
|
if self.femmesh.Volumes \
|
|
and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
|
|
FreeCAD.Console.PrintMessage("We need to find the solid nodes.\n")
|
|
if not self.femelement_volumes_table:
|
|
self.femelement_volumes_table = meshtools.get_femelement_volumes_table(
|
|
self.femmesh
|
|
)
|
|
for femobj in self.fixed_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
nds_solid = []
|
|
nds_faceedge = []
|
|
for n in femobj["Nodes"]:
|
|
solid_node = False
|
|
for ve in self.femelement_volumes_table:
|
|
if n in self.femelement_volumes_table[ve]:
|
|
solid_node = True
|
|
nds_solid.append(n)
|
|
break
|
|
if not solid_node:
|
|
nds_faceedge.append(n)
|
|
femobj["NodesSolid"] = set(nds_solid)
|
|
femobj["NodesFaceEdge"] = set(nds_faceedge)
|
|
|
|
def get_constraints_displacement_nodes(self):
|
|
if not self.displacement_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.displacement_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
# add nodes to constraint_conflict_nodes, needed by constraint plane rotation
|
|
for node in femobj["Nodes"]:
|
|
self.constraint_conflict_nodes.append(node)
|
|
|
|
def get_constraints_planerotation_nodes(self):
|
|
if not self.planerotation_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.planerotation_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
|
|
def get_constraints_transform_nodes(self):
|
|
if not self.transform_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.transform_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
|
|
def get_constraints_temperature_nodes(self):
|
|
if not self.temperature_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.temperature_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
|
|
def get_constraints_fluidsection_nodes(self):
|
|
if not self.fluidsection_objects:
|
|
return
|
|
# get nodes
|
|
for femobj in self.fluidsection_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
|
|
def get_constraints_force_nodeloads(self):
|
|
if not self.force_objects:
|
|
return
|
|
# check shape type of reference shape
|
|
for femobj in self.force_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"], log=True)
|
|
if femobj["RefShapeType"] == "Vertex":
|
|
FreeCAD.Console.PrintLog(
|
|
" load on vertices --> The femelement_table "
|
|
"and femnodes_mesh are not needed for node load calculation.\n"
|
|
)
|
|
elif femobj["RefShapeType"] == "Face" \
|
|
and meshtools.is_solid_femmesh(self.femmesh) \
|
|
and not meshtools.has_no_face_data(self.femmesh):
|
|
FreeCAD.Console.PrintLog(
|
|
" solid_mesh with face data --> The femelement_table is not "
|
|
"needed but the femnodes_mesh is needed for node load calculation.\n"
|
|
)
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
else:
|
|
FreeCAD.Console.PrintLog(
|
|
" mesh without needed data --> The femelement_table "
|
|
"and femnodes_mesh are not needed for node load calculation.\n"
|
|
)
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
if not self.femelement_table:
|
|
self.femelement_table = meshtools.get_femelement_table(
|
|
self.femmesh
|
|
)
|
|
# get node loads
|
|
FreeCAD.Console.PrintLog(
|
|
" Finite element mesh nodes will be retrieved by searching "
|
|
"the appropriate nodes in the finite element mesh.\n"
|
|
)
|
|
FreeCAD.Console.PrintLog(
|
|
" The appropriate finite element mesh node load values will "
|
|
"be calculated according to the finite element definition.\n"
|
|
)
|
|
for femobj in self.force_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
frc_obj = femobj["Object"]
|
|
print_obj_info(frc_obj)
|
|
if frc_obj.Force == 0:
|
|
FreeCAD.Console.PrintMessage(" Warning --> Force = 0\n")
|
|
if femobj["RefShapeType"] == "Vertex": # point load on vertices
|
|
femobj["NodeLoadTable"] = meshtools.get_force_obj_vertex_nodeload_table(
|
|
self.femmesh,
|
|
frc_obj
|
|
)
|
|
elif femobj["RefShapeType"] == "Edge": # line load on edges
|
|
femobj["NodeLoadTable"] = meshtools.get_force_obj_edge_nodeload_table(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
self.femnodes_mesh, frc_obj
|
|
)
|
|
elif femobj["RefShapeType"] == "Face": # area load on faces
|
|
femobj["NodeLoadTable"] = meshtools.get_force_obj_face_nodeload_table(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
self.femnodes_mesh, frc_obj
|
|
)
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# faces sets
|
|
def get_constraints_pressure_faces(self):
|
|
if not self.pressure_objects:
|
|
return
|
|
# TODO see comments in get_constraints_force_nodeloads()
|
|
# it applies here too. Mhh it applies to all constraints ...
|
|
|
|
"""
|
|
# deprecated version
|
|
# get the faces and face numbers
|
|
for femobj in self.pressure_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
femobj["PressureFaces"] = meshtools.get_pressure_obj_faces_depreciated(
|
|
self.femmesh,
|
|
femobj
|
|
)
|
|
# print(femobj["PressureFaces"])
|
|
"""
|
|
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
if not self.femelement_table:
|
|
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
|
|
if not self.femnodes_ele_table:
|
|
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
|
|
self.femnodes_mesh,
|
|
self.femelement_table
|
|
)
|
|
|
|
for femobj in self.pressure_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
pressure_faces = meshtools.get_pressure_obj_faces(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
self.femnodes_ele_table, femobj
|
|
)
|
|
# the data model is for compatibility reason with deprecated version
|
|
# get_pressure_obj_faces_depreciated returns the face ids in a tuple per ref_shape
|
|
# some_string was the reference_shape_element_string in deprecated method
|
|
# [(some_string, [ele_id, ele_face_id], [ele_id, ele_face_id], ...])]
|
|
some_string = "{}: face load".format(femobj["Object"].Name)
|
|
femobj["PressureFaces"] = [(some_string, pressure_faces)]
|
|
FreeCAD.Console.PrintLog("{}\n".format(femobj["PressureFaces"]))
|
|
|
|
def get_constraints_contact_faces(self):
|
|
if not self.contact_objects:
|
|
return
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
if not self.femelement_table:
|
|
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
|
|
if not self.femnodes_ele_table:
|
|
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
|
|
self.femnodes_mesh,
|
|
self.femelement_table
|
|
)
|
|
|
|
for femobj in self.contact_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
contact_slave_faces, contact_master_faces = meshtools.get_contact_obj_faces(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
self.femnodes_ele_table, femobj
|
|
)
|
|
# [ele_id, ele_face_id], [ele_id, ele_face_id], ...]
|
|
# whereas the ele_face_id might be ccx specific
|
|
femobj["ContactSlaveFaces"] = contact_slave_faces
|
|
femobj["ContactMasterFaces"] = contact_master_faces
|
|
# FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactSlaveFaces"]))
|
|
# FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactMasterFaces"]))
|
|
|
|
# information in the regard of element faces constraints
|
|
# forum post: https://forum.freecadweb.org/viewtopic.php?f=18&t=42783&p=370286#p366723
|
|
# contact: master and slave could be the same face: rubber of a damper
|
|
# tie: master and slave have to be separate faces AFA UR_ K
|
|
# section print: only the element faces of solid elements
|
|
# from one side of the geometric face are needed
|
|
|
|
def get_constraints_tie_faces(self):
|
|
if not self.tie_objects:
|
|
return
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
if not self.femelement_table:
|
|
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
|
|
if not self.femnodes_ele_table:
|
|
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
|
|
self.femnodes_mesh,
|
|
self.femelement_table
|
|
)
|
|
|
|
for femobj in self.tie_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
print_obj_info(femobj["Object"])
|
|
slave_faces, master_faces = meshtools.get_tie_obj_faces(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
self.femnodes_ele_table, femobj
|
|
)
|
|
# [ele_id, ele_face_id], [ele_id, ele_face_id], ...]
|
|
# whereas the ele_face_id might be ccx specific
|
|
femobj["TieSlaveFaces"] = slave_faces
|
|
femobj["TieMasterFaces"] = master_faces
|
|
# FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactSlaveFaces"]))
|
|
# FreeCAD.Console.PrintLog("{}\n".format(femobj["ContactMasterFaces"]))
|
|
|
|
def get_constraints_sectionprint_faces(self):
|
|
if not self.sectionprint_objects:
|
|
return
|
|
# TODO: use meshtools to get the surfaces
|
|
# see constraint contact or constrint tie
|
|
for femobj in self.sectionprint_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
sectionprint_obj = femobj["Object"]
|
|
if len(sectionprint_obj.References) > 1:
|
|
FreeCAD.Console.PrintError(
|
|
"Only one reference shape allowed for a section print "
|
|
"but {} found: {}\n"
|
|
.format(len(sectionprint_obj.References), sectionprint_obj.References)
|
|
)
|
|
for o, elem_tup in sectionprint_obj.References:
|
|
for elem in elem_tup:
|
|
# there should only be one reference for each section print object
|
|
# in the gui this is checked
|
|
ref_shape = o.Shape.getElement(elem)
|
|
if ref_shape.ShapeType == "Face":
|
|
v = self.mesh_object.FemMesh.getccxVolumesByFace(ref_shape)
|
|
if len(v) > 0:
|
|
femobj["SectionPrintFaces"] = v
|
|
# volume elements found
|
|
FreeCAD.Console.PrintLog(
|
|
"{}, surface {}, {} touching volume elements found\n"
|
|
.format(sectionprint_obj.Label, sectionprint_obj.Name, len(v))
|
|
)
|
|
else:
|
|
# no volume elements found, shell elements not allowed
|
|
FreeCAD.Console.PrintError(
|
|
"{}, surface {}, Error: "
|
|
"No volume elements found!\n"
|
|
.format(sectionprint_obj.Label, sectionprint_obj.Name)
|
|
)
|
|
else:
|
|
# in Gui only Faces can be added
|
|
FreeCAD.Console.PrintError(
|
|
"Wrong reference shapt type for {} "
|
|
"Only Faces are allowed, but a {} was found.\n"
|
|
.format(sectionprint_obj.Name, ref_shape.ShapeType)
|
|
)
|
|
|
|
def get_constraints_heatflux_faces(self):
|
|
if not self.heatflux_objects:
|
|
return
|
|
# TODO: use meshtools to get the surfaces (or move to mesh tools)
|
|
# see constraint contact or constrint tie and constraint force
|
|
# heatflux_obj_face_table: see force_obj_node_load_table
|
|
# [
|
|
# ("refshape_name:elemname", face_table),
|
|
# ...,
|
|
# ("refshape_name:elemname", face_table)
|
|
# ]
|
|
for femobj in self.heatflux_objects:
|
|
# femobj --> dict, FreeCAD document object is femobj["Object"]
|
|
heatflux_obj = femobj["Object"]
|
|
femobj["HeatFluxFaceTable"] = []
|
|
for o, elem_tup in heatflux_obj.References:
|
|
for elem in elem_tup:
|
|
ho = o.Shape.getElement(elem)
|
|
if ho.ShapeType == "Face":
|
|
elem_info = "{}:{}".format(o.Name, elem)
|
|
face_table = self.mesh_object.FemMesh.getccxVolumesByFace(ho)
|
|
femobj["HeatFluxFaceTable"].append((elem_info, face_table))
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# element sets constraints
|
|
def get_constraints_centrif_elements(self):
|
|
# get element ids and write them into the femobj
|
|
if not self.centrif_objects:
|
|
return
|
|
if len(self.centrif_objects) == 1 and not self.centrif_objects[0]["Object"].References:
|
|
self.centrif_objects[0]["FEMElements"] = self.ccx_evolumes
|
|
else:
|
|
self.get_solid_element_sets(self.centrif_objects)
|
|
|
|
# ********************************************************************************************
|
|
# ********************************************************************************************
|
|
# element sets material and element geometry
|
|
def get_solid_element_sets(self, femobjs):
|
|
# get element ids and write them into the femobj
|
|
all_found = False
|
|
if self.femmesh.GroupCount:
|
|
all_found = meshtools.get_femelement_sets_from_group_data(
|
|
self.femmesh,
|
|
femobjs
|
|
)
|
|
FreeCAD.Console.PrintMessage(all_found)
|
|
FreeCAD.Console.PrintMessage("\n")
|
|
if all_found is False:
|
|
if not self.femelement_table:
|
|
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
|
|
# we're going to use the binary search for get_femelements_by_femnodes()
|
|
# thus we need the parameter values self.femnodes_ele_table
|
|
if not self.femnodes_mesh:
|
|
self.femnodes_mesh = self.femmesh.Nodes
|
|
if not self.femnodes_ele_table:
|
|
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
|
|
self.femnodes_mesh,
|
|
self.femelement_table
|
|
)
|
|
control = meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_table,
|
|
femobjs,
|
|
self.femnodes_ele_table
|
|
)
|
|
# we only need to set it, if it is still True
|
|
if (self.femelement_count_test is True) and (control is False):
|
|
self.femelement_count_test = False
|
|
|
|
def get_element_geometry2D_elements(self):
|
|
# get element ids and write them into the objects
|
|
FreeCAD.Console.PrintMessage("Shell thicknesses\n")
|
|
if not self.femelement_faces_table:
|
|
self.femelement_faces_table = meshtools.get_femelement_faces_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_faces_table,
|
|
self.shellthickness_objects
|
|
)
|
|
|
|
def get_element_geometry1D_elements(self):
|
|
# get element ids and write them into the objects
|
|
FreeCAD.Console.PrintMessage("Beam sections\n")
|
|
if not self.femelement_edges_table:
|
|
self.femelement_edges_table = meshtools.get_femelement_edges_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_edges_table,
|
|
self.beamsection_objects
|
|
)
|
|
|
|
def get_element_rotation1D_elements(self):
|
|
# get for each geometry edge direction the element ids and rotation norma
|
|
FreeCAD.Console.PrintMessage("Beam rotations\n")
|
|
if not self.femelement_edges_table:
|
|
self.femelement_edges_table = meshtools.get_femelement_edges_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_direction1D_set(
|
|
self.femmesh,
|
|
self.femelement_edges_table,
|
|
self.beamrotation_objects,
|
|
self.theshape
|
|
)
|
|
|
|
def get_element_fluid1D_elements(self):
|
|
# get element ids and write them into the objects
|
|
FreeCAD.Console.PrintMessage("Fluid sections\n")
|
|
if not self.femelement_edges_table:
|
|
self.femelement_edges_table = meshtools.get_femelement_edges_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_edges_table,
|
|
self.fluidsection_objects
|
|
)
|
|
|
|
def get_material_elements(self):
|
|
# it only works if either Volumes or Shellthicknesses or Beamsections
|
|
# are in the material objects, it means it does not work
|
|
# for mixed meshes and multiple materials, this is checked in check_prerequisites
|
|
# the femelement_table is only calculated for
|
|
# the highest dimension in get_femelement_table
|
|
FreeCAD.Console.PrintMessage("Materials\n")
|
|
if self.femmesh.Volumes:
|
|
# we only could do this for volumes
|
|
# if a mesh contains volumes we're going to use them in the analysis
|
|
# but a mesh could contain
|
|
# the element faces of the volumes as faces
|
|
# and the edges of the faces as edges
|
|
# there we have to check of some geometric objects
|
|
# get element ids and write them into the femobj
|
|
self.get_solid_element_sets(self.material_objects)
|
|
if self.shellthickness_objects:
|
|
if not self.femelement_faces_table:
|
|
self.femelement_faces_table = meshtools.get_femelement_faces_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_faces_table,
|
|
self.material_objects
|
|
)
|
|
if self.beamsection_objects or self.fluidsection_objects:
|
|
if not self.femelement_edges_table:
|
|
self.femelement_edges_table = meshtools.get_femelement_edges_table(
|
|
self.femmesh
|
|
)
|
|
meshtools.get_femelement_sets(
|
|
self.femmesh,
|
|
self.femelement_edges_table,
|
|
self.material_objects
|
|
)
|
|
|
|
def get_element_sets_material_and_femelement_geometry(self):
|
|
if not self.material_objects:
|
|
return
|
|
# in any case if we have beams, we're going to need the element ids for the rotation elsets
|
|
if self.beamsection_objects:
|
|
# we will need to split the beam even for one beamobj
|
|
# because no beam in z-direction can be used in ccx without a special adjustment
|
|
# thus they need an own ccx_elset
|
|
self.get_element_rotation1D_elements()
|
|
|
|
# get the element ids for face and edge elements and write them into the objects
|
|
if len(self.shellthickness_objects) > 1:
|
|
self.get_element_geometry2D_elements()
|
|
if len(self.beamsection_objects) > 1:
|
|
self.get_element_geometry1D_elements()
|
|
if len(self.fluidsection_objects) > 1:
|
|
self.get_element_fluid1D_elements()
|
|
|
|
# get the element ids for material objects and write them into the material object
|
|
if len(self.material_objects) > 1:
|
|
self.get_material_elements()
|
|
|
|
# create the ccx_elsets
|
|
if len(self.material_objects) == 1:
|
|
if self.femmesh.Volumes:
|
|
# we only could do this for volumes, if a mesh contains volumes
|
|
# we're going to use them in the analysis
|
|
# but a mesh could contain the element faces of the volumes as faces
|
|
# and the edges of the faces as edges
|
|
# there we have to check for some geometric objects
|
|
self.get_ccx_elsets_single_mat_solid()
|
|
if len(self.shellthickness_objects) == 1:
|
|
self.get_ccx_elsets_single_mat_single_shell()
|
|
elif len(self.shellthickness_objects) > 1:
|
|
self.get_ccx_elsets_single_mat_multiple_shell()
|
|
if len(self.beamsection_objects) == 1:
|
|
self.get_ccx_elsets_single_mat_single_beam()
|
|
elif len(self.beamsection_objects) > 1:
|
|
self.get_ccx_elsets_single_mat_multiple_beam()
|
|
if len(self.fluidsection_objects) == 1:
|
|
self.get_ccx_elsets_single_mat_single_fluid()
|
|
elif len(self.fluidsection_objects) > 1:
|
|
self.get_ccx_elsets_single_mat_multiple_fluid()
|
|
elif len(self.material_objects) > 1:
|
|
if self.femmesh.Volumes:
|
|
# we only could do this for volumes, if a mseh contains volumes
|
|
# we're going to use them in the analysis
|
|
# but a mesh could contain the element faces of the volumes as faces
|
|
# and the edges of the faces as edges
|
|
# there we have to check for some geometric objects
|
|
# volume is a bit special
|
|
# because retrieving ids from group mesh data is implemented
|
|
self.get_ccx_elsets_multiple_mat_solid()
|
|
if len(self.shellthickness_objects) == 1:
|
|
self.get_ccx_elsets_multiple_mat_single_shell()
|
|
elif len(self.shellthickness_objects) > 1:
|
|
self.get_ccx_elsets_multiple_mat_multiple_shell()
|
|
if len(self.beamsection_objects) == 1:
|
|
self.get_ccx_elsets_multiple_mat_single_beam()
|
|
elif len(self.beamsection_objects) > 1:
|
|
self.get_ccx_elsets_multiple_mat_multiple_beam()
|
|
if len(self.fluidsection_objects) == 1:
|
|
self.get_ccx_elsets_multiple_mat_single_fluid()
|
|
elif len(self.fluidsection_objects) > 1:
|
|
self.get_ccx_elsets_multiple_mat_multiple_fluid()
|
|
|
|
# self.ccx_elsets = [ {
|
|
# "ccx_elset" : [e1, e2, e3, ... , en] or elements set name strings
|
|
# "ccx_elset_name" : "ccx_identifier_elset"
|
|
# "mat_obj_name" : "mat_obj.Name"
|
|
# "ccx_mat_name" : "mat_obj.Material["Name"]" !!! not unique !!!
|
|
# "beamsection_obj" : "beamsection_obj" if exists
|
|
# "fluidsection_obj" : "fluidsection_obj" if exists
|
|
# "shellthickness_obj" : shellthickness_obj" if exists
|
|
# "beam_normal" : normal vector for beams only
|
|
# },
|
|
# {}, ... , {} ]
|
|
|
|
# beam
|
|
# TODO support multiple beamrotations
|
|
# we do not need any more any data from the rotation document object,
|
|
# thus we do not need to save the rotation document object name in the else
|
|
def get_ccx_elsets_single_mat_single_beam(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
beamsec_obj = self.beamsection_objects[0]["Object"]
|
|
beamrot_data = self.beamrotation_objects[0]
|
|
for i, beamdirection in enumerate(beamrot_data["FEMRotations1D"]):
|
|
# ID's for this direction
|
|
elset_data = beamdirection["ids"]
|
|
names = [
|
|
{"short": "M0"},
|
|
{"short": "B0"},
|
|
{"short": beamrot_data["ShortName"]},
|
|
{"short": "D" + str(i)}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["beamsection_obj"] = beamsec_obj
|
|
# normal for this direction
|
|
ccx_elset["beam_normal"] = beamdirection["normal"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_single_mat_multiple_beam(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
beamrot_data = self.beamrotation_objects[0]
|
|
for beamsec_data in self.beamsection_objects:
|
|
beamsec_obj = beamsec_data["Object"]
|
|
beamsec_ids = set(beamsec_data["FEMElements"])
|
|
for i, beamdirection in enumerate(beamrot_data["FEMRotations1D"]):
|
|
beamdir_ids = set(beamdirection["ids"])
|
|
# empty intersection sets possible
|
|
elset_data = list(sorted(beamsec_ids.intersection(beamdir_ids)))
|
|
if elset_data:
|
|
names = [
|
|
{"short": "M0"},
|
|
{"short": beamsec_data["ShortName"]},
|
|
{"short": beamrot_data["ShortName"]},
|
|
{"short": "D" + str(i)}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["beamsection_obj"] = beamsec_obj
|
|
# normal for this direction
|
|
ccx_elset["beam_normal"] = beamdirection["normal"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_single_beam(self):
|
|
beamsec_obj = self.beamsection_objects[0]["Object"]
|
|
beamrot_data = self.beamrotation_objects[0]
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
mat_ids = set(mat_data["FEMElements"])
|
|
for i, beamdirection in enumerate(beamrot_data["FEMRotations1D"]):
|
|
beamdir_ids = set(beamdirection["ids"])
|
|
elset_data = list(sorted(mat_ids.intersection(beamdir_ids)))
|
|
if elset_data:
|
|
names = [
|
|
{"short": mat_data["ShortName"]},
|
|
{"short": "B0"},
|
|
{"short": beamrot_data["ShortName"]},
|
|
{"short": "D" + str(i)}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["beamsection_obj"] = beamsec_obj
|
|
# normal for this direction
|
|
ccx_elset["beam_normal"] = beamdirection["normal"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_multiple_beam(self):
|
|
beamrot_data = self.beamrotation_objects[0]
|
|
for beamsec_data in self.beamsection_objects:
|
|
beamsec_obj = beamsec_data["Object"]
|
|
beamsec_ids = set(beamsec_data["FEMElements"])
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
mat_ids = set(mat_data["FEMElements"])
|
|
for i, beamdirection in enumerate(beamrot_data["FEMRotations1D"]):
|
|
beamdir_ids = set(beamdirection["ids"])
|
|
# empty intersection sets possible
|
|
elset_data = list(sorted(
|
|
beamsec_ids.intersection(mat_ids).intersection(beamdir_ids)
|
|
))
|
|
if elset_data:
|
|
names = [
|
|
{"short": mat_data["ShortName"]},
|
|
{"short": beamsec_data["ShortName"]},
|
|
{"short": beamrot_data["ShortName"]},
|
|
{"short": "D" + str(i)}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["beamsection_obj"] = beamsec_obj
|
|
# normal for this direction
|
|
ccx_elset["beam_normal"] = beamdirection["normal"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
# fluid
|
|
def get_ccx_elsets_single_mat_single_fluid(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
fluidsec_obj = self.fluidsection_objects[0]["Object"]
|
|
elset_data = self.ccx_eedges
|
|
names = [{"short": "M0"}, {"short": "F0"}]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["fluidsection_obj"] = fluidsec_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_single_mat_multiple_fluid(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
for fluidsec_data in self.fluidsection_objects:
|
|
fluidsec_obj = fluidsec_data["Object"]
|
|
elset_data = fluidsec_data["FEMElements"]
|
|
names = [{"short": "M0"}, {"short": fluidsec_data["ShortName"]}]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["fluidsection_obj"] = fluidsec_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_single_fluid(self):
|
|
fluidsec_obj = self.fluidsection_objects[0]["Object"]
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
elset_data = mat_data["FEMElements"]
|
|
names = [{"short": mat_data["ShortName"]}, {"short": "F0"}]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["fluidsection_obj"] = fluidsec_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_multiple_fluid(self):
|
|
for fluidsec_data in self.fluidsection_objects:
|
|
fluidsec_obj = fluidsec_data["Object"]
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
fluidsec_ids = set(fluidsec_data["FEMElements"])
|
|
mat_ids = set(mat_data["FEMElements"])
|
|
# empty intersection sets possible
|
|
elset_data = list(sorted(fluidsec_ids.intersection(mat_ids)))
|
|
if elset_data:
|
|
names = [
|
|
{"short": mat_data["ShortName"]},
|
|
{"short": fluidsec_data["ShortName"]}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["fluidsection_obj"] = fluidsec_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
# shell
|
|
def get_ccx_elsets_single_mat_single_shell(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
shellth_obj = self.shellthickness_objects[0]["Object"]
|
|
elset_data = self.ccx_efaces
|
|
names = [
|
|
{"long": mat_obj.Name, "short": "M0"},
|
|
{"long": shellth_obj.Name, "short": "S0"}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["shellthickness_obj"] = shellth_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_single_mat_multiple_shell(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
for shellth_data in self.shellthickness_objects:
|
|
shellth_obj = shellth_data["Object"]
|
|
elset_data = shellth_data["FEMElements"]
|
|
names = [
|
|
{"long": mat_obj.Name, "short": "M0"},
|
|
{"long": shellth_obj.Name, "short": shellth_data["ShortName"]}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["shellthickness_obj"] = shellth_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_single_shell(self):
|
|
shellth_obj = self.shellthickness_objects[0]["Object"]
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
elset_data = mat_data["FEMElements"]
|
|
names = [
|
|
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
|
|
{"long": shellth_obj.Name, "short": "S0"}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["shellthickness_obj"] = shellth_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_multiple_shell(self):
|
|
for shellth_data in self.shellthickness_objects:
|
|
shellth_obj = shellth_data["Object"]
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
shellth_ids = set(shellth_data["FEMElements"])
|
|
mat_ids = set(mat_data["FEMElements"])
|
|
# empty intersection sets possible
|
|
elset_data = list(sorted(shellth_ids.intersection(mat_ids)))
|
|
if elset_data:
|
|
names = [
|
|
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
|
|
{"long": shellth_obj.Name, "short": shellth_data["ShortName"]}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
ccx_elset["shellthickness_obj"] = shellth_obj
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
# solid
|
|
def get_ccx_elsets_single_mat_solid(self):
|
|
mat_obj = self.material_objects[0]["Object"]
|
|
elset_data = self.ccx_evolumes
|
|
names = [
|
|
{"long": mat_obj.Name, "short": "M0"},
|
|
{"long": "Solid", "short": "Solid"}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
def get_ccx_elsets_multiple_mat_solid(self):
|
|
for mat_data in self.material_objects:
|
|
mat_obj = mat_data["Object"]
|
|
elset_data = mat_data["FEMElements"]
|
|
names = [
|
|
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
|
|
{"long": "Solid", "short": "Solid"}
|
|
]
|
|
ccx_elset = {}
|
|
ccx_elset["ccx_elset"] = elset_data
|
|
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
|
|
ccx_elset["mat_obj_name"] = mat_obj.Name
|
|
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
|
|
self.ccx_elsets.append(ccx_elset)
|
|
|
|
|
|
# ************************************************************************************************
|
|
# Helpers
|
|
|
|
|
|
# ccx elset names:
|
|
# M .. Material
|
|
# B .. Beam
|
|
# R .. BeamRotation
|
|
# D .. Direction
|
|
# F .. Fluid
|
|
# S .. Shell,
|
|
# TODO write comment into input file to elset ids and elset attributes
|
|
|
|
|
|
def get_ccx_elset_name_standard(names):
|
|
# standard max length = 80
|
|
ccx_elset_name = ""
|
|
for name in names:
|
|
ccx_elset_name += name["long"]
|
|
if len(ccx_elset_name) < 81:
|
|
return ccx_elset_name
|
|
else:
|
|
ccx_elset_name = ""
|
|
for name in names:
|
|
ccx_elset_name += name["short"]
|
|
if len(ccx_elset_name) < 81:
|
|
return ccx_elset_name
|
|
else:
|
|
error = (
|
|
"FEM: Trouble in ccx input file, because an "
|
|
"elset name is longer than 80 character! {}\n"
|
|
.format(ccx_elset_name)
|
|
)
|
|
raise Exception(error)
|
|
|
|
|
|
def get_ccx_elset_name_short(names):
|
|
# restricted max length = 20 (beam elsets)
|
|
ccx_elset_name = ""
|
|
for name in names:
|
|
ccx_elset_name += name["short"]
|
|
if len(ccx_elset_name) < 21:
|
|
return ccx_elset_name
|
|
else:
|
|
error = (
|
|
"FEM: Trouble in ccx input file, because an"
|
|
"beam elset name is longer than 20 character! {}\n"
|
|
.format(ccx_elset_name)
|
|
)
|
|
raise Exception(error)
|
|
|
|
|
|
def print_obj_info(obj, log=False):
|
|
if log is False:
|
|
FreeCAD.Console.PrintMessage("{}:\n".format(obj.Label))
|
|
FreeCAD.Console.PrintMessage(
|
|
" Type: {}, Name: {}\n".format(type_of_obj(obj), obj.Name)
|
|
)
|
|
else:
|
|
FreeCAD.Console.PrintLog("{}:\n".format(obj.Label))
|
|
FreeCAD.Console.PrintLog(
|
|
" Type: {}, Name: {}\n".format(type_of_obj(obj), obj.Name)
|
|
)
|
|
|
|
## @}
|