Fem: Enable time increments for non-transient analysis
This commit is contained in:
@@ -53,7 +53,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="AnalysisType",
|
||||
group="Solver",
|
||||
group="AnalysisType",
|
||||
doc="Type of the analysis",
|
||||
value=["static", "frequency", "thermomech", "check", "buckling", "electromagnetic"],
|
||||
)
|
||||
@@ -125,7 +125,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyTime",
|
||||
name="TimeInitialStep",
|
||||
group="Solver",
|
||||
group="TimeIncrement",
|
||||
doc="Initial time steps",
|
||||
value=0.01,
|
||||
)
|
||||
@@ -134,7 +134,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyTime",
|
||||
name="TimeEnd",
|
||||
group="Solver",
|
||||
group="TimeIncrement",
|
||||
doc="End time analysis",
|
||||
value=1.0,
|
||||
)
|
||||
@@ -143,7 +143,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyTime",
|
||||
name="TimeMinimumStep",
|
||||
group="Solver",
|
||||
group="TimeIncrement",
|
||||
doc="Minimum time step",
|
||||
value=0.00001,
|
||||
)
|
||||
@@ -152,7 +152,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyTime",
|
||||
name="TimeMaximumStep",
|
||||
group="Solver",
|
||||
group="TimeIncrement",
|
||||
doc="Maximum time step",
|
||||
value=1.0,
|
||||
)
|
||||
@@ -161,7 +161,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyBool",
|
||||
name="ThermoMechSteadyState",
|
||||
group="Solver",
|
||||
group="AnalysisType",
|
||||
doc="Choose between steady state thermo mech or transient thermo mech analysis",
|
||||
value=True,
|
||||
)
|
||||
@@ -225,21 +225,12 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
prop.append(
|
||||
_PropHelper(
|
||||
type="App::PropertyBool",
|
||||
name="IterationsUserDefinedIncrementations",
|
||||
group="Solver",
|
||||
doc="Set to True to switch off the ccx automatic incrementation completely\n"
|
||||
+ "(ccx parameter DIRECT). Use with care. Analysis may not converge!",
|
||||
value=False,
|
||||
)
|
||||
)
|
||||
prop.append(
|
||||
_PropHelper(
|
||||
type="App::PropertyBool",
|
||||
name="IterationsUserDefinedTimeStepLength",
|
||||
group="Solver",
|
||||
doc="Set to True to use the user defined time steps.\n"
|
||||
+ "They are set with TimeInitialStep, TimeEnd, TimeMinimum and TimeMaximum",
|
||||
value=False,
|
||||
name="AutomaticIncrementation",
|
||||
group="TimeIncrement",
|
||||
doc="If False, switch off automatic incrementation via CalculiX\n"
|
||||
+ "`DIRECT` parameter and ignore minimum and maximum time increments.\n"
|
||||
+ "Analysis may not converge!",
|
||||
value=True,
|
||||
)
|
||||
)
|
||||
prop.append(
|
||||
@@ -271,7 +262,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyBool",
|
||||
name="BeamReducedIntegration",
|
||||
group="Solver",
|
||||
group="ElementModel",
|
||||
doc="Set to True to use beam elements with reduced integration",
|
||||
value=True,
|
||||
)
|
||||
@@ -289,7 +280,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="ModelSpace",
|
||||
group="Solver",
|
||||
group="ElementModel",
|
||||
doc="Type of model space",
|
||||
value=["3D", "plane stress", "plane strain", "axisymmetric"],
|
||||
)
|
||||
@@ -298,7 +289,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="ThermoMechType",
|
||||
group="Solver",
|
||||
group="AnalysisType",
|
||||
doc="Type of thermomechanical analysis",
|
||||
value=["coupled", "uncoupled", "pure heat transfer"],
|
||||
)
|
||||
@@ -316,7 +307,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="ElectromagneticMode",
|
||||
group="Solver",
|
||||
group="AnalysisType",
|
||||
doc="Electromagnetic mode",
|
||||
value=["electrostatic"],
|
||||
)
|
||||
@@ -325,7 +316,7 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
_PropHelper(
|
||||
type="App::PropertyBool",
|
||||
name="ExcludeBendingStiffness",
|
||||
group="Solver",
|
||||
group="ElementModel",
|
||||
doc="Exclude bending stiffness to replace shells with membranes or beams with trusses",
|
||||
value=False,
|
||||
)
|
||||
@@ -339,3 +330,16 @@ class SolverCalculiX(base_fempythonobject.BaseFemPythonObject):
|
||||
obj.getPropertyByName(prop.name)
|
||||
except Base.PropertyError:
|
||||
prop.add_to_object(obj)
|
||||
|
||||
# remove old properties
|
||||
try:
|
||||
obj.AutomaticIncrementation = not obj.getPropertyByName(
|
||||
"IterationsUserDefinedIncrementations"
|
||||
)
|
||||
obj.setPropertyStatus("IterationsUserDefinedIncrementations", "-LockDynamic")
|
||||
obj.removeProperty("IterationsUserDefinedIncrementations")
|
||||
obj.setPropertyStatus("IterationsUserDefinedTimeStepLength", "-LockDynamic")
|
||||
obj.removeProperty("IterationsUserDefinedTimeStepLength")
|
||||
|
||||
except Base.PropertyError:
|
||||
pass
|
||||
|
||||
@@ -29,13 +29,11 @@ __url__ = "https://www.freecad.org"
|
||||
# \ingroup FEM
|
||||
# \brief solver calculix ccx tools object
|
||||
|
||||
import FreeCAD
|
||||
|
||||
from . import base_fempythonobject
|
||||
from femsolver.calculix.solver import _BaseSolverCalculix
|
||||
from .base_fempythonobject import _PropHelper
|
||||
from .solver_calculix import SolverCalculiX
|
||||
|
||||
|
||||
class SolverCcxTools(base_fempythonobject.BaseFemPythonObject, _BaseSolverCalculix):
|
||||
class SolverCcxTools(SolverCalculiX):
|
||||
"""The Fem::FemSolver's Proxy python type, add solver specific properties"""
|
||||
|
||||
Type = "Fem::SolverCcxTools"
|
||||
@@ -43,18 +41,26 @@ class SolverCcxTools(base_fempythonobject.BaseFemPythonObject, _BaseSolverCalcul
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
# implemented in framework calculix solver module
|
||||
self.add_attributes(obj)
|
||||
def _get_properties(self):
|
||||
prop = super()._get_properties()
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyPath",
|
||||
"WorkingDir",
|
||||
"Fem",
|
||||
"Working directory for calculations, will only be used it is left blank in preferences",
|
||||
# set analysis types supported by CcxTools solver
|
||||
for p in prop:
|
||||
if p.name == "AnalysisType":
|
||||
p.value = ["static", "frequency", "thermomech", "check", "buckling"]
|
||||
|
||||
# remove unused properties
|
||||
prop = list(filter(lambda p: p.name != "ElectromagneticMode", prop))
|
||||
|
||||
prop.append(
|
||||
_PropHelper(
|
||||
type="App::PropertyPath",
|
||||
name="WorkingDir",
|
||||
group="Solver",
|
||||
doc="Working directory for calculations.\n"
|
||||
+ "Will only be used it is left blank in preferences",
|
||||
value="",
|
||||
)
|
||||
)
|
||||
obj.setPropertyStatus("WorkingDir", "LockDynamic")
|
||||
# the working directory is not set, the solver working directory is
|
||||
# only used if the preferences working directory is left blank
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
self.on_restore_of_document(obj)
|
||||
return prop
|
||||
|
||||
@@ -37,7 +37,7 @@ def write_step_equation(f, ccxwriter):
|
||||
# build STEP line
|
||||
step = "*STEP"
|
||||
if ccxwriter.solver_obj.GeometricalNonlinearity == "nonlinear":
|
||||
if ccxwriter.analysis_type == "static" or ccxwriter.analysis_type == "thermomech":
|
||||
if ccxwriter.analysis_type in ["static", "thermomech"]:
|
||||
# https://www.comsol.com/blogs/what-is-geometric-nonlinearity
|
||||
step += ", NLGEOM"
|
||||
elif ccxwriter.analysis_type == "frequency":
|
||||
@@ -45,12 +45,11 @@ def write_step_equation(f, ccxwriter):
|
||||
"Analysis type frequency and geometrical nonlinear "
|
||||
"analysis are not allowed together, linear is used instead!\n"
|
||||
)
|
||||
|
||||
if ccxwriter.solver_obj.IterationsMaximum:
|
||||
if ccxwriter.analysis_type == "thermomech" or ccxwriter.analysis_type == "static":
|
||||
if ccxwriter.analysis_type in ["static", "thermomech", "electrostatic"]:
|
||||
step += f", INC={ccxwriter.solver_obj.IterationsMaximum}"
|
||||
elif ccxwriter.analysis_type == "frequency" or ccxwriter.analysis_type == "buckling":
|
||||
# parameter is for thermomechanical analysis only, see ccx manual *STEP
|
||||
pass
|
||||
|
||||
# write STEP line
|
||||
f.write(step + "\n")
|
||||
|
||||
@@ -63,6 +62,7 @@ def write_step_equation(f, ccxwriter):
|
||||
|
||||
# ANALYSIS type line
|
||||
# analysis line --> analysis type
|
||||
analysis_type = ""
|
||||
if ccxwriter.analysis_type == "static":
|
||||
analysis_type = "*STATIC"
|
||||
elif ccxwriter.analysis_type == "frequency":
|
||||
@@ -74,12 +74,15 @@ def write_step_equation(f, ccxwriter):
|
||||
analysis_type = "*UNCOUPLED TEMPERATURE-DISPLACEMENT"
|
||||
elif ccxwriter.solver_obj.ThermoMechType == "pure heat transfer":
|
||||
analysis_type = "*HEAT TRANSFER"
|
||||
if ccxwriter.solver_obj.ThermoMechSteadyState:
|
||||
analysis_type += ", STEADY STATE"
|
||||
elif ccxwriter.analysis_type == "check":
|
||||
analysis_type = "*NO ANALYSIS"
|
||||
elif ccxwriter.analysis_type == "buckling":
|
||||
analysis_type = "*BUCKLE"
|
||||
elif ccxwriter.analysis_type == "electromagnetic":
|
||||
analysis_type = "*HEAT TRANSFER, STEADY STATE"
|
||||
|
||||
# analysis line --> solver type
|
||||
# https://forum.freecad.org/viewtopic.php?f=18&t=43178
|
||||
if ccxwriter.solver_obj.MatrixSolverType == "default":
|
||||
@@ -94,45 +97,22 @@ def write_step_equation(f, ccxwriter):
|
||||
analysis_type += ", SOLVER=ITERATIVE SCALING"
|
||||
elif ccxwriter.solver_obj.MatrixSolverType == "iterativecholesky":
|
||||
analysis_type += ", SOLVER=ITERATIVE CHOLESKY"
|
||||
# analysis line --> user defined incrementations --> parameter DIRECT
|
||||
# --> completely switch off ccx automatic incrementation
|
||||
if ccxwriter.solver_obj.IterationsUserDefinedIncrementations:
|
||||
|
||||
# analysis line --> automatic incrementation --> parameter DIRECT
|
||||
# completely switch off ccx automatic incrementation
|
||||
if not ccxwriter.solver_obj.AutomaticIncrementation:
|
||||
if ccxwriter.analysis_type in ["static", "thermomech", "electromagnetic"]:
|
||||
analysis_type += ", DIRECT"
|
||||
elif ccxwriter.analysis_type == "frequency":
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"Analysis type frequency and IterationsUserDefinedIncrementations "
|
||||
"are not allowed together, it is ignored\n"
|
||||
)
|
||||
# analysis line --> steadystate --> thermomech only
|
||||
if ccxwriter.solver_obj.ThermoMechSteadyState:
|
||||
# bernd: I do not know if STEADY STATE is allowed with DIRECT
|
||||
# but since time steps are 1.0 it makes no sense IMHO
|
||||
if ccxwriter.analysis_type == "thermomech":
|
||||
analysis_type += ", STEADY STATE"
|
||||
# Set time to 1 and ignore user inputs for steady state
|
||||
ccxwriter.solver_obj.TimeInitialStep = 1.0
|
||||
ccxwriter.solver_obj.TimeEnd = 1.0
|
||||
elif (
|
||||
ccxwriter.analysis_type == "static"
|
||||
or ccxwriter.analysis_type == "frequency"
|
||||
or ccxwriter.analysis_type == "buckling"
|
||||
):
|
||||
pass # not supported for static and frequency!
|
||||
|
||||
# ANALYSIS parameter line
|
||||
analysis_parameter = ""
|
||||
if ccxwriter.analysis_type == "static" or ccxwriter.analysis_type == "check":
|
||||
if (
|
||||
ccxwriter.solver_obj.IterationsUserDefinedIncrementations is True
|
||||
or ccxwriter.solver_obj.IterationsUserDefinedTimeStepLength is True
|
||||
):
|
||||
analysis_parameter = "{},{},{},{}".format(
|
||||
ccxwriter.solver_obj.TimeInitialStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeEnd.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMinimumStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMaximumStep.getValueAs("s").Value,
|
||||
)
|
||||
if ccxwriter.analysis_type in ["static", "thermomech", "electromagnetic"]:
|
||||
analysis_parameter = "{},{},{},{}".format(
|
||||
ccxwriter.solver_obj.TimeInitialStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeEnd.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMinimumStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMaximumStep.getValueAs("s").Value,
|
||||
)
|
||||
elif ccxwriter.analysis_type == "frequency":
|
||||
if (
|
||||
ccxwriter.solver_obj.EigenmodeLowLimit == 0.0
|
||||
@@ -145,19 +125,13 @@ def write_step_equation(f, ccxwriter):
|
||||
ccxwriter.solver_obj.EigenmodeLowLimit.getValueAs("Hz").Value,
|
||||
ccxwriter.solver_obj.EigenmodeHighLimit.getValueAs("Hz").Value,
|
||||
)
|
||||
elif ccxwriter.analysis_type == "thermomech":
|
||||
# OvG: 1.0 increment, total time 1 for steady state will cut back automatically
|
||||
analysis_parameter = "{},{},{},{}".format(
|
||||
ccxwriter.solver_obj.TimeInitialStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeEnd.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMinimumStep.getValueAs("s").Value,
|
||||
ccxwriter.solver_obj.TimeMaximumStep.getValueAs("s").Value,
|
||||
)
|
||||
elif ccxwriter.analysis_type == "buckling":
|
||||
analysis_parameter = "{},{}".format(
|
||||
ccxwriter.solver_obj.BucklingFactors,
|
||||
ccxwriter.solver_obj.BucklingAccuracy,
|
||||
)
|
||||
elif ccxwriter.analysis_type == "check":
|
||||
analysis_parameter = ""
|
||||
|
||||
# write analysis type line, analysis parameter line
|
||||
f.write(analysis_type + "\n")
|
||||
|
||||
Reference in New Issue
Block a user