FEM: Add support for CalculiX truss elements (#23224)

* FEM: Update element_geometry1D.py

* FEM: Update write_femelement_geometry.py

* FEM: Update write_mesh.py

* FEM: Update solver.py

* FEM: Update solver_calculix.py

* FEM: Update element_geometry1D.py
This commit is contained in:
FEA-eng
2025-09-01 17:37:44 +02:00
committed by GitHub
parent a5751e5a3b
commit 0a392c2a3f
5 changed files with 72 additions and 53 deletions

View File

@@ -175,7 +175,16 @@ class ElementGeometry1D(base_femelement.BaseFemElement):
value=["Rectangular", "Circular", "Pipe", "Elliptical", "Box"],
)
)
prop.append(
_PropHelper(
type="App::PropertyArea",
name="TrussArea",
group="TrussSection",
doc="Set cross-sectional area of truss elements\n"
+ "(used if bending stiffness is excluded in the solver)",
value=10.0,
)
)
return prop
def onDocumentRestored(self, obj):

View File

@@ -326,7 +326,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
type="App::PropertyBool",
name="ExcludeBendingStiffness",
group="Solver",
doc="Exclude bending stiffness to replace shells with membranes",
doc="Exclude bending stiffness to replace shells with membranes or beams with trusses",
value=False,
)
)

View File

@@ -428,7 +428,7 @@ class _BaseSolverCalculix:
"App::PropertyBool",
"ExcludeBendingStiffness",
"Fem",
"Exclude bending stiffness to replace shells with membranes",
"Exclude bending stiffness to replace shells with membranes or beams with trusses",
locked=True,
)
obj.ExcludeBendingStiffness = False

View File

@@ -45,52 +45,58 @@ def write_femelement_geometry(f, ccxwriter):
section_nor = "{:.13G}, {:.13G}, {:.13G}\n".format(
beam_axis_m[0], beam_axis_m[1], beam_axis_m[2]
)
if beamsec_obj.SectionType == "Rectangular":
# see meshtools.get_beam_main_axis_m(beam_direction, defined_angle)
# the method get_beam_main_axis_m() which calculates the beam_axis_m vector
# unless rotated, this vector points towards +y axis
# doesn't follow 1,2-direction order of CalculiX
# ^ (n, 2-direction)
# |
# |
# .----> (m, 1-direction)
#
len_beam_axis_n = beamsec_obj.RectHeight.getValueAs("mm").Value
len_beam_axis_m = beamsec_obj.RectWidth.getValueAs("mm").Value
section_type = ", SECTION=RECT"
section_geo = f"{len_beam_axis_m:.13G},{len_beam_axis_n:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Circular":
diameter = beamsec_obj.CircDiameter.getValueAs("mm").Value
section_type = ", SECTION=CIRC"
section_geo = f"{diameter:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Elliptical":
axis1 = beamsec_obj.Axis1Length.getValueAs("mm").Value
axis2 = beamsec_obj.Axis2Length.getValueAs("mm").Value
section_type = ", SECTION=CIRC"
section_geo = f"{axis1:.13G},{axis2:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Pipe":
radius = 0.5 * beamsec_obj.PipeDiameter.getValueAs("mm").Value
thickness = beamsec_obj.PipeThickness.getValueAs("mm").Value
section_type = ", SECTION=PIPE"
section_geo = f"{radius:.13G},{thickness:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Box":
box_width = beamsec_obj.BoxWidth.getValueAs("mm").Value
box_height = beamsec_obj.BoxHeight.getValueAs("mm").Value
box_t1 = beamsec_obj.BoxT1.getValueAs("mm").Value
box_t2 = beamsec_obj.BoxT2.getValueAs("mm").Value
box_t3 = beamsec_obj.BoxT3.getValueAs("mm").Value
box_t4 = beamsec_obj.BoxT4.getValueAs("mm").Value
section_type = ", SECTION=BOX"
section_geo = f"{box_width:.13G},{box_height:.13G},{box_t1:.13G},{box_t2:.13G},{box_t3:.13G},{box_t4:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
if ccxwriter.solver_obj.ExcludeBendingStiffness:
area = beamsec_obj.TrussArea.getValueAs("mm^2").Value
section_def = f"*SOLID SECTION, {elsetdef}{material}\n"
section_geo = f"{area:.13G}\n"
else:
if beamsec_obj.SectionType == "Rectangular":
# see meshtools.get_beam_main_axis_m(beam_direction, defined_angle)
# the method get_beam_main_axis_m() which calculates the beam_axis_m vector
# unless rotated, this vector points towards +y axis
# doesn't follow 1,2-direction order of CalculiX
# ^ (n, 2-direction)
# |
# |
# .----> (m, 1-direction)
#
len_beam_axis_n = beamsec_obj.RectHeight.getValueAs("mm").Value
len_beam_axis_m = beamsec_obj.RectWidth.getValueAs("mm").Value
section_type = ", SECTION=RECT"
section_geo = f"{len_beam_axis_m:.13G},{len_beam_axis_n:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Circular":
diameter = beamsec_obj.CircDiameter.getValueAs("mm").Value
section_type = ", SECTION=CIRC"
section_geo = f"{diameter:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Elliptical":
axis1 = beamsec_obj.Axis1Length.getValueAs("mm").Value
axis2 = beamsec_obj.Axis2Length.getValueAs("mm").Value
section_type = ", SECTION=CIRC"
section_geo = f"{axis1:.13G},{axis2:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Pipe":
radius = 0.5 * beamsec_obj.PipeDiameter.getValueAs("mm").Value
thickness = beamsec_obj.PipeThickness.getValueAs("mm").Value
section_type = ", SECTION=PIPE"
section_geo = f"{radius:.13G},{thickness:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
elif beamsec_obj.SectionType == "Box":
box_width = beamsec_obj.BoxWidth.getValueAs("mm").Value
box_height = beamsec_obj.BoxHeight.getValueAs("mm").Value
box_t1 = beamsec_obj.BoxT1.getValueAs("mm").Value
box_t2 = beamsec_obj.BoxT2.getValueAs("mm").Value
box_t3 = beamsec_obj.BoxT3.getValueAs("mm").Value
box_t4 = beamsec_obj.BoxT4.getValueAs("mm").Value
section_type = ", SECTION=BOX"
section_geo = f"{box_width:.13G},{box_height:.13G},{box_t1:.13G},{box_t2:.13G},{box_t3:.13G},{box_t4:.13G}\n"
section_def = f"*BEAM SECTION, {elsetdef}{material}{section_type}\n"
f.write(section_def)
f.write(section_geo)
f.write(section_nor)
if not ccxwriter.solver_obj.ExcludeBendingStiffness:
f.write(section_nor)
elif "fluidsection_obj" in matgeoset: # fluid mesh
fluidsec_obj = matgeoset["fluidsection_obj"]
if fluidsec_obj.SectionType == "Liquid":

View File

@@ -37,14 +37,18 @@ def write_mesh(ccxwriter):
element_param = 1 # highest element order only
group_param = False # do not write mesh group data
# Use reduced integration beam elements if this option is enabled in ccx solver settings
# Use reduced integration beam elements or truss elements if this is enabled in ccx solver settings
vol_variant = "standard"
edge_variant = "beam"
if ccxwriter.solver_obj.BeamReducedIntegration:
edge_variant = "beam reduced"
# Check to see if fluid sections are in analysis and use D network element type
if ccxwriter.member.geos_fluidsection:
edge_variant = "network"
if ccxwriter.solver_obj.ExcludeBendingStiffness:
edge_variant = "truss"
else:
if ccxwriter.solver_obj.BeamReducedIntegration:
edge_variant = "beam reduced"
else:
edge_variant = "beam"
# Check to see if fluid sections are in analysis and use D network element type
if ccxwriter.member.geos_fluidsection:
edge_variant = "network"
# Use 2D elements if model space is not set to 3D
if ccxwriter.solver_obj.ModelSpace == "3D":