From 3818534cd6bbf78b3a57c946ac73f33650233f6c Mon Sep 17 00:00:00 2001 From: Uwe Date: Sat, 6 Aug 2022 04:32:18 +0200 Subject: [PATCH] [FEM] Elmer: fixes for the simulation parameters - output equation-specific values only if this equation is used - use Elmer's default for BDF order as default for FC too and allow to change it - don't hardcode to Steady State. Transient must be possible too, this way add parameters to run a transient analysis --- src/Mod/Fem/femsolver/elmer/equations/heat.py | 2 +- src/Mod/Fem/femsolver/elmer/solver.py | 50 ++++++++++++-- src/Mod/Fem/femsolver/elmer/writer.py | 69 ++++++++++++++++--- .../femtest/data/elmer/box_static_0_mm.sif | 4 +- .../elmer/ccxcantilever_faceload_0_mm.sif | 4 +- .../elmer/ccxcantilever_faceload_1_si.sif | 4 +- .../elmer/ccxcantilever_nodeload_0_mm.sif | 4 +- ...cantilever_prescribeddisplacement_0_mm.sif | 4 +- 8 files changed, 111 insertions(+), 30 deletions(-) diff --git a/src/Mod/Fem/femsolver/elmer/equations/heat.py b/src/Mod/Fem/femsolver/elmer/equations/heat.py index 19239224a5..80a5a82eff 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/heat.py +++ b/src/Mod/Fem/femsolver/elmer/equations/heat.py @@ -53,9 +53,9 @@ class Proxy(nonlinear.Proxy, equationbase.HeatProxy): "Heat", "" ) + obj.Bubbles = True obj.Stabilize = False - obj.Priority = 20 diff --git a/src/Mod/Fem/femsolver/elmer/solver.py b/src/Mod/Fem/femsolver/elmer/solver.py index 6392e9afc2..fd041f110d 100644 --- a/src/Mod/Fem/femsolver/elmer/solver.py +++ b/src/Mod/Fem/femsolver/elmer/solver.py @@ -47,6 +47,7 @@ from femtools import femutils if FreeCAD.GuiUp: import FemGui +SIMULATION_TYPE = ["Scanning", "Steady State", "Transient"] def create(doc, name="ElmerSolver"): return femutils.createObject( @@ -70,19 +71,60 @@ class Proxy(solverbase.Proxy): def __init__(self, obj): super(Proxy, self).__init__(obj) + obj.addProperty( + "App::PropertyIntegerConstraint", + "BDFOrder", + "Timestepping", + "Order of time stepping method 'BDF'" + ) + # according to the Elmer manual recommended is order 2 + # possible ranage is 1 - 5 + obj.BDFOrder = (2, 1, 5, 1) + + obj.addProperty( + "App::PropertyIntegerConstraint", + "TimestepIntervals", + "Timestepping", + "Maximum optimization rounds if 'Simulation Type'\nis either 'Scanning' or 'Transient'" + ) + obj.addProperty( + "App::PropertyFloatConstraint", + "TimestepSizes", + "Timestepping", + "Time step of optimization if 'Simulation Type'\nis either 'Scanning' or 'Transient'" + ) + # there is no universal default, it all depends on the analysis, however + # we have to set something and set 10 seconds in steps of 0.1s + # since the Emler manual lacks proper info, here a link to a forum thread: + # http://www.elmerfem.org/forum/viewtopic.php?p=18057&sid=73169c4ec544fd7f181f85178bbc8ffe#p18057 + # ----- + # Set maximum to 1e8 because on Win the max int is always 32bit (4.29e9) + # for TimestepSizes also 1e8 just to set something + obj.TimestepIntervals = (100, 1, int(1e8), 10) + obj.TimestepSizes = (0.1, 1e-8, 1e8, 0.1) + + obj.addProperty( + "App::PropertyEnumeration", + "SimulationType", + "Type", + "" + ) + obj.SimulationType = SIMULATION_TYPE + obj.SimulationType = "Steady State" + obj.addProperty( "App::PropertyInteger", "SteadyStateMaxIterations", - "Steady State", - "" + "Type", + "Maximal steady state iterations" ) obj.SteadyStateMaxIterations = 1 obj.addProperty( "App::PropertyInteger", "SteadyStateMinIterations", - "Steady State", - "" + "Type", + "Minimal steady state iterations" ) obj.SteadyStateMinIterations = 0 diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py index 4af83813f6..9590804bca 100644 --- a/src/Mod/Fem/femsolver/elmer/writer.py +++ b/src/Mod/Fem/femsolver/elmer/writer.py @@ -309,23 +309,72 @@ class Writer(object): ) def _handleSimulation(self): + # check if we need to update the equation + self._updateSimulation(self.solver) + # output the equation parameters + # first check what equations we have + hasHeat = False + for equation in self.solver.Group: + if femutils.is_of_type(equation, "Fem::EquationElmerHeat"): + hasHeat = True + if hasHeat: + self._simulation("BDF Order", self.solver.BDFOrder) self._simulation("Coordinate System", "Cartesian 3D") self._simulation("Coordinate Mapping", (1, 2, 3)) # Elmer uses SI base units, but our mesh is in mm, therefore we must tell # the solver that we have another scale self._simulation("Coordinate Scaling", 0.001) - self._simulation("Simulation Type", "Steady state") - self._simulation("Steady State Max Iterations", 1) self._simulation("Output Intervals", 1) - self._simulation("Timestepping Method", "BDF") - self._simulation("BDF Order", 1) + self._simulation("Simulation Type", + self.solver.SimulationType) + if self.solver.SimulationType == "Steady State": + self._simulation( + "Steady State Max Iterations", self.solver.SteadyStateMaxIterations) + self._simulation( + "Steady State Min Iterations", self.solver.SteadyStateMinIterations) + if (self.solver.SimulationType == "Scanning") \ + or (self.solver.SimulationType == "Transient"): + self._simulation("Timestep Intervals", self.solver.TimestepIntervals) + self._simulation("Timestep Sizes", self.solver.TimestepSizes) + if hasHeat: + self._simulation("Timestepping Method", "BDF") self._simulation("Use Mesh Names", True) - self._simulation( - "Steady State Max Iterations", - self.solver.SteadyStateMaxIterations) - self._simulation( - "Steady State Min Iterations", - self.solver.SteadyStateMinIterations) + + def _updateSimulation(self, solver): + # updates older simulations + if not hasattr(self.solver, "BDFOrder"): + solver.addProperty( + "App::PropertyIntegerConstraint", + "BDFOrder", + "Timestepping", + "Order of time stepping method 'BDF'" + ) + solver.BDFOrder = (2, 1, 5, 1) + if not hasattr(self.solver, "SimulationType"): + solver.addProperty( + "App::PropertyEnumeration", + "SimulationType", + "Type", + "" + ) + solver.SimulationType = ["Scanning", "Steady State", "Transient"] + solver.SimulationType = "Steady State" + if not hasattr(self.solver, "TimestepIntervals"): + solver.addProperty( + "App::PropertyIntegerConstraint", + "TimestepIntervals", + "Timestepping", + "Maximum optimization rounds if 'Simulation Type'\nis either 'Scanning' or 'Transient'" + ) + solver.TimestepIntervals = (100, 1, int(1e8), 10) + if not hasattr(self.solver, "TimestepSizes"): + solver.addProperty( + "App::PropertyFloatConstraint", + "TimestepSizes", + "Timestepping", + "Time step of optimization if 'Simulation Type'\nis either 'Scanning' or 'Transient'" + ) + solver.TimestepSizes = (0.1, 1e-8, 1e8, 0.1) def _handleHeat(self): activeIn = [] diff --git a/src/Mod/Fem/femtest/data/elmer/box_static_0_mm.sif b/src/Mod/Fem/femtest/data/elmer/box_static_0_mm.sif index b986c21c4b..7b0f1cc748 100644 --- a/src/Mod/Fem/femtest/data/elmer/box_static_0_mm.sif +++ b/src/Mod/Fem/femtest/data/elmer/box_static_0_mm.sif @@ -24,15 +24,13 @@ Solver 1 End Simulation - BDF Order = Integer 1 Coordinate Mapping(3) = Integer 1 2 3 Coordinate Scaling = Real 0.001 Coordinate System = String "Cartesian 3D" Output Intervals = Integer 1 - Simulation Type = String "Steady state" + Simulation Type = String "Steady State" Steady State Max Iterations = Integer 1 Steady State Min Iterations = Integer 0 - Timestepping Method = String "BDF" Use Mesh Names = Logical True End diff --git a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_0_mm.sif b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_0_mm.sif index aa797f1f6f..aed7f0236e 100644 --- a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_0_mm.sif +++ b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_0_mm.sif @@ -24,15 +24,13 @@ Solver 1 End Simulation - BDF Order = Integer 1 Coordinate Mapping(3) = Integer 1 2 3 Coordinate Scaling = Real 0.001 Coordinate System = String "Cartesian 3D" Output Intervals = Integer 1 - Simulation Type = String "Steady state" + Simulation Type = String "Steady State" Steady State Max Iterations = Integer 1 Steady State Min Iterations = Integer 0 - Timestepping Method = String "BDF" Use Mesh Names = Logical True End diff --git a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_1_si.sif b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_1_si.sif index ffedc8aad1..84760888df 100644 --- a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_1_si.sif +++ b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_faceload_1_si.sif @@ -24,15 +24,13 @@ Solver 1 End Simulation - BDF Order = Integer 1 Coordinate Mapping(3) = Integer 1 2 3 Coordinate Scaling = Real 0.001 Coordinate System = String "Cartesian 3D" Output Intervals = Integer 1 - Simulation Type = String "Steady state" + Simulation Type = String "Steady State" Steady State Max Iterations = Integer 1 Steady State Min Iterations = Integer 0 - Timestepping Method = String "BDF" Use Mesh Names = Logical True End diff --git a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_nodeload_0_mm.sif b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_nodeload_0_mm.sif index 7c4aecf3e8..c8a586d319 100644 --- a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_nodeload_0_mm.sif +++ b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_nodeload_0_mm.sif @@ -24,15 +24,13 @@ Solver 1 End Simulation - BDF Order = Integer 1 Coordinate Mapping(3) = Integer 1 2 3 Coordinate Scaling = Real 0.001 Coordinate System = String "Cartesian 3D" Output Intervals = Integer 1 - Simulation Type = String "Steady state" + Simulation Type = String "Steady State" Steady State Max Iterations = Integer 1 Steady State Min Iterations = Integer 0 - Timestepping Method = String "BDF" Use Mesh Names = Logical True End diff --git a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_prescribeddisplacement_0_mm.sif b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_prescribeddisplacement_0_mm.sif index 10ad289fd1..24a564b516 100644 --- a/src/Mod/Fem/femtest/data/elmer/ccxcantilever_prescribeddisplacement_0_mm.sif +++ b/src/Mod/Fem/femtest/data/elmer/ccxcantilever_prescribeddisplacement_0_mm.sif @@ -24,15 +24,13 @@ Solver 1 End Simulation - BDF Order = Integer 1 Coordinate Mapping(3) = Integer 1 2 3 Coordinate Scaling = Real 0.001 Coordinate System = String "Cartesian 3D" Output Intervals = Integer 1 - Simulation Type = String "Steady state" + Simulation Type = String "Steady State" Steady State Max Iterations = Integer 1 Steady State Min Iterations = Integer 0 - Timestepping Method = String "BDF" Use Mesh Names = Logical True End