diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index cb99d6c051..b047e1b480 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -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): diff --git a/src/Mod/Fem/femobjects/solver_ccxtools.py b/src/Mod/Fem/femobjects/solver_ccxtools.py index ab03e9ce29..4a8a26cdfa 100644 --- a/src/Mod/Fem/femobjects/solver_ccxtools.py +++ b/src/Mod/Fem/femobjects/solver_ccxtools.py @@ -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) diff --git a/src/Mod/Fem/femsolver/calculix/solver.py b/src/Mod/Fem/femsolver/calculix/solver.py index dbaa434bb9..0bf2587257 100644 --- a/src/Mod/Fem/femsolver/calculix/solver.py +++ b/src/Mod/Fem/femsolver/calculix/solver.py @@ -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?