FEM: Add support for amplitudes with CalculiX (#22851)

This commit is contained in:
FEA-eng
2025-08-01 22:22:01 +02:00
committed by GitHub
parent c41c50e946
commit 79e6d8f016
41 changed files with 202 additions and 32 deletions

View File

@@ -0,0 +1,51 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * Copyright (c) 2025 Jakub Michalski <jakub.j.michalski[at]gmail.com> *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD 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 *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
__title__ = "FreeCAD FEM calculix amplitude"
__author__ = "Jakub Michalski"
__url__ = "https://www.freecad.org"
def write_amplitude(f, ccxwriter):
# write amplitude definitions for all analysis features that use them
def write_obj_amplitude(obj):
if obj.EnableAmplitude:
f.write(f"*AMPLITUDE, NAME={obj.Name}\n")
for value in obj.AmplitudeValues:
f.write(f"{value}\n")
f.write("\n")
constraint_lists = [
ccxwriter.member.cons_force,
ccxwriter.member.cons_pressure,
ccxwriter.member.cons_displacement,
ccxwriter.member.cons_heatflux,
ccxwriter.member.cons_temperature,
ccxwriter.member.cons_bodyheatsource,
]
for constraint_list in constraint_lists:
for entry in constraint_list:
write_obj_amplitude(entry["Object"])

View File

@@ -96,6 +96,9 @@ def write_constraint(f, femobj, bodyheatsource_obj, ccxwriter):
volume = ref_feat.getSubObject(ref_sub_obj).Volume
heat = bodyheatsource_obj.TotalPower / FreeCAD.Units.Quantity(volume, "mm^3")
# write to file
f.write("*DFLUX\n")
if bodyheatsource_obj.EnableAmplitude:
f.write(f"*DFLUX, AMPLITUDE={bodyheatsource_obj.Name}\n")
else:
f.write("*DFLUX\n")
f.write("{},BF,{:.13G}\n".format(bodyheatsource_obj.Name, heat.getValueAs("t/(mm*s^3)").Value))
f.write("\n")

View File

@@ -66,7 +66,10 @@ def write_constraint(f, femobj, disp_obj, ccxwriter):
# floats read from ccx should use {:.13G}, see comment in writer module
f.write("*BOUNDARY\n")
if disp_obj.EnableAmplitude:
f.write(f"*BOUNDARY, AMPLITUDE={disp_obj.Name}\n")
else:
f.write("*BOUNDARY\n")
if not disp_obj.xFree:
f.write(
"{},1,1,{}\n".format(

View File

@@ -35,7 +35,7 @@ def get_sets_name():
def get_before_write_meshdata_constraint():
return "*CLOAD\n"
return ""
def get_after_write_meshdata_constraint():
@@ -46,6 +46,10 @@ def write_meshdata_constraint(f, femobj, force_obj, ccxwriter):
# floats read from ccx should use {:.13G}, see comment in writer module
if force_obj.EnableAmplitude:
f.write(f"*CLOAD, AMPLITUDE={force_obj.Name}\n")
else:
f.write("*CLOAD\n")
direction_vec = femobj["Object"].DirectionVector
dir_zero_tol = 1e-15 # TODO: should this be more generally for more values?
# be careful with raising the tolerance, a big load would have an impact

View File

@@ -76,7 +76,12 @@ def write_meshdata_constraint(f, femobj, heatflux_obj, ccxwriter):
else:
return
f.write(f"*{heatflux_key_word}\n")
if heatflux_obj.EnableAmplitude:
heatflux_amplitude = f", AMPLITUDE={heatflux_obj.Name}"
else:
heatflux_amplitude = ""
f.write(f"*{heatflux_key_word}{heatflux_amplitude}\n")
for ref_shape in femobj["HeatFluxFaceTable"]:
elem_string = ref_shape[0]
face_table = ref_shape[1]

View File

@@ -48,12 +48,14 @@ def write_meshdata_constraint(f, femobj, prs_obj, ccxwriter):
# floats read from ccx should use {:.13G}, see comment in writer module
if prs_obj.EnableAmplitude:
f.write(f"*DLOAD, AMPLITUDE={prs_obj.Name}\n")
else:
f.write("*DLOAD\n")
rev = -1 if prs_obj.Reversed else 1
# the pressure has to be output in MPa
pressure_quantity = FreeCAD.Units.Quantity(prs_obj.Pressure.getValueAs("MPa"))
press_rev = rev * pressure_quantity
f.write("*DLOAD\n")
for ref_shape in femobj["PressureFaces"]:
# the loop is needed for compatibility reason
# in deprecated method get_pressure_obj_faces_depreciated

View File

@@ -68,8 +68,12 @@ def write_constraint(f, femobj, temp_obj, ccxwriter):
# floats read from ccx should use {:.13G}, see comment in writer module
NumberOfNodes = len(femobj["Nodes"])
if temp_obj.EnableAmplitude:
temp_amplitude = f", AMPLITUDE={temp_obj.Name}"
else:
temp_amplitude = ""
if temp_obj.ConstraintType == "Temperature":
f.write("*BOUNDARY\n")
f.write(f"*BOUNDARY{temp_amplitude}\n")
f.write(
"{},11,11,{}\n".format(
temp_obj.Name, FreeCAD.Units.Quantity(temp_obj.Temperature.getValueAs("K"))
@@ -77,7 +81,7 @@ def write_constraint(f, femobj, temp_obj, ccxwriter):
)
f.write("\n")
elif temp_obj.ConstraintType == "CFlux":
f.write("*CFLUX\n")
f.write(f"*CFLUX{temp_amplitude}\n")
# CFLUX has to be specified in mW
f.write(
"{},11,{}\n".format(

View File

@@ -60,6 +60,7 @@ from . import write_femelement_material
from . import write_femelement_matgeosets
from . import write_footer
from . import write_mesh
from . import write_amplitude
from . import write_step_equation
from . import write_step_output
from .. import writerbase
@@ -182,6 +183,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
self.write_constraints_propdata(inpfile, self.member.cons_transform, con_transform)
self.write_constraints_propdata(inpfile, self.member.cons_rigidbody, con_rigidbody)
# amplitudes
write_amplitude.write_amplitude(inpfile, self)
# step equation
write_step_equation.write_step_equation(inpfile, self)