Fem: Remove dependency of calculix solver classes on user parameters - fixes #13383
This commit is contained in:
committed by
Chris Hennes
parent
55dd8076cc
commit
3d7d5ab785
@@ -1044,6 +1044,110 @@ class _ResultsPurge(CommandManager):
|
||||
import femresult.resulttools as resulttools
|
||||
resulttools.purge_results(self.active_analysis)
|
||||
|
||||
class _SolverCalculixContextManager:
|
||||
|
||||
def __init__(self, make_name, cli_obj_ref_name):
|
||||
self.make_name = make_name
|
||||
self.cli_name = cli_obj_ref_name
|
||||
|
||||
def __enter__(self):
|
||||
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
|
||||
FreeCAD.ActiveDocument.openTransaction("Create SolverCalculix")
|
||||
FreeCADGui.addModule("ObjectsFem")
|
||||
FreeCADGui.addModule("FemGui")
|
||||
FreeCADGui.doCommand(
|
||||
"{} = ObjectsFem.{}(FreeCAD.ActiveDocument)".format(
|
||||
self.cli_name, self.make_name
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.AnalysisType = {}".format(
|
||||
self.cli_name, ccx_prefs.GetInt("AnalysisType", 0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.EigenmodesCount = {}".format(
|
||||
self.cli_name, ccx_prefs.GetInt("EigenmodesCount", 10)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.EigenmodeLowLimit = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("EigenmodeLowLimit", 0.0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.EigenmodeHighLimit = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("EigenmodeHighLimit", 1000000.0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.IterationsMaximum = {}".format(
|
||||
self.cli_name, ccx_prefs.GetInt("AnalysisMaxIterations", 2000)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.TimeInitialStep = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("AnalysisTimeInitialStep", 1.0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.TimeEnd = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("AnalysisTime", 1.0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.TimeMinimumStep = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("AnalysisTimeMinimumStep", 0.00001)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.TimeMaximumStep = {}".format(
|
||||
self.cli_name, ccx_prefs.GetFloat("AnalysisTimeMaximumStep", 1.0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.ThermoMechSteadyState = {}".format(
|
||||
self.cli_name, ccx_prefs.GetBool("StaticAnalysis", True)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.IterationsControlParameterTimeUse = {}".format(
|
||||
self.cli_name, ccx_prefs.GetInt("UseNonCcxIterationParam", False)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.SplitInputWriter = {}".format(
|
||||
self.cli_name, ccx_prefs.GetBool("SplitInputWriter", False)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.MatrixSolverType = {}".format(
|
||||
self.cli_name, ccx_prefs.GetInt("Solver", 0)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.BeamShellResultOutput3D = {}".format(
|
||||
self.cli_name, ccx_prefs.GetBool("BeamShellOutput", True)
|
||||
)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.GeometricalNonlinearity = \"{}\"".format(
|
||||
self.cli_name,
|
||||
"nonlinear" if ccx_prefs.GetBool("NonlinearGeometry", False) else "linear"
|
||||
)
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, trace):
|
||||
FreeCADGui.doCommand(
|
||||
"FemGui.getActiveAnalysis().addObject({})".format(self.cli_name)
|
||||
)
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
# expand analysis object in tree view
|
||||
expandParentObject()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
class _SolverCcxTools(CommandManager):
|
||||
"The FEM_SolverCalculix ccx tools command definition"
|
||||
@@ -1063,29 +1167,19 @@ class _SolverCcxTools(CommandManager):
|
||||
self.is_active = "with_analysis"
|
||||
|
||||
def Activated(self):
|
||||
has_nonlinear_material_obj = False
|
||||
for m in self.active_analysis.Group:
|
||||
if is_of_type(m, "Fem::MaterialMechanicalNonlinear"):
|
||||
has_nonlinear_material_obj = True
|
||||
FreeCAD.ActiveDocument.openTransaction("Create SolverCalculix")
|
||||
FreeCADGui.addModule("ObjectsFem")
|
||||
FreeCADGui.addModule("FemGui")
|
||||
if has_nonlinear_material_obj:
|
||||
FreeCADGui.doCommand(
|
||||
"solver = ObjectsFem.makeSolverCalculiXCcxTools(FreeCAD.ActiveDocument)"
|
||||
)
|
||||
FreeCADGui.doCommand("solver.GeometricalNonlinearity = 'nonlinear'")
|
||||
FreeCADGui.doCommand("solver.MaterialNonlinearity = 'nonlinear'")
|
||||
FreeCADGui.doCommand("FemGui.getActiveAnalysis().addObject(solver)")
|
||||
else:
|
||||
FreeCADGui.doCommand(
|
||||
"FemGui.getActiveAnalysis().addObject(ObjectsFem."
|
||||
"makeSolverCalculiXCcxTools(FreeCAD.ActiveDocument))"
|
||||
)
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
# expand analysis object in tree view
|
||||
expandParentObject()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
with _SolverCalculixContextManager("makeSolverCalculiXCcxTools", "solver") as cm:
|
||||
has_nonlinear_material_obj = False
|
||||
for m in self.active_analysis.Group:
|
||||
if is_of_type(m, "Fem::MaterialMechanicalNonlinear"):
|
||||
has_nonlinear_material_obj = True
|
||||
|
||||
if has_nonlinear_material_obj:
|
||||
FreeCADGui.doCommand(
|
||||
"{}.GeometricalNonlinearity = 'nonlinear'".format(cm.cli_name)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.MaterialNonlinearity = 'nonlinear'".format(cm.cli_name)
|
||||
)
|
||||
|
||||
|
||||
class _SolverCalculix(CommandManager):
|
||||
@@ -1104,8 +1198,21 @@ class _SolverCalculix(CommandManager):
|
||||
"Creates a FEM solver CalculiX new framework (less result error handling)"
|
||||
)
|
||||
self.is_active = "with_analysis"
|
||||
self.is_active = "with_analysis"
|
||||
self.do_activated = "add_obj_on_gui_expand_noset_edit"
|
||||
|
||||
def Activated(self):
|
||||
with _SolverCalculixContextManager("makeSolverCalculix", "solver") as cm:
|
||||
has_nonlinear_material_obj = False
|
||||
for m in self.active_analysis.Group:
|
||||
if is_of_type(m, "Fem::MaterialMechanicalNonlinear"):
|
||||
has_nonlinear_material_obj = True
|
||||
|
||||
if has_nonlinear_material_obj:
|
||||
FreeCADGui.doCommand(
|
||||
"{}.GeometricalNonlinearity = 'nonlinear'".format(cm.cli_name)
|
||||
)
|
||||
FreeCADGui.doCommand(
|
||||
"{}.MaterialNonlinearity = 'nonlinear'".format(cm.cli_name)
|
||||
)
|
||||
|
||||
|
||||
class _SolverControl(CommandManager):
|
||||
|
||||
@@ -32,11 +32,10 @@ __url__ = "https://www.freecad.org"
|
||||
import FreeCAD
|
||||
|
||||
from . import base_fempythonobject
|
||||
from femsolver.calculix.solver import add_attributes
|
||||
from femsolver.calculix.solver import on_restore_of_document
|
||||
from femsolver.calculix.solver import _BaseSolverCalculix
|
||||
|
||||
|
||||
class SolverCcxTools(base_fempythonobject.BaseFemPythonObject):
|
||||
class SolverCcxTools(base_fempythonobject.BaseFemPythonObject, _BaseSolverCalculix):
|
||||
"""The Fem::FemSolver's Proxy python type, add solver specific properties
|
||||
"""
|
||||
|
||||
@@ -45,11 +44,8 @@ class SolverCcxTools(base_fempythonobject.BaseFemPythonObject):
|
||||
def __init__(self, obj):
|
||||
super(SolverCcxTools, self).__init__(obj)
|
||||
|
||||
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
|
||||
|
||||
# add attributes
|
||||
# implemented in framework calculix solver module
|
||||
add_attributes(obj, ccx_prefs)
|
||||
self.add_attributes(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyPath",
|
||||
@@ -62,8 +58,4 @@ class SolverCcxTools(base_fempythonobject.BaseFemPythonObject):
|
||||
# only used if the preferences working directory is left blank
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
|
||||
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
|
||||
|
||||
# implemented in framework calculix solver module
|
||||
on_restore_of_document(obj, ccx_prefs)
|
||||
self.on_restore_of_document(obj)
|
||||
|
||||
@@ -49,7 +49,318 @@ def create(doc, name="SolverCalculiX"):
|
||||
doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(solverbase.Proxy):
|
||||
class _BaseSolverCalculix:
|
||||
|
||||
def on_restore_of_document(self, obj):
|
||||
temp_analysis_type = obj.AnalysisType
|
||||
obj.AnalysisType = ANALYSIS_TYPES
|
||||
if temp_analysis_type in ANALYSIS_TYPES:
|
||||
obj.AnalysisType = temp_analysis_type
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
"Analysis type {} not found. Standard is used.\n"
|
||||
.format(temp_analysis_type)
|
||||
)
|
||||
obj.AnalysisType = ANALYSIS_TYPES[0]
|
||||
|
||||
self.add_attributes(obj)
|
||||
|
||||
|
||||
def add_attributes(self, obj):
|
||||
if not hasattr(obj, "AnalysisType"):
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"AnalysisType",
|
||||
"Fem",
|
||||
"Type of the analysis"
|
||||
)
|
||||
obj.AnalysisType = ANALYSIS_TYPES
|
||||
obj.AnalysisType = ANALYSIS_TYPES[0]
|
||||
|
||||
if not hasattr(obj, "GeometricalNonlinearity"):
|
||||
choices_geom_nonlinear = ["linear", "nonlinear"]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"GeometricalNonlinearity",
|
||||
"Fem",
|
||||
"Set geometrical nonlinearity"
|
||||
)
|
||||
obj.GeometricalNonlinearity = choices_geom_nonlinear
|
||||
obj.GeometricalNonlinearity = choices_geom_nonlinear[0]
|
||||
|
||||
if not hasattr(obj, "MaterialNonlinearity"):
|
||||
choices_material_nonlinear = ["linear", "nonlinear"]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"MaterialNonlinearity",
|
||||
"Fem",
|
||||
"Set material nonlinearity"
|
||||
)
|
||||
obj.MaterialNonlinearity = choices_material_nonlinear
|
||||
obj.MaterialNonlinearity = choices_material_nonlinear[0]
|
||||
|
||||
if not hasattr(obj, "EigenmodesCount"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"EigenmodesCount",
|
||||
"Fem",
|
||||
"Number of modes for frequency calculations"
|
||||
)
|
||||
obj.EigenmodesCount = (10, 1, 100, 1)
|
||||
|
||||
if not hasattr(obj, "EigenmodeLowLimit"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"EigenmodeLowLimit",
|
||||
"Fem",
|
||||
"Low frequency limit for eigenmode calculations"
|
||||
)
|
||||
obj.EigenmodeLowLimit = (0.0, 0.0, 1000000.0, 10000.0)
|
||||
|
||||
if not hasattr(obj, "EigenmodeHighLimit"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"EigenmodeHighLimit",
|
||||
"Fem",
|
||||
"High frequency limit for eigenmode calculations"
|
||||
)
|
||||
obj.EigenmodeHighLimit = (1000000.0, 0.0, 1000000.0, 10000.0)
|
||||
|
||||
if not hasattr(obj, "IterationsMaximum"):
|
||||
help_string_IterationsMaximum = (
|
||||
"Maximum Number of iterations "
|
||||
"in each time step before stopping jobs"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"IterationsMaximum",
|
||||
"Fem",
|
||||
help_string_IterationsMaximum
|
||||
)
|
||||
obj.IterationsMaximum = 2000
|
||||
|
||||
if hasattr(obj, "IterationsThermoMechMaximum"):
|
||||
obj.IterationsMaximum = obj.IterationsThermoMechMaximum
|
||||
obj.removeProperty("IterationsThermoMechMaximum")
|
||||
|
||||
if not hasattr(obj, "BucklingFactors"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"BucklingFactors",
|
||||
"Fem",
|
||||
"Calculates the lowest buckling modes to the corresponding buckling factors"
|
||||
)
|
||||
obj.BucklingFactors = 1
|
||||
|
||||
if not hasattr(obj, "TimeInitialStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeInitialStep",
|
||||
"Fem",
|
||||
"Initial time steps"
|
||||
)
|
||||
obj.TimeInitialStep = 0.01
|
||||
|
||||
if not hasattr(obj, "TimeEnd"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeEnd",
|
||||
"Fem",
|
||||
"End time analysis"
|
||||
)
|
||||
obj.TimeEnd = 1.0
|
||||
|
||||
if not hasattr(obj, "TimeMinimumStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeMinimumStep",
|
||||
"Fem",
|
||||
"Minimum time step"
|
||||
)
|
||||
obj.TimeMinimumStep = 0.00001
|
||||
|
||||
if not hasattr(obj, "TimeMaximumStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeMaximumStep",
|
||||
"Fem",
|
||||
"Maximum time step"
|
||||
)
|
||||
obj.TimeMaximumStep = 1.0
|
||||
|
||||
if not hasattr(obj, "ThermoMechSteadyState"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ThermoMechSteadyState",
|
||||
"Fem",
|
||||
"Choose between steady state thermo mech or transient thermo mech analysis"
|
||||
)
|
||||
obj.ThermoMechSteadyState = True
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterTimeUse"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsControlParameterTimeUse",
|
||||
"Fem",
|
||||
"Use the user defined time incrementation control parameter"
|
||||
)
|
||||
obj.IterationsControlParameterTimeUse = False
|
||||
|
||||
if not hasattr(obj, "SplitInputWriter"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"SplitInputWriter",
|
||||
"Fem",
|
||||
"Split writing of ccx input file"
|
||||
)
|
||||
obj.SplitInputWriter = False
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterIter"):
|
||||
control_parameter_iterations = (
|
||||
"{I_0},{I_R},{I_P},{I_C},{I_L},{I_G},{I_S},{I_A},{I_J},{I_T}".format(
|
||||
I_0=4,
|
||||
I_R=8,
|
||||
I_P=9,
|
||||
I_C=200, # ccx default = 16
|
||||
I_L=10,
|
||||
I_G=400, # ccx default = 4
|
||||
I_S="",
|
||||
I_A=200, # ccx default = 5
|
||||
I_J="",
|
||||
I_T="",
|
||||
)
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"IterationsControlParameterIter",
|
||||
"Fem",
|
||||
"User defined time incrementation iterations control parameter"
|
||||
)
|
||||
obj.IterationsControlParameterIter = control_parameter_iterations
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterCutb"):
|
||||
control_parameter_cutback = (
|
||||
"{D_f},{D_C},{D_B},{D_A},{D_S},{D_H},{D_D},{W_G}".format(
|
||||
D_f=0.25,
|
||||
D_C=0.5,
|
||||
D_B=0.75,
|
||||
D_A=0.85,
|
||||
D_S="",
|
||||
D_H="",
|
||||
D_D=1.5,
|
||||
W_G="",
|
||||
)
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"IterationsControlParameterCutb",
|
||||
"Fem",
|
||||
"User defined time incrementation cutbacks control parameter"
|
||||
)
|
||||
obj.IterationsControlParameterCutb = control_parameter_cutback
|
||||
|
||||
if not hasattr(obj, "IterationsUserDefinedIncrementations"):
|
||||
stringIterationsUserDefinedIncrementations = (
|
||||
"Set to True to switch off the ccx automatic incrementation completely "
|
||||
"(ccx parameter DIRECT). Use with care. Analysis may not converge!"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsUserDefinedIncrementations",
|
||||
"Fem",
|
||||
stringIterationsUserDefinedIncrementations
|
||||
)
|
||||
obj.IterationsUserDefinedIncrementations = False
|
||||
|
||||
if not hasattr(obj, "IterationsUserDefinedTimeStepLength"):
|
||||
help_string_IterationsUserDefinedTimeStepLength = (
|
||||
"Set to True to use the user defined time steps. "
|
||||
"They are set with TimeInitialStep, TimeEnd, TimeMinimum and TimeMaximum"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsUserDefinedTimeStepLength",
|
||||
"Fem",
|
||||
help_string_IterationsUserDefinedTimeStepLength
|
||||
)
|
||||
obj.IterationsUserDefinedTimeStepLength = False
|
||||
|
||||
if not hasattr(obj, "MatrixSolverType"):
|
||||
known_ccx_solver_types = [
|
||||
"default",
|
||||
"pastix",
|
||||
"pardiso",
|
||||
"spooles",
|
||||
"iterativescaling",
|
||||
"iterativecholesky"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"MatrixSolverType",
|
||||
"Fem",
|
||||
"Type of solver to use"
|
||||
)
|
||||
obj.MatrixSolverType = known_ccx_solver_types
|
||||
obj.MatrixSolverType = known_ccx_solver_types[0]
|
||||
|
||||
if not hasattr(obj, "BeamShellResultOutput3D"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"BeamShellResultOutput3D",
|
||||
"Fem",
|
||||
"Output 3D results for 1D and 2D analysis "
|
||||
)
|
||||
obj.BeamShellResultOutput3D = True
|
||||
|
||||
if not hasattr(obj, "BeamReducedIntegration"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"BeamReducedIntegration",
|
||||
"Fem",
|
||||
"Set to True to use beam elements with reduced integration"
|
||||
)
|
||||
obj.BeamReducedIntegration = True
|
||||
|
||||
if not hasattr(obj, "OutputFrequency"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"OutputFrequency",
|
||||
"Fem",
|
||||
"Set the output frequency in increments"
|
||||
)
|
||||
obj.OutputFrequency = 1
|
||||
|
||||
if not hasattr(obj, "ModelSpace"):
|
||||
model_space_types = [
|
||||
"3D",
|
||||
"plane stress",
|
||||
"plane strain",
|
||||
"axisymmetric"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"ModelSpace",
|
||||
"Fem",
|
||||
"Type of model space"
|
||||
)
|
||||
obj.ModelSpace = model_space_types
|
||||
|
||||
if not hasattr(obj, "ThermoMechType"):
|
||||
thermomech_types = [
|
||||
"coupled",
|
||||
"uncoupled",
|
||||
"pure heat transfer"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"ThermoMechType",
|
||||
"Fem",
|
||||
"Type of thermomechanical analysis"
|
||||
)
|
||||
obj.ThermoMechType = thermomech_types
|
||||
|
||||
|
||||
class Proxy(solverbase.Proxy, _BaseSolverCalculix):
|
||||
"""The Fem::FemSolver's Proxy python type, add solver specific properties
|
||||
"""
|
||||
|
||||
@@ -58,15 +369,10 @@ class Proxy(solverbase.Proxy):
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.Proxy = self
|
||||
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
|
||||
add_attributes(obj, ccx_prefs)
|
||||
self.add_attributes(obj)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
|
||||
# since it is needed for the ccxtools solver too
|
||||
# the method is implemented outside of the class
|
||||
# thus we need to pass the prefs
|
||||
on_restore_of_document(obj, ccx_prefs)
|
||||
self.on_restore_of_document(obj)
|
||||
|
||||
def createMachine(self, obj, directory, testmode=False):
|
||||
return run.Machine(
|
||||
@@ -94,355 +400,6 @@ class ViewProxy(solverbase.ViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
# ************************************************************************************************
|
||||
# helper
|
||||
# these methods are outside of the class to be able
|
||||
# to use them from framework solver and ccxtools solver
|
||||
|
||||
|
||||
def on_restore_of_document(obj, ccx_prefs):
|
||||
|
||||
# ANALYSIS_TYPES
|
||||
# They have been extended. If file was saved with a old FC version
|
||||
# not all enum types are available, because they are saved in the FC file
|
||||
# thus refresh the list of known ANALYSIS_TYPES
|
||||
# print("onRestoredFromSuperClass")
|
||||
# print(obj.AnalysisType)
|
||||
# print(obj.getEnumerationsOfProperty("AnalysisType"))
|
||||
|
||||
temp_analysis_type = obj.AnalysisType
|
||||
# self.add_properties(obj)
|
||||
obj.AnalysisType = ANALYSIS_TYPES
|
||||
if temp_analysis_type in ANALYSIS_TYPES:
|
||||
obj.AnalysisType = temp_analysis_type
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
"Analysis type {} not found. Standard is used.\n"
|
||||
.format(temp_analysis_type)
|
||||
)
|
||||
analysis_type = ccx_prefs.GetInt("AnalysisType", 0)
|
||||
obj.AnalysisType = ANALYSIS_TYPES[analysis_type]
|
||||
|
||||
# add missing properties
|
||||
# for example BucklingFactors will be added
|
||||
# for all files created before buckle analysis was introduced
|
||||
add_attributes(obj, ccx_prefs)
|
||||
|
||||
|
||||
def add_attributes(obj, ccx_prefs):
|
||||
|
||||
if not hasattr(obj, "AnalysisType"):
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"AnalysisType",
|
||||
"Fem",
|
||||
"Type of the analysis"
|
||||
)
|
||||
obj.AnalysisType = ANALYSIS_TYPES
|
||||
analysis_type = ccx_prefs.GetInt("AnalysisType", 0)
|
||||
obj.AnalysisType = ANALYSIS_TYPES[analysis_type]
|
||||
|
||||
if not hasattr(obj, "GeometricalNonlinearity"):
|
||||
choices_geom_nonlinear = ["linear", "nonlinear"]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"GeometricalNonlinearity",
|
||||
"Fem",
|
||||
"Set geometrical nonlinearity"
|
||||
)
|
||||
obj.GeometricalNonlinearity = choices_geom_nonlinear
|
||||
nonlinear_geom = ccx_prefs.GetBool("NonlinearGeometry", False)
|
||||
if nonlinear_geom is True:
|
||||
obj.GeometricalNonlinearity = choices_geom_nonlinear[1] # nonlinear
|
||||
else:
|
||||
obj.GeometricalNonlinearity = choices_geom_nonlinear[0] # linear
|
||||
|
||||
if not hasattr(obj, "MaterialNonlinearity"):
|
||||
choices_material_nonlinear = ["linear", "nonlinear"]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"MaterialNonlinearity",
|
||||
"Fem",
|
||||
"Set material nonlinearity"
|
||||
)
|
||||
obj.MaterialNonlinearity = choices_material_nonlinear
|
||||
obj.MaterialNonlinearity = choices_material_nonlinear[0]
|
||||
|
||||
if not hasattr(obj, "EigenmodesCount"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"EigenmodesCount",
|
||||
"Fem",
|
||||
"Number of modes for frequency calculations"
|
||||
)
|
||||
noem = ccx_prefs.GetInt("EigenmodesCount", 10)
|
||||
obj.EigenmodesCount = (noem, 1, 100, 1)
|
||||
|
||||
if not hasattr(obj, "EigenmodeLowLimit"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"EigenmodeLowLimit",
|
||||
"Fem",
|
||||
"Low frequency limit for eigenmode calculations"
|
||||
)
|
||||
ell = ccx_prefs.GetFloat("EigenmodeLowLimit", 0.0)
|
||||
obj.EigenmodeLowLimit = (ell, 0.0, 1000000.0, 10000.0)
|
||||
|
||||
if not hasattr(obj, "EigenmodeHighLimit"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"EigenmodeHighLimit",
|
||||
"Fem",
|
||||
"High frequency limit for eigenmode calculations"
|
||||
)
|
||||
ehl = ccx_prefs.GetFloat("EigenmodeHighLimit", 1000000.0)
|
||||
obj.EigenmodeHighLimit = (ehl, 0.0, 1000000.0, 10000.0)
|
||||
|
||||
if not hasattr(obj, "IterationsMaximum"):
|
||||
help_string_IterationsMaximum = (
|
||||
"Maximum Number of iterations "
|
||||
"in each time step before stopping jobs"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"IterationsMaximum",
|
||||
"Fem",
|
||||
help_string_IterationsMaximum
|
||||
)
|
||||
niter = ccx_prefs.GetInt("AnalysisMaxIterations", 2000)
|
||||
obj.IterationsMaximum = niter
|
||||
|
||||
if hasattr(obj, "IterationsThermoMechMaximum"):
|
||||
obj.IterationsMaximum = obj.IterationsThermoMechMaximum
|
||||
obj.removeProperty("IterationsThermoMechMaximum")
|
||||
|
||||
if not hasattr(obj, "BucklingFactors"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"BucklingFactors",
|
||||
"Fem",
|
||||
"Calculates the lowest buckling modes to the corresponding buckling factors"
|
||||
)
|
||||
bckl = ccx_prefs.GetInt("BucklingFactors", 1)
|
||||
obj.BucklingFactors = bckl
|
||||
|
||||
if not hasattr(obj, "TimeInitialStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeInitialStep",
|
||||
"Fem",
|
||||
"Initial time steps"
|
||||
)
|
||||
ini = ccx_prefs.GetFloat("AnalysisTimeInitialStep", 1.0)
|
||||
obj.TimeInitialStep = ini
|
||||
|
||||
if not hasattr(obj, "TimeEnd"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeEnd",
|
||||
"Fem",
|
||||
"End time analysis"
|
||||
)
|
||||
eni = ccx_prefs.GetFloat("AnalysisTime", 1.0)
|
||||
obj.TimeEnd = eni
|
||||
|
||||
if not hasattr(obj, "TimeMinimumStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeMinimumStep",
|
||||
"Fem",
|
||||
"Minimum time step"
|
||||
)
|
||||
mini = ccx_prefs.GetFloat("AnalysisTimeMinimumStep", 0.00001)
|
||||
obj.TimeMinimumStep = mini
|
||||
|
||||
if not hasattr(obj, "TimeMaximumStep"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"TimeMaximumStep",
|
||||
"Fem",
|
||||
"Maximum time step"
|
||||
)
|
||||
maxi = ccx_prefs.GetFloat("AnalysisTimeMaximumStep", 1.0)
|
||||
obj.TimeMaximumStep = maxi
|
||||
|
||||
if not hasattr(obj, "ThermoMechSteadyState"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ThermoMechSteadyState",
|
||||
"Fem",
|
||||
"Choose between steady state thermo mech or transient thermo mech analysis"
|
||||
)
|
||||
sted = ccx_prefs.GetBool("StaticAnalysis", True)
|
||||
obj.ThermoMechSteadyState = sted
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterTimeUse"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsControlParameterTimeUse",
|
||||
"Fem",
|
||||
"Use the user defined time incrementation control parameter"
|
||||
)
|
||||
use_non_ccx_iterations_param = ccx_prefs.GetInt("UseNonCcxIterationParam", False)
|
||||
obj.IterationsControlParameterTimeUse = use_non_ccx_iterations_param
|
||||
|
||||
if not hasattr(obj, "SplitInputWriter"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"SplitInputWriter",
|
||||
"Fem",
|
||||
"Split writing of ccx input file"
|
||||
)
|
||||
split = ccx_prefs.GetBool("SplitInputWriter", False)
|
||||
obj.SplitInputWriter = split
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterIter"):
|
||||
control_parameter_iterations = (
|
||||
"{I_0},{I_R},{I_P},{I_C},{I_L},{I_G},{I_S},{I_A},{I_J},{I_T}".format(
|
||||
I_0=4,
|
||||
I_R=8,
|
||||
I_P=9,
|
||||
I_C=200, # ccx default = 16
|
||||
I_L=10,
|
||||
I_G=400, # ccx default = 4
|
||||
I_S="",
|
||||
I_A=200, # ccx default = 5
|
||||
I_J="",
|
||||
I_T="",
|
||||
)
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"IterationsControlParameterIter",
|
||||
"Fem",
|
||||
"User defined time incrementation iterations control parameter"
|
||||
)
|
||||
obj.IterationsControlParameterIter = control_parameter_iterations
|
||||
|
||||
if not hasattr(obj, "IterationsControlParameterCutb"):
|
||||
control_parameter_cutback = (
|
||||
"{D_f},{D_C},{D_B},{D_A},{D_S},{D_H},{D_D},{W_G}".format(
|
||||
D_f=0.25,
|
||||
D_C=0.5,
|
||||
D_B=0.75,
|
||||
D_A=0.85,
|
||||
D_S="",
|
||||
D_H="",
|
||||
D_D=1.5,
|
||||
W_G="",
|
||||
)
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"IterationsControlParameterCutb",
|
||||
"Fem",
|
||||
"User defined time incrementation cutbacks control parameter"
|
||||
)
|
||||
obj.IterationsControlParameterCutb = control_parameter_cutback
|
||||
|
||||
if not hasattr(obj, "IterationsUserDefinedIncrementations"):
|
||||
stringIterationsUserDefinedIncrementations = (
|
||||
"Set to True to switch off the ccx automatic incrementation completely "
|
||||
"(ccx parameter DIRECT). Use with care. Analysis may not converge!"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsUserDefinedIncrementations",
|
||||
"Fem",
|
||||
stringIterationsUserDefinedIncrementations
|
||||
)
|
||||
obj.IterationsUserDefinedIncrementations = False
|
||||
|
||||
if not hasattr(obj, "IterationsUserDefinedTimeStepLength"):
|
||||
help_string_IterationsUserDefinedTimeStepLength = (
|
||||
"Set to True to use the user defined time steps. "
|
||||
"They are set with TimeInitialStep, TimeEnd, TimeMinimum and TimeMaximum"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IterationsUserDefinedTimeStepLength",
|
||||
"Fem",
|
||||
help_string_IterationsUserDefinedTimeStepLength
|
||||
)
|
||||
obj.IterationsUserDefinedTimeStepLength = False
|
||||
|
||||
if not hasattr(obj, "MatrixSolverType"):
|
||||
known_ccx_solver_types = [
|
||||
"default",
|
||||
"pastix",
|
||||
"pardiso",
|
||||
"spooles",
|
||||
"iterativescaling",
|
||||
"iterativecholesky"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"MatrixSolverType",
|
||||
"Fem",
|
||||
"Type of solver to use"
|
||||
)
|
||||
obj.MatrixSolverType = known_ccx_solver_types
|
||||
solver_type = ccx_prefs.GetInt("Solver", 0)
|
||||
obj.MatrixSolverType = known_ccx_solver_types[solver_type]
|
||||
|
||||
if not hasattr(obj, "BeamShellResultOutput3D"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"BeamShellResultOutput3D",
|
||||
"Fem",
|
||||
"Output 3D results for 1D and 2D analysis "
|
||||
)
|
||||
dimout = ccx_prefs.GetBool("BeamShellOutput", True)
|
||||
obj.BeamShellResultOutput3D = dimout
|
||||
|
||||
|
||||
if not hasattr(obj, "BeamReducedIntegration"):
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"BeamReducedIntegration",
|
||||
"Fem",
|
||||
"Set to True to use beam elements with reduced integration"
|
||||
)
|
||||
obj.BeamReducedIntegration = True
|
||||
|
||||
if not hasattr(obj, "OutputFrequency"):
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"OutputFrequency",
|
||||
"Fem",
|
||||
"Set the output frequency in increments"
|
||||
)
|
||||
obj.OutputFrequency = 1
|
||||
|
||||
if not hasattr(obj, "ModelSpace"):
|
||||
model_space_types = [
|
||||
"3D",
|
||||
"plane stress",
|
||||
"plane strain",
|
||||
"axisymmetric"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"ModelSpace",
|
||||
"Fem",
|
||||
"Type of model space"
|
||||
)
|
||||
obj.ModelSpace = model_space_types
|
||||
|
||||
if not hasattr(obj, "ThermoMechType"):
|
||||
thermomech_types = [
|
||||
"coupled",
|
||||
"uncoupled",
|
||||
"pure heat transfer"
|
||||
]
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"ThermoMechType",
|
||||
"Fem",
|
||||
"Type of thermomechanical analysis"
|
||||
)
|
||||
obj.ThermoMechType = thermomech_types
|
||||
|
||||
"""
|
||||
Should there be some equation object for Calculix too?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user