FEM: reformat codebase
This commit is contained in:
@@ -34,8 +34,7 @@ from ... import equationbase
|
||||
|
||||
|
||||
def create(doc, name="Deformation"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.DeformationProxy):
|
||||
@@ -43,51 +42,40 @@ class Proxy(nonlinear.Proxy, equationbase.DeformationProxy):
|
||||
Type = "Fem::EquationElmerDeformation"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculatePangle",
|
||||
"Deformation",
|
||||
"Compute principal stress angles"
|
||||
"App::PropertyBool", "CalculatePangle", "Deformation", "Compute principal stress angles"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculatePrincipal",
|
||||
"Deformation",
|
||||
"Compute principal stress components"
|
||||
"Compute principal stress components",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateStrains",
|
||||
"Deformation",
|
||||
"Compute the strain tensor"
|
||||
"App::PropertyBool", "CalculateStrains", "Deformation", "Compute the strain tensor"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateStresses",
|
||||
"Deformation",
|
||||
"Compute stress tensor and vanMises"
|
||||
"Compute stress tensor and vanMises",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"InitializeStateVariables",
|
||||
"Deformation",
|
||||
"See Elmer manual for info"
|
||||
"See Elmer manual for info",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"MixedFormulation",
|
||||
"Deformation",
|
||||
"See Elmer manual for info"
|
||||
"App::PropertyBool", "MixedFormulation", "Deformation", "See Elmer manual for info"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"NeoHookeanMaterial",
|
||||
"Deformation",
|
||||
(
|
||||
"Uses the neo-Hookean material model"
|
||||
)
|
||||
("Uses the neo-Hookean material model"),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -96,13 +84,13 @@ class Proxy(nonlinear.Proxy, equationbase.DeformationProxy):
|
||||
(
|
||||
"Computes solution according to plane\nstress situation.\n"
|
||||
"Applies only for 2D geometry."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"Variable",
|
||||
"Deformation",
|
||||
"Only for a 2D model change the '3' to '2'"
|
||||
"Only for a 2D model change the '3' to '2'",
|
||||
)
|
||||
|
||||
obj.Priority = 10
|
||||
@@ -114,4 +102,5 @@ class Proxy(nonlinear.Proxy, equationbase.DeformationProxy):
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.DeformationViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -151,7 +151,7 @@ class DeformationWriter:
|
||||
gravity = self.write.convert(obj.GravityAcceleration.toStr(), "L/T^2")
|
||||
if self.write.getBodyMaterial(name) is None:
|
||||
raise general_writer.WriteError(
|
||||
"The body {} is not referenced in any material.\n\n".format(name)
|
||||
f"The body {name} is not referenced in any material.\n\n"
|
||||
)
|
||||
m = self.write.getBodyMaterial(name).Material
|
||||
|
||||
@@ -193,17 +193,13 @@ class DeformationWriter:
|
||||
# get the material data for all bodies
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies()
|
||||
)
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
# don't evaluate fluid material
|
||||
if self.write.isBodyMaterialFluid(name):
|
||||
break
|
||||
if "YoungsModulus" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
# it is no fluid but also no solid
|
||||
# -> user set no material reference at all
|
||||
# that now material is known
|
||||
@@ -213,22 +209,14 @@ class DeformationWriter:
|
||||
)
|
||||
self.write.material(name, "Name", m["Name"])
|
||||
if density_needed is True:
|
||||
self.write.material(
|
||||
name, "Density",
|
||||
self.write.getDensity(m)
|
||||
)
|
||||
self.write.material(
|
||||
name, "Youngs Modulus",
|
||||
self._getYoungsModulus(m)
|
||||
)
|
||||
self.write.material(
|
||||
name, "Poisson ratio",
|
||||
float(m["PoissonRatio"])
|
||||
)
|
||||
self.write.material(name, "Density", self.write.getDensity(m))
|
||||
self.write.material(name, "Youngs Modulus", self._getYoungsModulus(m))
|
||||
self.write.material(name, "Poisson ratio", float(m["PoissonRatio"]))
|
||||
if tempObj:
|
||||
self.write.material(
|
||||
name, "Heat expansion Coefficient",
|
||||
self.write.convert(m["ThermalExpansionCoefficient"], "O^-1")
|
||||
name,
|
||||
"Heat expansion Coefficient",
|
||||
self.write.convert(m["ThermalExpansionCoefficient"], "O^-1"),
|
||||
)
|
||||
|
||||
def _getYoungsModulus(self, m):
|
||||
@@ -237,4 +225,5 @@ class DeformationWriter:
|
||||
youngsModulus *= 1e3
|
||||
return youngsModulus
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -39,13 +39,12 @@ EIGEN_SYSTEM_SELECT = [
|
||||
"Smallest Real Part",
|
||||
"Largest Real Part",
|
||||
"Smallest Imag Part",
|
||||
"Largest Imag Part"
|
||||
"Largest Imag Part",
|
||||
]
|
||||
|
||||
|
||||
def create(doc, name="Elasticity"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
@@ -53,52 +52,37 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
Type = "Fem::EquationElmerElasticity"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculatePangle",
|
||||
"Elasticity",
|
||||
"Compute principal stress angles"
|
||||
"App::PropertyBool", "CalculatePangle", "Elasticity", "Compute principal stress angles"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculatePrincipal",
|
||||
"Elasticity",
|
||||
"Compute principal stress components"
|
||||
"Compute principal stress components",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateStrains",
|
||||
"Elasticity",
|
||||
"Compute the strain tensor"
|
||||
"App::PropertyBool", "CalculateStrains", "Elasticity", "Compute the strain tensor"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateStresses",
|
||||
"Elasticity",
|
||||
"Compute stress tensor and vanMises"
|
||||
"Compute stress tensor and vanMises",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ConstantBulkSystem",
|
||||
"Elasticity",
|
||||
"See Elmer manual for info"
|
||||
"App::PropertyBool", "ConstantBulkSystem", "Elasticity", "See Elmer manual for info"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"DisplaceMesh",
|
||||
"Elasticity",
|
||||
(
|
||||
"If mesh is deformed by displacement field.\n"
|
||||
"Set to False for 'Eigen Analysis'."
|
||||
)
|
||||
("If mesh is deformed by displacement field.\nSet to False for 'Eigen Analysis'."),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"EigenAnalysis",
|
||||
"Eigen Values",
|
||||
"If true, modal analysis"
|
||||
"App::PropertyBool", "EigenAnalysis", "Eigen Values", "If true, modal analysis"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -107,13 +91,13 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Should be true if eigen system is complex\n"
|
||||
"Must be false for a damped eigen value analysis."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"EigenSystemComputeResiduals",
|
||||
"Eigen Values",
|
||||
"Computes residuals of eigen value system"
|
||||
"Computes residuals of eigen value system",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -122,19 +106,19 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Set a damped eigen analysis. Can only be\n"
|
||||
"used if 'Linear Solver Type' is 'Iterative'."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"EigenSystemMaxIterations",
|
||||
"Eigen Values",
|
||||
"Max iterations for iterative eigensystem solver"
|
||||
"Max iterations for iterative eigensystem solver",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"EigenSystemSelect",
|
||||
"Eigen Values",
|
||||
"Which eigenvalues are computed"
|
||||
"Which eigenvalues are computed",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
@@ -143,25 +127,22 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Convergence tolerance for iterative eigensystem solve\n"
|
||||
"Default is 100 times the 'Linear Tolerance'"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger",
|
||||
"EigenSystemValues",
|
||||
"Eigen Values",
|
||||
"Number of lowest eigen modes"
|
||||
"Number of lowest eigen modes",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"FixDisplacement",
|
||||
"Elasticity",
|
||||
"If displacements or forces are set,\nthereby model lumping is used"
|
||||
"If displacements or forces are set,\nthereby model lumping is used",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"GeometricStiffness",
|
||||
"Elasticity",
|
||||
"Consider geometric stiffness"
|
||||
"App::PropertyBool", "GeometricStiffness", "Elasticity", "Consider geometric stiffness"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -170,25 +151,20 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Computation of incompressible material in connection\n"
|
||||
"with viscoelastic Maxwell material and a custom 'Variable'"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"MaxwellMaterial",
|
||||
"Elasticity",
|
||||
"Compute viscoelastic material model"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ModelLumping",
|
||||
"Elasticity",
|
||||
"Use model lumping"
|
||||
"Compute viscoelastic material model",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "ModelLumping", "Elasticity", "Use model lumping")
|
||||
obj.addProperty(
|
||||
"App::PropertyFile",
|
||||
"ModelLumpingFilename",
|
||||
"Elasticity",
|
||||
"File to save results from model lumping to"
|
||||
"File to save results from model lumping to",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -197,13 +173,10 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"If true, 'Eigen Analysis' is stability analysis.\n"
|
||||
"Otherwise modal analysis is performed."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"UpdateTransientSystem",
|
||||
"Elasticity",
|
||||
"See Elmer manual for info"
|
||||
"App::PropertyBool", "UpdateTransientSystem", "Elasticity", "See Elmer manual for info"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
@@ -212,7 +185,7 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Only change this if 'Incompressible' is set to true\n"
|
||||
"according to the Elmer manual."
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
obj.addProperty(
|
||||
@@ -222,7 +195,7 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
(
|
||||
"Computes solution according to plane\nstress situation.\n"
|
||||
"Applies only for 2D geometry."
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
obj.EigenSystemValues = 5
|
||||
@@ -243,8 +216,8 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
obj.EigenSystemSelect = "Smallest Magnitude"
|
||||
# according to Elmer manual default is 100 times the Linear Tolerance
|
||||
# since this is a small value we must set an expression, see linear.py for background
|
||||
for (prop, expr) in obj.ExpressionEngine:
|
||||
if (prop == "LinearTolerance"):
|
||||
for prop, expr in obj.ExpressionEngine:
|
||||
if prop == "LinearTolerance":
|
||||
obj.setExpression("EigenSystemTolerance", str(100 * obj.evalExpression(expr)))
|
||||
obj.Variable = "Displacement"
|
||||
|
||||
@@ -252,4 +225,5 @@ class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
class ViewProxy(linear.ViewProxy, equationbase.ElasticityViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -63,8 +63,7 @@ class ElasticityWriter:
|
||||
s["Displace mesh"] = equation.DisplaceMesh
|
||||
s["Eigen Analysis"] = equation.EigenAnalysis
|
||||
if equation.EigenAnalysis is True:
|
||||
s["Eigen System Convergence Tolerance"] = \
|
||||
equation.EigenSystemTolerance
|
||||
s["Eigen System Convergence Tolerance"] = equation.EigenSystemTolerance
|
||||
s["Eigen System Complex"] = equation.EigenSystemComplex
|
||||
if equation.EigenSystemComputeResiduals is True:
|
||||
s["Eigen System Compute Residuals"] = equation.EigenSystemComputeResiduals
|
||||
@@ -110,7 +109,7 @@ class ElasticityWriter:
|
||||
(
|
||||
"Only change this if 'Incompressible' is set to true\n"
|
||||
"according to the Elmer manual."
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.Variable = "Displacement"
|
||||
if hasattr(equation, "Bubbles"):
|
||||
@@ -118,10 +117,7 @@ class ElasticityWriter:
|
||||
equation.removeProperty("Bubbles")
|
||||
if not hasattr(equation, "ConstantBulkSystem"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ConstantBulkSystem",
|
||||
"Elasticity",
|
||||
"See Elmer manual for info"
|
||||
"App::PropertyBool", "ConstantBulkSystem", "Elasticity", "See Elmer manual for info"
|
||||
)
|
||||
if not hasattr(equation, "DisplaceMesh"):
|
||||
equation.addProperty(
|
||||
@@ -131,7 +127,7 @@ class ElasticityWriter:
|
||||
(
|
||||
"If mesh is deformed by displacement field.\n"
|
||||
"Set to False for 'Eigen Analysis'."
|
||||
)
|
||||
),
|
||||
)
|
||||
# DisplaceMesh is true except if DoFrequencyAnalysis is true
|
||||
equation.DisplaceMesh = True
|
||||
@@ -142,10 +138,7 @@ class ElasticityWriter:
|
||||
# DoFrequencyAnalysis was renamed to EigenAnalysis
|
||||
# to follow the Elmer manual
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"EigenAnalysis",
|
||||
"Eigen Values",
|
||||
"If true, modal analysis"
|
||||
"App::PropertyBool", "EigenAnalysis", "Eigen Values", "If true, modal analysis"
|
||||
)
|
||||
if hasattr(equation, "DoFrequencyAnalysis"):
|
||||
equation.EigenAnalysis = equation.DoFrequencyAnalysis
|
||||
@@ -158,7 +151,7 @@ class ElasticityWriter:
|
||||
(
|
||||
"Should be true if eigen system is complex\n"
|
||||
"Must be false for a damped eigen value analysis."
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.EigenSystemComplex = True
|
||||
if not hasattr(equation, "EigenSystemComputeResiduals"):
|
||||
@@ -166,7 +159,7 @@ class ElasticityWriter:
|
||||
"App::PropertyBool",
|
||||
"EigenSystemComputeResiduals",
|
||||
"Eigen Values",
|
||||
"Computes residuals of eigen value system"
|
||||
"Computes residuals of eigen value system",
|
||||
)
|
||||
if not hasattr(equation, "EigenSystemDamped"):
|
||||
equation.addProperty(
|
||||
@@ -176,14 +169,14 @@ class ElasticityWriter:
|
||||
(
|
||||
"Set a damped eigen analysis. Can only be\n"
|
||||
"used if 'Linear Solver Type' is 'Iterative'."
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "EigenSystemMaxIterations"):
|
||||
equation.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"EigenSystemMaxIterations",
|
||||
"Eigen Values",
|
||||
"Max iterations for iterative eigensystem solver"
|
||||
"Max iterations for iterative eigensystem solver",
|
||||
)
|
||||
equation.EigenSystemMaxIterations = (300, 1, int(1e8), 1)
|
||||
if not hasattr(equation, "EigenSystemSelect"):
|
||||
@@ -191,7 +184,7 @@ class ElasticityWriter:
|
||||
"App::PropertyEnumeration",
|
||||
"EigenSystemSelect",
|
||||
"Eigen Values",
|
||||
"Which eigenvalues are computed"
|
||||
"Which eigenvalues are computed",
|
||||
)
|
||||
equation.EigenSystemSelect = elasticity.EIGEN_SYSTEM_SELECT
|
||||
equation.EigenSystemSelect = "Smallest Magnitude"
|
||||
@@ -203,7 +196,7 @@ class ElasticityWriter:
|
||||
(
|
||||
"Convergence tolerance for iterative eigensystem solve\n"
|
||||
"Default is 100 times the 'Linear Tolerance'"
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.setExpression("EigenSystemTolerance", str(100 * equation.LinearTolerance))
|
||||
if not hasattr(equation, "EigenSystemValues"):
|
||||
@@ -213,7 +206,7 @@ class ElasticityWriter:
|
||||
"App::PropertyInteger",
|
||||
"EigenSystemValues",
|
||||
"Eigen Values",
|
||||
"Number of lowest eigen modes"
|
||||
"Number of lowest eigen modes",
|
||||
)
|
||||
if hasattr(equation, "EigenmodesCount"):
|
||||
equation.EigenSystemValues = equation.EigenmodesCount
|
||||
@@ -223,14 +216,14 @@ class ElasticityWriter:
|
||||
"App::PropertyBool",
|
||||
"FixDisplacement",
|
||||
"Elasticity",
|
||||
"If displacements or forces are set,\nthereby model lumping is used"
|
||||
"If displacements or forces are set,\nthereby model lumping is used",
|
||||
)
|
||||
if not hasattr(equation, "GeometricStiffness"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"GeometricStiffness",
|
||||
"Elasticity",
|
||||
"Consider geometric stiffness"
|
||||
"Consider geometric stiffness",
|
||||
)
|
||||
if not hasattr(equation, "Incompressible"):
|
||||
equation.addProperty(
|
||||
@@ -240,28 +233,25 @@ class ElasticityWriter:
|
||||
(
|
||||
"Computation of incompressible material in connection\n"
|
||||
"with viscoelastic Maxwell material and a custom 'Variable'"
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "MaxwellMaterial"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"MaxwellMaterial",
|
||||
"Elasticity",
|
||||
"Compute viscoelastic material model"
|
||||
"Compute viscoelastic material model",
|
||||
)
|
||||
if not hasattr(equation, "ModelLumping"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ModelLumping",
|
||||
"Elasticity",
|
||||
"Use model lumping"
|
||||
"App::PropertyBool", "ModelLumping", "Elasticity", "Use model lumping"
|
||||
)
|
||||
if not hasattr(equation, "ModelLumpingFilename"):
|
||||
equation.addProperty(
|
||||
"App::PropertyFile",
|
||||
"ModelLumpingFilename",
|
||||
"Elasticity",
|
||||
"File to save results from model lumping to"
|
||||
"File to save results from model lumping to",
|
||||
)
|
||||
if not hasattr(equation, "PlaneStress"):
|
||||
equation.addProperty(
|
||||
@@ -271,7 +261,7 @@ class ElasticityWriter:
|
||||
(
|
||||
"Computes solution according to plane\nstress situation.\n"
|
||||
"Applies only for 2D geometry."
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "StabilityAnalysis"):
|
||||
equation.addProperty(
|
||||
@@ -281,14 +271,14 @@ class ElasticityWriter:
|
||||
(
|
||||
"If true, 'Eigen Analysis' is stability analysis.\n"
|
||||
"Otherwise modal analysis is performed."
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "UpdateTransientSystem"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"UpdateTransientSystem",
|
||||
"Elasticity",
|
||||
"See Elmer manual for info"
|
||||
"See Elmer manual for info",
|
||||
)
|
||||
|
||||
def handleElasticityConstants(self):
|
||||
@@ -367,7 +357,7 @@ class ElasticityWriter:
|
||||
gravity = self.write.convert(obj.GravityAcceleration.toStr(), "L/T^2")
|
||||
if self.write.getBodyMaterial(name) is None:
|
||||
raise general_writer.WriteError(
|
||||
"The body {} is not referenced in any material.\n\n".format(name)
|
||||
f"The body {name} is not referenced in any material.\n\n"
|
||||
)
|
||||
m = self.write.getBodyMaterial(name).Material
|
||||
|
||||
@@ -409,17 +399,13 @@ class ElasticityWriter:
|
||||
# get the material data for all bodies
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies()
|
||||
)
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
# don't evaluate fluid material
|
||||
if self.write.isBodyMaterialFluid(name):
|
||||
break
|
||||
if "YoungsModulus" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
# it is no fluid but also no solid
|
||||
# -> user set no material reference at all
|
||||
# that now material is known
|
||||
@@ -429,22 +415,14 @@ class ElasticityWriter:
|
||||
)
|
||||
self.write.material(name, "Name", m["Name"])
|
||||
if density_needed is True:
|
||||
self.write.material(
|
||||
name, "Density",
|
||||
self.write.getDensity(m)
|
||||
)
|
||||
self.write.material(
|
||||
name, "Youngs Modulus",
|
||||
self._getYoungsModulus(m)
|
||||
)
|
||||
self.write.material(
|
||||
name, "Poisson ratio",
|
||||
float(m["PoissonRatio"])
|
||||
)
|
||||
self.write.material(name, "Density", self.write.getDensity(m))
|
||||
self.write.material(name, "Youngs Modulus", self._getYoungsModulus(m))
|
||||
self.write.material(name, "Poisson ratio", float(m["PoissonRatio"]))
|
||||
if tempObj:
|
||||
self.write.material(
|
||||
name, "Heat expansion Coefficient",
|
||||
self.write.convert(m["ThermalExpansionCoefficient"], "O^-1")
|
||||
name,
|
||||
"Heat expansion Coefficient",
|
||||
self.write.convert(m["ThermalExpansionCoefficient"], "O^-1"),
|
||||
)
|
||||
|
||||
def _getYoungsModulus(self, m):
|
||||
@@ -453,4 +431,5 @@ class ElasticityWriter:
|
||||
youngsModulus *= 1e3
|
||||
return youngsModulus
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -36,8 +36,7 @@ SOLVER_EXEC_METHODS = ["After Timestep", "Always"]
|
||||
|
||||
|
||||
def create(doc, name="Electricforce"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.ElectricforceProxy):
|
||||
@@ -45,7 +44,7 @@ class Proxy(linear.Proxy, equationbase.ElectricforceProxy):
|
||||
Type = "Fem::EquationElmerElectricforce"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
@@ -54,7 +53,7 @@ class Proxy(linear.Proxy, equationbase.ElectricforceProxy):
|
||||
(
|
||||
"That solver is only executed after solution converged\n"
|
||||
"To execute always, change to 'Always'"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
obj.ExecSolver = SOLVER_EXEC_METHODS
|
||||
@@ -68,4 +67,5 @@ class Proxy(linear.Proxy, equationbase.ElectricforceProxy):
|
||||
class ViewProxy(linear.ViewProxy, equationbase.ElectricforceViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -60,9 +60,10 @@ class EFwriter:
|
||||
(
|
||||
"That solver is only executed after solution converged\n"
|
||||
"To execute always, change to 'Always'"
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.ExecSolver = electricforce.SOLVER_EXEC_METHODS
|
||||
equation.ExecSolver = "After Timestep"
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -35,8 +35,7 @@ from . import linear
|
||||
|
||||
|
||||
def create(doc, name="Electrostatic"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.ElectrostaticProxy):
|
||||
@@ -44,38 +43,13 @@ class Proxy(linear.Proxy, equationbase.ElectrostaticProxy):
|
||||
Type = "Fem::EquationElmerElectrostatic"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateCapacitanceMatrix",
|
||||
"Electrostatic",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElectricEnergy",
|
||||
"Electrostatic",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElectricField",
|
||||
"Electrostatic",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElectricFlux",
|
||||
"Electrostatic",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateSurfaceCharge",
|
||||
"Electrostatic",
|
||||
""
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "CalculateCapacitanceMatrix", "Electrostatic", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElectricEnergy", "Electrostatic", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElectricField", "Electrostatic", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElectricFlux", "Electrostatic", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateSurfaceCharge", "Electrostatic", "")
|
||||
"""
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger",
|
||||
@@ -91,13 +65,13 @@ class Proxy(linear.Proxy, equationbase.ElectrostaticProxy):
|
||||
(
|
||||
"File where capacitance matrix is being saved\n"
|
||||
"Only used if 'CalculateCapacitanceMatrix' is true"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ConstantWeights",
|
||||
"Electrostatic",
|
||||
"Use constant weighting for results"
|
||||
"Use constant weighting for results",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
@@ -106,7 +80,7 @@ class Proxy(linear.Proxy, equationbase.ElectrostaticProxy):
|
||||
(
|
||||
"Potential difference in Volt for which capacitance is\n"
|
||||
"calculated if 'CalculateCapacitanceMatrix' is false"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
obj.CapacitanceMatrixFilename = "cmatrix.dat"
|
||||
@@ -117,4 +91,5 @@ class Proxy(linear.Proxy, equationbase.ElectrostaticProxy):
|
||||
class ViewProxy(linear.ViewProxy, equationbase.ElectrostaticViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -63,10 +63,7 @@ class ESwriter:
|
||||
s["Constant Weights"] = equation.ConstantWeights
|
||||
s["Exec Solver"] = "Always"
|
||||
s["Optimize Bandwidth"] = True
|
||||
if (
|
||||
equation.CalculateCapacitanceMatrix is False
|
||||
and (equation.PotentialDifference != 0.0)
|
||||
):
|
||||
if equation.CalculateCapacitanceMatrix is False and (equation.PotentialDifference != 0.0):
|
||||
s["Potential Difference"] = equation.PotentialDifference
|
||||
s["Stabilize"] = equation.Stabilize
|
||||
return s
|
||||
@@ -81,7 +78,7 @@ class ESwriter:
|
||||
(
|
||||
"File where capacitance matrix is being saved\n"
|
||||
"Only used if 'CalculateCapacitanceMatrix' is true"
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.CapacitanceMatrixFilename = "cmatrix.dat"
|
||||
if not hasattr(equation, "ConstantWeights"):
|
||||
@@ -89,7 +86,7 @@ class ESwriter:
|
||||
"App::PropertyBool",
|
||||
"ConstantWeights",
|
||||
"Electrostatic",
|
||||
"Use constant weighting for results"
|
||||
"Use constant weighting for results",
|
||||
)
|
||||
if not hasattr(equation, "PotentialDifference"):
|
||||
equation.addProperty(
|
||||
@@ -99,14 +96,13 @@ class ESwriter:
|
||||
(
|
||||
"Potential difference in Volt for which capacitance is\n"
|
||||
"calculated if 'CalculateCapacitanceMatrix' is false"
|
||||
)
|
||||
),
|
||||
)
|
||||
equation.PotentialDifference = 0.0
|
||||
|
||||
def handleElectrostaticConstants(self):
|
||||
permittivity = self.write.convert(
|
||||
self.write.constsdef["PermittivityOfVacuum"],
|
||||
"T^4*I^2/(L^3*M)"
|
||||
self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)"
|
||||
)
|
||||
permittivity = round(permittivity, 20) # to get rid of numerical artifacts
|
||||
self.write.constant("Permittivity Of Vacuum", permittivity)
|
||||
@@ -114,16 +110,12 @@ class ESwriter:
|
||||
def handleElectrostaticMaterial(self, bodies):
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies())
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
self.write.material(name, "Name", m["Name"])
|
||||
if "RelativePermittivity" in m:
|
||||
self.write.material(
|
||||
name, "Relative Permittivity",
|
||||
float(m["RelativePermittivity"])
|
||||
name, "Relative Permittivity", float(m["RelativePermittivity"])
|
||||
)
|
||||
|
||||
def handleElectrostaticBndConditions(self):
|
||||
@@ -143,7 +135,7 @@ class ESwriter:
|
||||
"App::PropertyElectricPotential",
|
||||
"Potential",
|
||||
"Parameter",
|
||||
"Electric Potential"
|
||||
"Electric Potential",
|
||||
)
|
||||
# scale to match SI units
|
||||
obj.Potential = savePotential * 1e6
|
||||
@@ -160,4 +152,5 @@ class ESwriter:
|
||||
self.write.boundary(name, "Capacitance Body", obj.CapacitanceBody)
|
||||
self.write.handled(obj)
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -40,7 +40,7 @@ if App.GuiUp:
|
||||
class Proxy(equationbase.BaseProxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger",
|
||||
"Priority",
|
||||
@@ -49,7 +49,7 @@ class Proxy(equationbase.BaseProxy):
|
||||
"Number of your choice\n"
|
||||
"The equation with highest number\n"
|
||||
"will be solved first."
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -72,14 +72,13 @@ class ViewProxy(equationbase.BaseViewProxy):
|
||||
return None
|
||||
|
||||
|
||||
class _TaskPanel(object):
|
||||
class _TaskPanel:
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self._refWidget = selection_widgets.SolidSelector()
|
||||
self._refWidget.setReferences(obj.References)
|
||||
propWidget = obj.ViewObject.Proxy.getTaskWidget(
|
||||
obj.ViewObject)
|
||||
propWidget = obj.ViewObject.Proxy.getTaskWidget(obj.ViewObject)
|
||||
if propWidget is None:
|
||||
self.form = self._refWidget
|
||||
else:
|
||||
|
||||
@@ -38,8 +38,7 @@ FLOW_MODEL = ["Full", "No convection", "Stokes"]
|
||||
|
||||
|
||||
def create(doc, name="Flow"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
@@ -47,7 +46,7 @@ class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
Type = "Fem::EquationElmerFlow"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -56,14 +55,9 @@ class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
(
|
||||
"Set to true for incompressible flow for more stable\n"
|
||||
"discretization when Reynolds number increases"
|
||||
)
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"FlowModel",
|
||||
"Flow",
|
||||
"Flow model to be used"
|
||||
),
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "FlowModel", "Flow", "Flow model to be used")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"GradpDiscretization",
|
||||
@@ -71,20 +65,14 @@ class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
(
|
||||
"If true pressure Dirichlet boundary conditions can be used.\n"
|
||||
"Also mass flux is available as a natural boundary condition."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyString",
|
||||
"Variable",
|
||||
"Flow",
|
||||
"Only for a 2D model change the '3' to '2'"
|
||||
"App::PropertyString", "Variable", "Flow", "Only for a 2D model change the '3' to '2'"
|
||||
)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"Convection",
|
||||
"Equation",
|
||||
"Type of convection to be used"
|
||||
"App::PropertyEnumeration", "Convection", "Equation", "Type of convection to be used"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -93,7 +81,7 @@ class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
(
|
||||
"Magnetic induction equation will be solved\n"
|
||||
"along with the Navier-Stokes equations"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.FlowModel = FLOW_MODEL
|
||||
obj.FlowModel = "Full"
|
||||
@@ -106,4 +94,5 @@ class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.FlowViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -72,7 +72,7 @@ class Flowwriter:
|
||||
"App::PropertyEnumeration",
|
||||
"Convection",
|
||||
"Equation",
|
||||
"Type of convection to be used"
|
||||
"Type of convection to be used",
|
||||
)
|
||||
equation.Convection = flow.CONVECTION_TYPE
|
||||
equation.Convection = "Computed"
|
||||
@@ -84,14 +84,11 @@ class Flowwriter:
|
||||
(
|
||||
"Set to true for incompressible flow for more stable\n"
|
||||
"discretization when Reynolds number increases"
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "FlowModel"):
|
||||
equation.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"FlowModel",
|
||||
"Flow",
|
||||
"Flow model to be used"
|
||||
"App::PropertyEnumeration", "FlowModel", "Flow", "Flow model to be used"
|
||||
)
|
||||
equation.FlowModel = flow.FLOW_MODEL
|
||||
equation.FlowModel = "Full"
|
||||
@@ -103,7 +100,7 @@ class Flowwriter:
|
||||
(
|
||||
"If true pressure Dirichlet boundary conditions can be used.\n"
|
||||
"Also mass flux is available as a natural boundary condition."
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "MagneticInduction"):
|
||||
equation.addProperty(
|
||||
@@ -113,14 +110,14 @@ class Flowwriter:
|
||||
(
|
||||
"Magnetic induction equation will be solved\n"
|
||||
"along with the Navier-Stokes equations"
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "Variable"):
|
||||
equation.addProperty(
|
||||
"App::PropertyString",
|
||||
"Variable",
|
||||
"Flow",
|
||||
"Only for a 2D model change the '3' to '2'"
|
||||
"Only for a 2D model change the '3' to '2'",
|
||||
)
|
||||
equation.Variable = "Flow Solution[Velocity:3 Pressure:1]"
|
||||
|
||||
@@ -132,10 +129,7 @@ class Flowwriter:
|
||||
self.write.material(name, "Reference Temperature", refTemp)
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies())
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
self.write.material(name, "Name", m["Name"])
|
||||
if "Density" in m:
|
||||
@@ -161,9 +155,7 @@ class Flowwriter:
|
||||
if "SpecificHeatRatio" in m:
|
||||
self.write.material(name, "Specific Heat Ratio", float(m["SpecificHeatRatio"]))
|
||||
if "CompressibilityModel" in m:
|
||||
self.write.material(
|
||||
name, "Compressibility Model",
|
||||
m["CompressibilityModel"])
|
||||
self.write.material(name, "Compressibility Model", m["CompressibilityModel"])
|
||||
|
||||
def _outputInitialPressure(self, obj, name):
|
||||
# initial pressure only makes sense for fluid material
|
||||
@@ -276,4 +268,5 @@ class Flowwriter:
|
||||
if equation.MagneticInduction is True:
|
||||
self.write.equation(b, "Magnetic Induction", equation.MagneticInduction)
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -39,8 +39,7 @@ VARIABLES = ["Potential", "Temperature"]
|
||||
|
||||
|
||||
def create(doc, name="Flux"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
@@ -48,7 +47,7 @@ class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
Type = "Fem::EquationElmerFlux"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -57,43 +56,29 @@ class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
(
|
||||
"Enforces continuity within the same material\n"
|
||||
"in the 'Discontinuous Galerkin' discretization"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "CalculateFlux", "Flux", "Computes flux vector")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateFlux",
|
||||
"Flux",
|
||||
"Computes flux vector"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateFluxAbs",
|
||||
"Flux",
|
||||
"Computes absolute of flux vector"
|
||||
"App::PropertyBool", "CalculateFluxAbs", "Flux", "Computes absolute of flux vector"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateFluxMagnitude",
|
||||
"Flux",
|
||||
"Computes magnitude of flux vector field"
|
||||
"Computes magnitude of flux vector field",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateGrad",
|
||||
"Flux",
|
||||
"Select calculation of gradient"
|
||||
"App::PropertyBool", "CalculateGrad", "Flux", "Select calculation of gradient"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateGradAbs",
|
||||
"Flux",
|
||||
"Computes absolute of gradient field"
|
||||
"App::PropertyBool", "CalculateGradAbs", "Flux", "Computes absolute of gradient field"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateGradMagnitude",
|
||||
"Flux",
|
||||
"Computes magnitude of gradient field"
|
||||
"Computes magnitude of gradient field",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -102,7 +87,7 @@ class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
(
|
||||
"Enable if standard Galerkin approximation leads to\n"
|
||||
"unphysical results when there are discontinuities"
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -111,19 +96,16 @@ class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
(
|
||||
"If true, negative values of computed magnitude fields\n"
|
||||
"are a posteriori set to zero."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"FluxCoefficient",
|
||||
"Flux",
|
||||
"Proportionality coefficient\nto compute the flux"
|
||||
"Proportionality coefficient\nto compute the flux",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"FluxVariable",
|
||||
"Flux",
|
||||
"Variable name for flux calculation"
|
||||
"App::PropertyEnumeration", "FluxVariable", "Flux", "Variable name for flux calculation"
|
||||
)
|
||||
|
||||
obj.CalculateFlux = True
|
||||
@@ -141,4 +123,5 @@ class Proxy(linear.Proxy, equationbase.FluxProxy):
|
||||
class ViewProxy(linear.ViewProxy, equationbase.FluxViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -78,38 +78,35 @@ class Fluxwriter:
|
||||
(
|
||||
"Enforces continuity within the same material\n"
|
||||
"in the 'Discontinuous Galerkin' discretization"
|
||||
)
|
||||
),
|
||||
)
|
||||
if hasattr(equation, "Bubbles"):
|
||||
# Bubbles was removed because it is unused by Elmer for the flux solver
|
||||
equation.removeProperty("Bubbles")
|
||||
if not hasattr(equation, "CalculateFluxAbs"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateFluxAbs",
|
||||
"Flux",
|
||||
"Computes absolute of flux vector"
|
||||
"App::PropertyBool", "CalculateFluxAbs", "Flux", "Computes absolute of flux vector"
|
||||
)
|
||||
if not hasattr(equation, "CalculateFluxMagnitude"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateFluxMagnitude",
|
||||
"Flux",
|
||||
"Computes magnitude of flux vector field"
|
||||
"Computes magnitude of flux vector field",
|
||||
)
|
||||
if not hasattr(equation, "CalculateGradAbs"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateGradAbs",
|
||||
"Flux",
|
||||
"Computes absolute of gradient field"
|
||||
"Computes absolute of gradient field",
|
||||
)
|
||||
if not hasattr(equation, "CalculateGradMagnitude"):
|
||||
equation.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateGradMagnitude",
|
||||
"Flux",
|
||||
"Computes magnitude of gradient field"
|
||||
"Computes magnitude of gradient field",
|
||||
)
|
||||
if not hasattr(equation, "DiscontinuousGalerkin"):
|
||||
equation.addProperty(
|
||||
@@ -119,7 +116,7 @@ class Fluxwriter:
|
||||
(
|
||||
"Enable if standard Galerkin approximation leads to\n"
|
||||
"unphysical results when there are discontinuities"
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "EnforcePositiveMagnitude"):
|
||||
equation.addProperty(
|
||||
@@ -129,7 +126,7 @@ class Fluxwriter:
|
||||
(
|
||||
"If true, negative values of computed magnitude fields\n"
|
||||
"are a posteriori set to zero."
|
||||
)
|
||||
),
|
||||
)
|
||||
tempFluxCoefficient = ""
|
||||
if hasattr(equation, "FluxCoefficient"):
|
||||
@@ -143,7 +140,7 @@ class Fluxwriter:
|
||||
"App::PropertyEnumeration",
|
||||
"FluxCoefficient",
|
||||
"Flux",
|
||||
"Name of proportionality coefficient\nto compute the flux"
|
||||
"Name of proportionality coefficient\nto compute the flux",
|
||||
)
|
||||
equation.FluxCoefficient = flux.COEFFICIENTS
|
||||
if tempFluxCoefficient:
|
||||
@@ -161,9 +158,10 @@ class Fluxwriter:
|
||||
"App::PropertyEnumeration",
|
||||
"FluxVariable",
|
||||
"Flux",
|
||||
"Variable name for flux calculation"
|
||||
"Variable name for flux calculation",
|
||||
)
|
||||
equation.FluxVariable = flux.VARIABLES
|
||||
equation.FluxVariable = tempFluxVariable
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -38,8 +38,7 @@ PHASE_CHANGE_MODEL = ["None", "Spatial 1", "Spatial 2", "Temporal"]
|
||||
|
||||
|
||||
def create(doc, name="Heat"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.HeatProxy):
|
||||
@@ -47,27 +46,16 @@ class Proxy(nonlinear.Proxy, equationbase.HeatProxy):
|
||||
Type = "Fem::EquationElmerHeat"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
# according to the Elmer models manual Bubbles is by default True
|
||||
# and Stabilize is False (Stabilize is added in linear.py)
|
||||
obj.addProperty("App::PropertyBool", "Bubbles", "Heat", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"Bubbles",
|
||||
"Heat",
|
||||
""
|
||||
"App::PropertyEnumeration", "Convection", "Equation", "Type of convection to be used"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"Convection",
|
||||
"Equation",
|
||||
"Type of convection to be used"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"PhaseChangeModel",
|
||||
"Equation",
|
||||
"Model for phase change"
|
||||
"App::PropertyEnumeration", "PhaseChangeModel", "Equation", "Model for phase change"
|
||||
)
|
||||
|
||||
obj.Bubbles = True
|
||||
@@ -82,4 +70,5 @@ class Proxy(nonlinear.Proxy, equationbase.HeatProxy):
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.HeatViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -63,7 +63,7 @@ class Heatwriter:
|
||||
def handleHeatConstants(self):
|
||||
self.write.constant(
|
||||
"Stefan Boltzmann",
|
||||
self.write.convert(self.write.constsdef["StefanBoltzmann"], "M/(O^4*T^3)")
|
||||
self.write.convert(self.write.constsdef["StefanBoltzmann"], "M/(O^4*T^3)"),
|
||||
)
|
||||
|
||||
def handleHeatEquation(self, bodies, equation):
|
||||
@@ -80,16 +80,13 @@ class Heatwriter:
|
||||
"App::PropertyEnumeration",
|
||||
"Convection",
|
||||
"Equation",
|
||||
"Type of convection to be used"
|
||||
"Type of convection to be used",
|
||||
)
|
||||
equation.Convection = heat.CONVECTION_TYPE
|
||||
equation.Convection = "None"
|
||||
if not hasattr(equation, "PhaseChangeModel"):
|
||||
equation.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"PhaseChangeModel",
|
||||
"Equation",
|
||||
"Model for phase change"
|
||||
"App::PropertyEnumeration", "PhaseChangeModel", "Equation", "Model for phase change"
|
||||
)
|
||||
equation.PhaseChangeModel = heat.PHASE_CHANGE_MODEL
|
||||
equation.PhaseChangeModel = "None"
|
||||
@@ -99,12 +96,10 @@ class Heatwriter:
|
||||
for obj in self.write.getMember("Fem::ConstraintTemperature"):
|
||||
i = i + 1
|
||||
femobjects = membertools.get_several_member(
|
||||
self.write.analysis,
|
||||
"Fem::ConstraintTemperature"
|
||||
self.write.analysis, "Fem::ConstraintTemperature"
|
||||
)
|
||||
femobjects[i]["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
|
||||
self.write.getSingleMember("Fem::FemMeshObject").FemMesh,
|
||||
femobjects[i]
|
||||
self.write.getSingleMember("Fem::FemMeshObject").FemMesh, femobjects[i]
|
||||
)
|
||||
NumberOfNodes = len(femobjects[i]["Nodes"])
|
||||
if obj.References:
|
||||
@@ -150,7 +145,9 @@ class Heatwriter:
|
||||
ref_sub_obj = ref[1][0]
|
||||
density = None
|
||||
for mat in self.write.getMember("App::MaterialObject"):
|
||||
mat_ref = [*itertools.chain(*[itertools.product([i[0]],i[1]) for i in mat.References])]
|
||||
mat_ref = [
|
||||
*itertools.chain(*[itertools.product([i[0]], i[1]) for i in mat.References])
|
||||
]
|
||||
if (ref_feat, ref_sub_obj) in mat_ref:
|
||||
density = FreeCAD.Units.Quantity(mat.Material["Density"])
|
||||
break
|
||||
@@ -162,8 +159,12 @@ class Heatwriter:
|
||||
density = FreeCAD.Units.Quantity(mat.Material["Density"])
|
||||
break
|
||||
volume = ref_feat.getSubObject(ref_sub_obj).Volume
|
||||
heatSource = (obj.TotalPower / (density*FreeCAD.Units.Quantity(volume, "mm^3"))).getValueAs("W/kg").Value
|
||||
|
||||
heatSource = (
|
||||
(obj.TotalPower / (density * FreeCAD.Units.Quantity(volume, "mm^3")))
|
||||
.getValueAs("W/kg")
|
||||
.Value
|
||||
)
|
||||
|
||||
if heatSource == 0.0:
|
||||
# a zero heat would break Elmer (division by zero)
|
||||
raise general_writer.WriteError("The body heat source must not be zero!")
|
||||
@@ -197,32 +198,30 @@ class Heatwriter:
|
||||
self.write.material(name, "Reference Temperature", refTemp)
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies())
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
if "Density" not in m:
|
||||
raise general_writer.WriteError(
|
||||
"Used material does not specify the necessary 'Density'."
|
||||
)
|
||||
self.write.material(name, "Name", m["Name"])
|
||||
self.write.material(
|
||||
name, "Density",
|
||||
self.write.getDensity(m))
|
||||
self.write.material(name, "Density", self.write.getDensity(m))
|
||||
if "ThermalConductivity" not in m:
|
||||
raise general_writer.WriteError(
|
||||
"Used material does not specify the necessary 'Thermal Conductivity'."
|
||||
)
|
||||
self.write.material(
|
||||
name, "Heat Conductivity",
|
||||
self.write.convert(m["ThermalConductivity"], "M*L/(T^3*O)"))
|
||||
name,
|
||||
"Heat Conductivity",
|
||||
self.write.convert(m["ThermalConductivity"], "M*L/(T^3*O)"),
|
||||
)
|
||||
if "SpecificHeat" not in m:
|
||||
raise general_writer.WriteError(
|
||||
"Used material does not specify the necessary 'Specific Heat'."
|
||||
)
|
||||
self.write.material(
|
||||
name, "Heat Capacity",
|
||||
self.write.convert(m["SpecificHeat"], "L^2/(T^2*O)"))
|
||||
name, "Heat Capacity", self.write.convert(m["SpecificHeat"], "L^2/(T^2*O)")
|
||||
)
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -39,75 +39,32 @@ from . import equation
|
||||
|
||||
LINEAR_SOLVER = ["Direct", "Iterative"]
|
||||
LINEAR_DIRECT = ["Banded", "MUMPS", "Umfpack"]
|
||||
LINEAR_ITERATIVE = [
|
||||
"BiCGStab",
|
||||
"BiCGStabl",
|
||||
"CG",
|
||||
"GCR",
|
||||
"CGS",
|
||||
"GMRES",
|
||||
"Idrs",
|
||||
"TFQMR"
|
||||
]
|
||||
LINEAR_PRECONDITIONING = [
|
||||
"None",
|
||||
"Diagonal",
|
||||
"ILU0",
|
||||
"ILU1",
|
||||
"ILU2",
|
||||
"ILU3",
|
||||
"ILU4",
|
||||
"ILUT"
|
||||
]
|
||||
LINEAR_ITERATIVE = ["BiCGStab", "BiCGStabl", "CG", "GCR", "CGS", "GMRES", "Idrs", "TFQMR"]
|
||||
LINEAR_PRECONDITIONING = ["None", "Diagonal", "ILU0", "ILU1", "ILU2", "ILU3", "ILU4", "ILUT"]
|
||||
|
||||
|
||||
class Proxy(equation.Proxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"BiCGstablDegree",
|
||||
"Linear System",
|
||||
"Polynom degree for iterative method 'BiCGstabl'"
|
||||
"Polynom degree for iterative method 'BiCGstabl'",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"IdrsParameter",
|
||||
"Linear System",
|
||||
"Parameter for iterative method 'Idrs'"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"LinearDirectMethod",
|
||||
"Linear System",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"LinearIterations",
|
||||
"Linear System",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"LinearIterativeMethod",
|
||||
"Linear System",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"LinearPreconditioning",
|
||||
"Linear System",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"LinearSolverType",
|
||||
"Linear System",
|
||||
""
|
||||
"Parameter for iterative method 'Idrs'",
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "LinearDirectMethod", "Linear System", "")
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "LinearIterations", "Linear System", "")
|
||||
obj.addProperty("App::PropertyEnumeration", "LinearIterativeMethod", "Linear System", "")
|
||||
obj.addProperty("App::PropertyEnumeration", "LinearPreconditioning", "Linear System", "")
|
||||
obj.addProperty("App::PropertyEnumeration", "LinearSolverType", "Linear System", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"LinearSystemSolverDisabled",
|
||||
@@ -116,26 +73,16 @@ class Proxy(equation.Proxy):
|
||||
"Disable the linear system.\n"
|
||||
"Only use for special cases\n"
|
||||
"and consult the Elmer docs."
|
||||
)
|
||||
),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"LinearTolerance",
|
||||
"Linear System",
|
||||
"Linear preconditioning method"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"Stabilize",
|
||||
"Base",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"SteadyStateTolerance",
|
||||
"Steady State",
|
||||
""
|
||||
"Linear preconditioning method",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "Stabilize", "Base", "")
|
||||
obj.addProperty("App::PropertyFloat", "SteadyStateTolerance", "Steady State", "")
|
||||
|
||||
obj.BiCGstablDegree = (2, 2, 10, 1)
|
||||
obj.IdrsParameter = (2, 1, 10, 1)
|
||||
@@ -160,4 +107,5 @@ class Proxy(equation.Proxy):
|
||||
class ViewProxy(equation.ViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -34,8 +34,7 @@ from ... import equationbase
|
||||
|
||||
|
||||
def create(doc, name="Magnetodynamic"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.MagnetodynamicProxy):
|
||||
@@ -43,19 +42,19 @@ class Proxy(nonlinear.Proxy, equationbase.MagnetodynamicProxy):
|
||||
Type = "Fem::EquationElmerMagnetodynamic"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IsHarmonic",
|
||||
"Magnetodynamic",
|
||||
"If the magnetic source is harmonically driven"
|
||||
"If the magnetic source is harmonically driven",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFrequency",
|
||||
"AngularFrequency",
|
||||
"Magnetodynamic",
|
||||
"Frequency of the driving current"
|
||||
"Frequency of the driving current",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
@@ -63,129 +62,68 @@ class Proxy(nonlinear.Proxy, equationbase.MagnetodynamicProxy):
|
||||
"Magnetodynamic",
|
||||
"Must be True if basis functions for edge element interpolation\n"
|
||||
"are selected to be members of optimal edge element family\n"
|
||||
"or if second-order approximation is used."
|
||||
"or if second-order approximation is used.",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"QuadraticApproximation",
|
||||
"Magnetodynamic",
|
||||
"Enables second-order approximation of driving current"
|
||||
"Enables second-order approximation of driving current",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"StaticConductivity",
|
||||
"Magnetodynamic",
|
||||
"See Elmer models manual for info"
|
||||
"See Elmer models manual for info",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"FixInputCurrentDensity",
|
||||
"Magnetodynamic",
|
||||
"Ensures divergence-freeness of current density"
|
||||
"Ensures divergence-freeness of current density",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"AutomatedSourceProjectionBCs",
|
||||
"Magnetodynamic",
|
||||
"See Elmer models manual for info"
|
||||
"See Elmer models manual for info",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"UseLagrangeGauge",
|
||||
"Magnetodynamic",
|
||||
"See Elmer models manual for info"
|
||||
"See Elmer models manual for info",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"LagrangeGaugePenalizationCoefficient",
|
||||
"Magnetodynamic",
|
||||
"See Elmer models manual for info"
|
||||
"See Elmer models manual for info",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"UseTreeGauge",
|
||||
"Magnetodynamic",
|
||||
"See Elmer models manual for info\n"
|
||||
"Will be ignored if 'UsePiolaTransform' is True"
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"LinearSystemRefactorize",
|
||||
"Linear System",
|
||||
""
|
||||
"See Elmer models manual for info\nWill be ignored if 'UsePiolaTransform' is True",
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "LinearSystemRefactorize", "Linear System", "")
|
||||
|
||||
obj.IsHarmonic = False
|
||||
obj.AngularFrequency = 0
|
||||
obj.Priority = 10
|
||||
|
||||
# the post processor options
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateCurrentDensity",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElectricField",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElementalFields",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateHarmonicLoss",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateJouleHeating",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateMagneticFieldStrength",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateMaxwellStress",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalFields",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalForces",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalHeating",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"DiscontinuousBodies",
|
||||
"Results",
|
||||
""
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "CalculateCurrentDensity", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElectricField", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElementalFields", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateHarmonicLoss", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateJouleHeating", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateMagneticFieldStrength", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateMaxwellStress", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalFields", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalForces", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalHeating", "Results", "")
|
||||
obj.addProperty("App::PropertyBool", "DiscontinuousBodies", "Results", "")
|
||||
obj.CalculateCurrentDensity = False
|
||||
obj.CalculateElectricField = False
|
||||
# FIXME: at the moment FreeCAD's post processor cannot display elementary field
|
||||
@@ -204,4 +142,5 @@ class Proxy(nonlinear.Proxy, equationbase.MagnetodynamicProxy):
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.MagnetodynamicViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -34,8 +34,7 @@ from ... import equationbase
|
||||
|
||||
|
||||
def create(doc, name="Magnetodynamic2D"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.Magnetodynamic2DProxy):
|
||||
@@ -43,85 +42,37 @@ class Proxy(nonlinear.Proxy, equationbase.Magnetodynamic2DProxy):
|
||||
Type = "Fem::EquationElmerMagnetodynamic2D"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"IsHarmonic",
|
||||
"Magnetodynamic2D",
|
||||
"If the magnetic source is harmonically driven"
|
||||
"If the magnetic source is harmonically driven",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFrequency",
|
||||
"AngularFrequency",
|
||||
"Magnetodynamic2D",
|
||||
"Frequency of the driving current"
|
||||
"Frequency of the driving current",
|
||||
)
|
||||
obj.IsHarmonic = False
|
||||
obj.AngularFrequency = 0
|
||||
obj.Priority = 10
|
||||
|
||||
# the post processor options
|
||||
obj.addProperty("App::PropertyBool", "CalculateCurrentDensity", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElectricField", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateElementalFields", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateHarmonicLoss", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateJouleHeating", "Magnetodynamic2D", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateCurrentDensity",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElectricField",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateElementalFields",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateHarmonicLoss",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateJouleHeating",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateMagneticFieldStrength",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateMaxwellStress",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalFields",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalForces",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalHeating",
|
||||
"Magnetodynamic2D",
|
||||
""
|
||||
"App::PropertyBool", "CalculateMagneticFieldStrength", "Magnetodynamic2D", ""
|
||||
)
|
||||
obj.addProperty("App::PropertyBool", "CalculateMaxwellStress", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalFields", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalForces", "Magnetodynamic2D", "")
|
||||
obj.addProperty("App::PropertyBool", "CalculateNodalHeating", "Magnetodynamic2D", "")
|
||||
obj.CalculateCurrentDensity = False
|
||||
obj.CalculateElectricField = False
|
||||
# FIXME: at the moment FreeCAD's post processor cannot display elementary field
|
||||
@@ -139,4 +90,5 @@ class Proxy(nonlinear.Proxy, equationbase.Magnetodynamic2DProxy):
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.Magnetodynamic2DViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -92,15 +92,13 @@ class MgDyn2Dwriter:
|
||||
|
||||
def handleMagnetodynamic2DConstants(self):
|
||||
permeability = self.write.convert(
|
||||
self.write.constsdef["PermeabilityOfVacuum"],
|
||||
"M*L/(T^2*I^2)"
|
||||
self.write.constsdef["PermeabilityOfVacuum"], "M*L/(T^2*I^2)"
|
||||
)
|
||||
# we round in the following to get rid of numerical artifacts
|
||||
self.write.constant("Permeability Of Vacuum", round(permeability, 20))
|
||||
|
||||
permittivity = self.write.convert(
|
||||
self.write.constsdef["PermittivityOfVacuum"],
|
||||
"T^4*I^2/(L^3*M)"
|
||||
self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)"
|
||||
)
|
||||
self.write.constant("Permittivity Of Vacuum", round(permittivity, 20))
|
||||
|
||||
@@ -109,22 +107,19 @@ class MgDyn2Dwriter:
|
||||
for name in bodies:
|
||||
if self.write.getBodyMaterial(name) is None:
|
||||
raise general_writer.WriteError(
|
||||
"The body {} is not referenced in any material.\n\n".format(name)
|
||||
f"The body {name} is not referenced in any material.\n\n"
|
||||
)
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies())
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
if "ElectricalConductivity" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
raise general_writer.WriteError(
|
||||
"The electrical conductivity must be specified for all materials.\n\n"
|
||||
)
|
||||
if "RelativePermeability" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
raise general_writer.WriteError(
|
||||
"The relative permeability must be specified for all materials.\n\n"
|
||||
)
|
||||
@@ -132,15 +127,11 @@ class MgDyn2Dwriter:
|
||||
conductivity = self.write.convert(m["ElectricalConductivity"], "T^3*I^2/(L^3*M)")
|
||||
conductivity = round(conductivity, 10) # to get rid of numerical artifacts
|
||||
self.write.material(name, "Electric Conductivity", conductivity)
|
||||
self.write.material(
|
||||
name, "Relative Permeability",
|
||||
float(m["RelativePermeability"])
|
||||
)
|
||||
self.write.material(name, "Relative Permeability", float(m["RelativePermeability"]))
|
||||
# permittivity might be necessary for the post processor
|
||||
if "RelativePermittivity" in m:
|
||||
self.write.material(
|
||||
name, "Relative Permittivity",
|
||||
float(m["RelativePermittivity"])
|
||||
name, "Relative Permittivity", float(m["RelativePermittivity"])
|
||||
)
|
||||
|
||||
def _outputMagnetodynamic2DBodyForce(self, obj, name, equation):
|
||||
@@ -229,12 +220,11 @@ class MgDyn2Dwriter:
|
||||
def handleMagnetodynamic2DEquation(self, bodies, equation):
|
||||
for b in bodies:
|
||||
if equation.IsHarmonic and (equation.AngularFrequency == 0):
|
||||
raise general_writer.WriteError(
|
||||
"The angular frequency must not be zero.\n\n"
|
||||
)
|
||||
raise general_writer.WriteError("The angular frequency must not be zero.\n\n")
|
||||
self.write.equation(b, "Name", equation.Name)
|
||||
if equation.IsHarmonic:
|
||||
frequency = float(Units.Quantity(equation.AngularFrequency).Value)
|
||||
self.write.equation(b, "Angular Frequency", round(frequency, 6))
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -73,8 +73,9 @@ class MgDynwriter:
|
||||
if equation.UseLagrangeGauge is True:
|
||||
s["Use Lagrange Gauge"] = True
|
||||
if equation.LagrangeGaugePenalizationCoefficient != 0.0:
|
||||
s["Lagrange Gauge Penalization Coefficient"] = \
|
||||
s["Lagrange Gauge Penalization Coefficient"] = (
|
||||
equation.LagrangeGaugePenalizationCoefficient
|
||||
)
|
||||
if equation.UseTreeGauge is True:
|
||||
s["Use Tree Gauge"] = True
|
||||
return s
|
||||
@@ -117,15 +118,13 @@ class MgDynwriter:
|
||||
|
||||
def handleMagnetodynamicConstants(self):
|
||||
permeability = self.write.convert(
|
||||
self.write.constsdef["PermeabilityOfVacuum"],
|
||||
"M*L/(T^2*I^2)"
|
||||
self.write.constsdef["PermeabilityOfVacuum"], "M*L/(T^2*I^2)"
|
||||
)
|
||||
# we round in the following to get rid of numerical artifacts
|
||||
self.write.constant("Permeability Of Vacuum", round(permeability, 20))
|
||||
|
||||
permittivity = self.write.convert(
|
||||
self.write.constsdef["PermittivityOfVacuum"],
|
||||
"T^4*I^2/(L^3*M)"
|
||||
self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)"
|
||||
)
|
||||
self.write.constant("Permittivity Of Vacuum", round(permittivity, 20))
|
||||
|
||||
@@ -134,22 +133,19 @@ class MgDynwriter:
|
||||
for name in bodies:
|
||||
if self.write.getBodyMaterial(name) is None:
|
||||
raise general_writer.WriteError(
|
||||
"The body {} is not referenced in any material.\n\n".format(name)
|
||||
f"The body {name} is not referenced in any material.\n\n"
|
||||
)
|
||||
for obj in self.write.getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self.write.getAllBodies())
|
||||
refs = obj.References[0][1] if obj.References else self.write.getAllBodies()
|
||||
for name in (n for n in refs if n in bodies):
|
||||
if "ElectricalConductivity" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
raise general_writer.WriteError(
|
||||
"The electrical conductivity must be specified for all materials.\n\n"
|
||||
)
|
||||
if "RelativePermeability" not in m:
|
||||
Console.PrintMessage("m: {}\n".format(m))
|
||||
Console.PrintMessage(f"m: {m}\n")
|
||||
raise general_writer.WriteError(
|
||||
"The relative permeability must be specified for all materials.\n\n"
|
||||
)
|
||||
@@ -157,15 +153,11 @@ class MgDynwriter:
|
||||
conductivity = self.write.convert(m["ElectricalConductivity"], "T^3*I^2/(L^3*M)")
|
||||
conductivity = round(conductivity, 10) # to get rid of numerical artifacts
|
||||
self.write.material(name, "Electric Conductivity", conductivity)
|
||||
self.write.material(
|
||||
name, "Relative Permeability",
|
||||
float(m["RelativePermeability"])
|
||||
)
|
||||
self.write.material(name, "Relative Permeability", float(m["RelativePermeability"]))
|
||||
# permittivity might be necessary for the post processor
|
||||
if "RelativePermittivity" in m:
|
||||
self.write.material(
|
||||
name, "Relative Permittivity",
|
||||
float(m["RelativePermittivity"])
|
||||
name, "Relative Permittivity", float(m["RelativePermittivity"])
|
||||
)
|
||||
|
||||
def _outputMagnetodynamicBodyForce(self, obj, name, equation):
|
||||
@@ -235,7 +227,7 @@ class MgDynwriter:
|
||||
for obj in currentDensities:
|
||||
if obj.References:
|
||||
firstName = obj.References[0][1][0]
|
||||
firstName = firstName.rstrip('0123456789')
|
||||
firstName = firstName.rstrip("0123456789")
|
||||
if firstName == "Solid":
|
||||
for name in obj.References[0][1]:
|
||||
self._outputMagnetodynamicBodyForce(obj, name, equation)
|
||||
@@ -278,7 +270,7 @@ class MgDynwriter:
|
||||
for obj in potentials:
|
||||
if obj.References:
|
||||
firstName = obj.References[0][1][0]
|
||||
firstName = firstName.rstrip('0123456789')
|
||||
firstName = firstName.rstrip("0123456789")
|
||||
if firstName == "Solid":
|
||||
for name in obj.References[0][1]:
|
||||
# output only if potentiual is enabled and needed
|
||||
@@ -346,7 +338,7 @@ class MgDynwriter:
|
||||
for obj in currentDensities:
|
||||
if obj.References:
|
||||
firstName = obj.References[0][1][0]
|
||||
firstName = firstName.rstrip('0123456789')
|
||||
firstName = firstName.rstrip("0123456789")
|
||||
if firstName == "Face":
|
||||
for name in obj.References[0][1]:
|
||||
self._outputMagnetodynamicBndConditions(obj, name, equation)
|
||||
@@ -363,7 +355,7 @@ class MgDynwriter:
|
||||
for obj in potentials:
|
||||
if obj.References:
|
||||
firstName = obj.References[0][1][0]
|
||||
firstName = firstName.rstrip('0123456789')
|
||||
firstName = firstName.rstrip("0123456789")
|
||||
if firstName == "Face":
|
||||
for name in obj.References[0][1]:
|
||||
# output the FreeCAD label as comment
|
||||
@@ -373,4 +365,5 @@ class MgDynwriter:
|
||||
self._outputMagnetodynamicBndConditions(obj, name, equation)
|
||||
self.write.handled(obj)
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -40,32 +40,24 @@ from . import linear
|
||||
class Proxy(linear.Proxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"NonlinearIterations",
|
||||
"Nonlinear System",
|
||||
"Maximum number of iterations"
|
||||
"Maximum number of iterations",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"NonlinearNewtonAfterIterations",
|
||||
"Nonlinear System",
|
||||
""
|
||||
"",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"NonlinearNewtonAfterTolerance",
|
||||
"Nonlinear System",
|
||||
""
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"NonlinearTolerance",
|
||||
"Nonlinear System",
|
||||
""
|
||||
"App::PropertyFloat", "NonlinearNewtonAfterTolerance", "Nonlinear System", ""
|
||||
)
|
||||
obj.addProperty("App::PropertyFloat", "NonlinearTolerance", "Nonlinear System", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint",
|
||||
"RelaxationFactor",
|
||||
@@ -73,7 +65,7 @@ class Proxy(linear.Proxy):
|
||||
(
|
||||
"Value below 1.0 might be necessary to achieve convergence\n"
|
||||
"Typical values are in the range [0.3, 1.0]"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
obj.NonlinearIterations = (20, 1, int(1e6), 10)
|
||||
@@ -90,4 +82,5 @@ class Proxy(linear.Proxy):
|
||||
class ViewProxy(linear.ViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -78,10 +78,10 @@ _TYPE_STRING = "String"
|
||||
_TYPE_FILE = "File"
|
||||
_TYPE_VARIABLE = "Variable"
|
||||
|
||||
WARN = "\"Warn\""
|
||||
IGNORE = "\"Ignore\""
|
||||
ABORT = "\"Abort\""
|
||||
SILENT = "\"Silent\""
|
||||
WARN = '"Warn"'
|
||||
IGNORE = '"Ignore"'
|
||||
ABORT = '"Abort"'
|
||||
SILENT = '"Silent"'
|
||||
|
||||
|
||||
def createSection(name):
|
||||
@@ -104,7 +104,7 @@ def isValid(section):
|
||||
return section.name in _VALID_SECTIONS
|
||||
|
||||
|
||||
class Builder(object):
|
||||
class Builder:
|
||||
|
||||
_ACTIVE_SOLVERS = "Active Solvers"
|
||||
|
||||
@@ -191,7 +191,7 @@ class Builder(object):
|
||||
return iter(allSections)
|
||||
|
||||
|
||||
class Sif(object):
|
||||
class Sif:
|
||||
|
||||
_CHECK_KEYWORDS = "Check Keywords"
|
||||
_HEADER = "Header"
|
||||
@@ -238,7 +238,7 @@ class Sif(object):
|
||||
stream.write('"%s"' % value)
|
||||
|
||||
|
||||
class Section(object):
|
||||
class Section:
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@@ -274,7 +274,7 @@ class FileAttr(str):
|
||||
pass
|
||||
|
||||
|
||||
class _Writer(object):
|
||||
class _Writer:
|
||||
|
||||
def __init__(self, idManager, sections, stream):
|
||||
self._idMgr = idManager
|
||||
@@ -282,8 +282,7 @@ class _Writer(object):
|
||||
self._stream = stream
|
||||
|
||||
def write(self):
|
||||
sortedSections = sorted(
|
||||
self._sections, key=lambda s: s.priority, reverse=True)
|
||||
sortedSections = sorted(self._sections, key=lambda s: s.priority, reverse=True)
|
||||
for s in sortedSections:
|
||||
self._writeSection(s)
|
||||
self._stream.write(_NEWLINE)
|
||||
@@ -332,10 +331,7 @@ class _Writer(object):
|
||||
return next(it)
|
||||
|
||||
def _isCollection(self, data):
|
||||
return (
|
||||
not isinstance(data, str)
|
||||
and isinstance(data, collections.abc.Iterable)
|
||||
)
|
||||
return not isinstance(data, str) and isinstance(data, collections.abc.Iterable)
|
||||
|
||||
def _checkScalar(self, dataType):
|
||||
if issubclass(dataType, int):
|
||||
@@ -359,7 +355,7 @@ class _Writer(object):
|
||||
self._stream.write(_WHITESPACE)
|
||||
# check if we have a variable string
|
||||
if attrType is _TYPE_STRING:
|
||||
if data.startswith('Variable'):
|
||||
if data.startswith("Variable"):
|
||||
attrType = _TYPE_VARIABLE
|
||||
if attrType is not _TYPE_VARIABLE:
|
||||
self._stream.write(attrType)
|
||||
@@ -367,7 +363,7 @@ class _Writer(object):
|
||||
output = self._preprocess(data, type(data))
|
||||
# in case of a variable the output must be without the quatoation marks
|
||||
if attrType is _TYPE_VARIABLE:
|
||||
output = output.lstrip('\"')
|
||||
output = output.lstrip('"')
|
||||
# we cannot use rstrip because there are two subsequent " at the end
|
||||
output = output[:-1]
|
||||
self._stream.write(output)
|
||||
@@ -382,7 +378,7 @@ class _Writer(object):
|
||||
self._stream.write(_WHITESPACE)
|
||||
# check if we have a variable string
|
||||
if attrType is _TYPE_STRING:
|
||||
if data.startswith('Variable'):
|
||||
if data.startswith("Variable"):
|
||||
attrType = _TYPE_VARIABLE
|
||||
if attrType is not _TYPE_VARIABLE:
|
||||
self._stream.write(attrType)
|
||||
@@ -391,7 +387,7 @@ class _Writer(object):
|
||||
output = self._preprocess(val, type(val))
|
||||
# in case of a variable the output must be without the quatoation marks
|
||||
if attrType is _TYPE_VARIABLE:
|
||||
output = output.lstrip('\"')
|
||||
output = output.lstrip('"')
|
||||
# we cannot use rstrip because there are two subsequent " at the end
|
||||
output = output[:-1]
|
||||
self._stream.write(output)
|
||||
@@ -442,7 +438,7 @@ class _Writer(object):
|
||||
return self._getSifDataType(dataType)
|
||||
|
||||
|
||||
class _IdManager(object):
|
||||
class _IdManager:
|
||||
|
||||
def __init__(self, firstId=1):
|
||||
self._pool = dict()
|
||||
@@ -460,4 +456,5 @@ class _IdManager(object):
|
||||
self.setId(section)
|
||||
return self._ids[section]
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -50,16 +50,22 @@ from femtools import femutils
|
||||
if FreeCAD.GuiUp:
|
||||
import FemGui
|
||||
|
||||
COORDINATE_SYSTEM = ["Cartesian", "Cartesian 1D", "Cartesian 2D", "Cartesian 3D",
|
||||
"Polar 2D", "Polar 3D",
|
||||
"Cylindric", "Cylindric Symmetric",
|
||||
"Axi Symmetric"]
|
||||
COORDINATE_SYSTEM = [
|
||||
"Cartesian",
|
||||
"Cartesian 1D",
|
||||
"Cartesian 2D",
|
||||
"Cartesian 3D",
|
||||
"Polar 2D",
|
||||
"Polar 3D",
|
||||
"Cylindric",
|
||||
"Cylindric Symmetric",
|
||||
"Axi Symmetric",
|
||||
]
|
||||
SIMULATION_TYPE = ["Scanning", "Steady State", "Transient"]
|
||||
|
||||
|
||||
def create(doc, name="ElmerSolver"):
|
||||
return femutils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(solverbase.Proxy):
|
||||
@@ -80,14 +86,9 @@ class Proxy(solverbase.Proxy):
|
||||
}
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"CoordinateSystem",
|
||||
"Coordinate System",
|
||||
""
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "CoordinateSystem", "Coordinate System", "")
|
||||
obj.CoordinateSystem = COORDINATE_SYSTEM
|
||||
obj.CoordinateSystem = "Cartesian"
|
||||
|
||||
@@ -95,7 +96,7 @@ class Proxy(solverbase.Proxy):
|
||||
"App::PropertyIntegerConstraint",
|
||||
"BDFOrder",
|
||||
"Timestepping",
|
||||
"Order of time stepping method 'BDF'"
|
||||
"Order of time stepping method 'BDF'",
|
||||
)
|
||||
# according to the Elmer manual recommended is order 2
|
||||
# possible ranage is 1 - 5
|
||||
@@ -105,7 +106,7 @@ class Proxy(solverbase.Proxy):
|
||||
"App::PropertyIntegerList",
|
||||
"OutputIntervals",
|
||||
"Timestepping",
|
||||
"After how many time steps a result file is output"
|
||||
"After how many time steps a result file is output",
|
||||
)
|
||||
obj.OutputIntervals = [1]
|
||||
|
||||
@@ -113,10 +114,7 @@ class Proxy(solverbase.Proxy):
|
||||
"App::PropertyIntegerList",
|
||||
"TimestepIntervals",
|
||||
"Timestepping",
|
||||
(
|
||||
"List of times if 'Simulation Type'\n"
|
||||
"is either 'Scanning' or 'Transient'"
|
||||
)
|
||||
("List of times if 'Simulation Type'\nis either 'Scanning' or 'Transient'"),
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatList",
|
||||
@@ -125,19 +123,14 @@ class Proxy(solverbase.Proxy):
|
||||
(
|
||||
"List of time steps sizes if 'Simulation Type'\n"
|
||||
"is 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
|
||||
obj.TimestepIntervals = [100]
|
||||
obj.TimestepSizes = [0.1]
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"SimulationType",
|
||||
"Type",
|
||||
""
|
||||
)
|
||||
obj.addProperty("App::PropertyEnumeration", "SimulationType", "Type", "")
|
||||
obj.SimulationType = SIMULATION_TYPE
|
||||
obj.SimulationType = "Steady State"
|
||||
|
||||
@@ -145,7 +138,7 @@ class Proxy(solverbase.Proxy):
|
||||
"App::PropertyInteger",
|
||||
"SteadyStateMaxIterations",
|
||||
"Type",
|
||||
"Maximal steady state iterations"
|
||||
"Maximal steady state iterations",
|
||||
)
|
||||
obj.SteadyStateMaxIterations = 1
|
||||
|
||||
@@ -153,42 +146,26 @@ class Proxy(solverbase.Proxy):
|
||||
"App::PropertyInteger",
|
||||
"SteadyStateMinIterations",
|
||||
"Type",
|
||||
"Minimal steady state iterations"
|
||||
"Minimal steady state iterations",
|
||||
)
|
||||
obj.SteadyStateMinIterations = 0
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyLink",
|
||||
"ElmerResult",
|
||||
"Base",
|
||||
"",
|
||||
4 | 8
|
||||
)
|
||||
obj.addProperty("App::PropertyLink", "ElmerResult", "Base", "", 4 | 8)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkList",
|
||||
"ElmerTimeResults",
|
||||
"Base",
|
||||
"",
|
||||
4 | 8
|
||||
)
|
||||
obj.addProperty("App::PropertyLinkList", "ElmerTimeResults", "Base", "", 4 | 8)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyLink",
|
||||
"ElmerOutput",
|
||||
"Base",
|
||||
"",
|
||||
4 | 8
|
||||
)
|
||||
obj.addProperty("App::PropertyLink", "ElmerOutput", "Base", "", 4 | 8)
|
||||
|
||||
def createMachine(self, obj, directory, testmode=False):
|
||||
return run.Machine(
|
||||
solver=obj, directory=directory,
|
||||
solver=obj,
|
||||
directory=directory,
|
||||
check=tasks.Check(),
|
||||
prepare=tasks.Prepare(),
|
||||
solve=tasks.Solve(),
|
||||
results=tasks.Results(),
|
||||
testmode=testmode)
|
||||
testmode=testmode,
|
||||
)
|
||||
|
||||
def createEquation(self, doc, eqId):
|
||||
return self._EQUATIONS[eqId].create(doc)
|
||||
@@ -201,7 +178,7 @@ class Proxy(solverbase.Proxy):
|
||||
|
||||
def edit(self, directory):
|
||||
pattern = os.path.join(directory, "case.sif")
|
||||
FreeCAD.Console.PrintMessage("{}\n".format(pattern))
|
||||
FreeCAD.Console.PrintMessage(f"{pattern}\n")
|
||||
f = glob.glob(pattern)[0]
|
||||
FemGui.open(f)
|
||||
|
||||
@@ -212,4 +189,5 @@ class ViewProxy(solverbase.ViewProxy):
|
||||
def getIcon(self):
|
||||
return ":/icons/FEM_SolverElmer.svg"
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -47,7 +47,7 @@ class Check(run.Check):
|
||||
|
||||
def run(self):
|
||||
self.pushStatus("Checking analysis...\n")
|
||||
if (self.check_mesh_exists()):
|
||||
if self.check_mesh_exists():
|
||||
self.checkMeshType()
|
||||
self.check_material_exists()
|
||||
self.checkEquations()
|
||||
@@ -55,9 +55,7 @@ class Check(run.Check):
|
||||
def checkMeshType(self):
|
||||
mesh = membertools.get_single_member(self.analysis, "Fem::FemMeshObject")
|
||||
if not femutils.is_of_type(mesh, "Fem::FemMeshGmsh"):
|
||||
self.report.error(
|
||||
"Unsupported type of mesh. "
|
||||
"Mesh must be created with gmsh.")
|
||||
self.report.error("Unsupported type of mesh. Mesh must be created with gmsh.")
|
||||
self.fail()
|
||||
return False
|
||||
return True
|
||||
@@ -65,9 +63,7 @@ class Check(run.Check):
|
||||
def checkEquations(self):
|
||||
equations = self.solver.Group
|
||||
if not equations:
|
||||
self.report.error(
|
||||
"Solver has no equations. "
|
||||
"Add at least one equation.")
|
||||
self.report.error("Solver has no equations. Add at least one equation.")
|
||||
self.fail()
|
||||
|
||||
|
||||
@@ -77,14 +73,13 @@ class Prepare(run.Prepare):
|
||||
# TODO print working dir to report console
|
||||
self.pushStatus("Preparing input files...\n")
|
||||
num_cores = settings.get_cores("ElmerGrid")
|
||||
self.pushStatus("Number of CPU cores to be used for the solver run: {}\n"
|
||||
.format(num_cores))
|
||||
self.pushStatus(f"Number of CPU cores to be used for the solver run: {num_cores}\n")
|
||||
if self.testmode:
|
||||
# test mode: neither gmsh, nor elmergrid nor elmersolver binaries needed
|
||||
FreeCAD.Console.PrintMessage("Machine testmode: {}\n".format(self.testmode))
|
||||
FreeCAD.Console.PrintMessage(f"Machine testmode: {self.testmode}\n")
|
||||
w = writer.Writer(self.solver, self.directory, True)
|
||||
else:
|
||||
FreeCAD.Console.PrintLog("Machine testmode: {}\n".format(self.testmode))
|
||||
FreeCAD.Console.PrintLog(f"Machine testmode: {self.testmode}\n")
|
||||
w = writer.Writer(self.solver, self.directory)
|
||||
try:
|
||||
w.write_solver_input()
|
||||
@@ -93,7 +88,7 @@ class Prepare(run.Prepare):
|
||||
except writer.WriteError as e:
|
||||
self.report.error(str(e))
|
||||
self.fail()
|
||||
except IOError:
|
||||
except OSError:
|
||||
self.report.error("Can't access working directory.")
|
||||
self.fail()
|
||||
|
||||
@@ -124,11 +119,10 @@ class Solve(run.Solve):
|
||||
solvpath = os.path.split(binary)[0]
|
||||
if os.path.isdir(solvpath):
|
||||
os.environ["ELMER_HOME"] = solvpath
|
||||
os.environ["LD_LIBRARY_PATH"] = "$LD_LIBRARY_PATH:{}/modules".format(solvpath)
|
||||
os.environ["LD_LIBRARY_PATH"] = f"$LD_LIBRARY_PATH:{solvpath}/modules"
|
||||
# different call depending if with multithreading or not
|
||||
num_cores = settings.get_cores("ElmerSolver")
|
||||
self.pushStatus("Number of CPU cores to be used for the solver run: {}\n"
|
||||
.format(num_cores))
|
||||
self.pushStatus(f"Number of CPU cores to be used for the solver run: {num_cores}\n")
|
||||
args = []
|
||||
if num_cores > 1:
|
||||
if system() != "Windows":
|
||||
@@ -143,14 +137,11 @@ class Solve(run.Solve):
|
||||
cwd=self.directory,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
startupinfo=femutils.startProgramInfo("hide")
|
||||
startupinfo=femutils.startProgramInfo("hide"),
|
||||
)
|
||||
else:
|
||||
self._process = subprocess.Popen(
|
||||
args,
|
||||
cwd=self.directory,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
args, cwd=self.directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
self.signalAbort.add(self._process.terminate)
|
||||
output = self._observeSolver(self._process)
|
||||
@@ -172,7 +163,8 @@ class Solve(run.Solve):
|
||||
|
||||
def _createOutput(self):
|
||||
self.solver.ElmerOutput = self.analysis.Document.addObject(
|
||||
"App::TextDocument", self.solver.Name + "Output")
|
||||
"App::TextDocument", self.solver.Name + "Output"
|
||||
)
|
||||
self.solver.ElmerOutput.Label = self.solver.Label + "Output"
|
||||
# App::TextDocument has no Attribute ReadOnly
|
||||
# TODO check if the attribute has been removed from App::TextDocument
|
||||
@@ -194,11 +186,7 @@ class Solve(run.Solve):
|
||||
FrequencyList = []
|
||||
for line in OutputList:
|
||||
LineList = line.split(" ")
|
||||
if (
|
||||
len(LineList) > 1
|
||||
and LineList[0] == "EigenSolve:"
|
||||
and LineList[1] == "Computed"
|
||||
):
|
||||
if len(LineList) > 1 and LineList[0] == "EigenSolve:" and LineList[1] == "Computed":
|
||||
# we found a result and take now the next LineList[2] lines
|
||||
modeCount = int(LineList[2])
|
||||
modeNumber = modeCount
|
||||
@@ -219,9 +207,7 @@ class Solve(run.Solve):
|
||||
# now we can perform the calculation
|
||||
eigenFreq = cmath.sqrt(eigenFreq) / (2 * cmath.pi)
|
||||
# create an output line
|
||||
FrequencyList.append(
|
||||
"Mode {}: {} Hz".format(modeNumber - modeCount + 1, eigenFreq.real)
|
||||
)
|
||||
FrequencyList.append(f"Mode {modeNumber - modeCount + 1}: {eigenFreq.real} Hz")
|
||||
modeCount = modeCount - 1
|
||||
if modeNumber > 0:
|
||||
# push the results and append to output
|
||||
@@ -274,7 +260,8 @@ class Results(run.Results):
|
||||
|
||||
def _createResults(self):
|
||||
self.solver.ElmerResult = self.analysis.Document.addObject(
|
||||
"Fem::FemPostPipeline", self.solver.Name + "Result")
|
||||
"Fem::FemPostPipeline", self.solver.Name + "Result"
|
||||
)
|
||||
self.solver.ElmerResult.Label = self.solver.ElmerResult.Name
|
||||
self.solver.ElmerResult.ViewObject.SelectionStyle = "BoundBox"
|
||||
self.analysis.addObject(self.solver.ElmerResult)
|
||||
@@ -290,7 +277,7 @@ class Results(run.Results):
|
||||
self.pushStatus("\nNo result file was created.\n")
|
||||
self.fail()
|
||||
return
|
||||
pvdFile = open(pvdFilePath, "r")
|
||||
pvdFile = open(pvdFilePath)
|
||||
# read all lines
|
||||
pvdContent = pvdFile.readlines()
|
||||
# skip header and footer line and evaluate all lines
|
||||
@@ -299,7 +286,7 @@ class Results(run.Results):
|
||||
# so .split("\"") gives as 2nd the time and as 7th the filename
|
||||
for i in range(0, len(pvdContent) - 2):
|
||||
# get time
|
||||
lineArray = pvdContent[i + 1].split("\"")
|
||||
lineArray = pvdContent[i + 1].split('"')
|
||||
time = float(lineArray[1])
|
||||
filename = os.path.join(self.directory, lineArray[7])
|
||||
if os.path.isfile(filename):
|
||||
@@ -317,7 +304,7 @@ class Results(run.Results):
|
||||
# but not the shape and bar coloring
|
||||
self.solver.ElmerTimeResults[i].ViewObject.updateColorBars()
|
||||
else:
|
||||
self.pushStatus("\nResult file for time {} is missing.\n".format(time))
|
||||
self.pushStatus(f"\nResult file for time {time} is missing.\n")
|
||||
self.fail()
|
||||
return
|
||||
self.solver.Document.recompute()
|
||||
@@ -328,9 +315,7 @@ class Results(run.Results):
|
||||
# FreeCAD would replaces dots in object names with underscores, thus do the same
|
||||
newName = self.solver.Name + "_" + str(time).replace(".", "_") + "_" + "Result"
|
||||
if counter > len(self.solver.ElmerTimeResults):
|
||||
pipeline = self.analysis.Document.addObject(
|
||||
"Fem::FemPostPipeline", newName
|
||||
)
|
||||
pipeline = self.analysis.Document.addObject("Fem::FemPostPipeline", newName)
|
||||
# App::PropertyLinkList does not support append
|
||||
# thus we have to use a temporary list to append
|
||||
tmplist = self.solver.ElmerTimeResults
|
||||
@@ -343,9 +328,7 @@ class Results(run.Results):
|
||||
# store current list before removing object since object removal will automatically
|
||||
# remove entry from self.solver.ElmerTimeResults
|
||||
tmplist = self.solver.ElmerTimeResults
|
||||
self.analysis.Document.removeObject(
|
||||
self.solver.ElmerTimeResults[counter - 1].Name
|
||||
)
|
||||
self.analysis.Document.removeObject(self.solver.ElmerTimeResults[counter - 1].Name)
|
||||
tmplist[counter - 1] = self.analysis.Document.addObject(
|
||||
"Fem::FemPostPipeline", newName
|
||||
)
|
||||
@@ -354,10 +337,7 @@ class Results(run.Results):
|
||||
|
||||
def _finishTimeResults(self, time, counter):
|
||||
# we purposely use the decimal dot in the label
|
||||
self.solver.ElmerTimeResults[counter].Label = (
|
||||
"{}_{}_Result"
|
||||
.format(self.solver.Name, time)
|
||||
)
|
||||
self.solver.ElmerTimeResults[counter].Label = f"{self.solver.Name}_{time}_Result"
|
||||
self.solver.ElmerTimeResults[counter].ViewObject.OnTopWhenSelected = True
|
||||
self.analysis.addObject(self.solver.ElmerTimeResults[counter])
|
||||
# to assure the user sees something, set the default to Surface
|
||||
@@ -389,4 +369,5 @@ class Results(run.Results):
|
||||
self.fail()
|
||||
return postPath
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
@@ -63,25 +63,30 @@ _STARTINFO_NAME = "ELMERSOLVER_STARTINFO"
|
||||
_SIF_NAME = "case.sif"
|
||||
_ELMERGRID_IFORMAT = "8"
|
||||
_ELMERGRID_OFORMAT = "2"
|
||||
_COORDS_NON_MAGNETO_2D = ["Polar 2D", "Polar 3D", "Cartesian 3D",
|
||||
"Cylindric", "Cylindric Symmetric"]
|
||||
_COORDS_NON_MAGNETO_2D = [
|
||||
"Polar 2D",
|
||||
"Polar 3D",
|
||||
"Cartesian 3D",
|
||||
"Cylindric",
|
||||
"Cylindric Symmetric",
|
||||
]
|
||||
|
||||
|
||||
def _getAllSubObjects(obj):
|
||||
s = ["Solid" + str(i + 1) for i in range(len(obj.Shape.Solids))]
|
||||
s.extend(("Face" + str(i + 1) for i in range(len(obj.Shape.Faces))))
|
||||
s.extend(("Edge" + str(i + 1) for i in range(len(obj.Shape.Edges))))
|
||||
s.extend(("Vertex" + str(i + 1) for i in range(len(obj.Shape.Vertexes))))
|
||||
s.extend("Face" + str(i + 1) for i in range(len(obj.Shape.Faces)))
|
||||
s.extend("Edge" + str(i + 1) for i in range(len(obj.Shape.Edges)))
|
||||
s.extend("Vertex" + str(i + 1) for i in range(len(obj.Shape.Vertexes)))
|
||||
return s
|
||||
|
||||
|
||||
class Writer(object):
|
||||
class Writer:
|
||||
|
||||
def __init__(self, solver, directory, testmode=False):
|
||||
self.analysis = solver.getParentGroup()
|
||||
self.solver = solver
|
||||
self.directory = directory
|
||||
Console.PrintMessage("Write elmer input files to: {}\n".format(self.directory))
|
||||
Console.PrintMessage(f"Write elmer input files to: {self.directory}\n")
|
||||
self.testmode = testmode
|
||||
self._usedVarNames = set()
|
||||
self._builder = sifio.Builder()
|
||||
@@ -184,8 +189,9 @@ class Writer(object):
|
||||
Console.PrintMessage(
|
||||
"Unit schema: {} not supported by Elmer writer. "
|
||||
"The FreeCAD standard unit schema mm/kg/s is used. "
|
||||
"Elmer sif-file writing is done in Standard FreeCAD units.\n"
|
||||
.format(Units.listSchemas(self.unit_schema))
|
||||
"Elmer sif-file writing is done in Standard FreeCAD units.\n".format(
|
||||
Units.listSchemas(self.unit_schema)
|
||||
)
|
||||
)
|
||||
|
||||
def getFromUi(self, value, unit, outputDim):
|
||||
@@ -216,8 +222,7 @@ class Writer(object):
|
||||
self._exportToUnv(groups, mesh, unvPath)
|
||||
if self.testmode:
|
||||
Console.PrintMessage(
|
||||
"Solver Elmer testmode, ElmerGrid will not be used. "
|
||||
"It might not be installed.\n"
|
||||
"Solver Elmer testmode, ElmerGrid will not be used. It might not be installed.\n"
|
||||
)
|
||||
else:
|
||||
binary = settings.get_binary("ElmerGrid")
|
||||
@@ -226,29 +231,23 @@ class Writer(object):
|
||||
raise WriteError("Could not find ElmerGrid binary.")
|
||||
# for multithreading we first need a normal mesh creation run
|
||||
# then a second to split the mesh into the number of used cores
|
||||
argsBasic = [binary,
|
||||
_ELMERGRID_IFORMAT,
|
||||
_ELMERGRID_OFORMAT,
|
||||
unvPath]
|
||||
argsBasic = [binary, _ELMERGRID_IFORMAT, _ELMERGRID_OFORMAT, unvPath]
|
||||
args = argsBasic
|
||||
args.extend(["-out", self.directory])
|
||||
if system() == "Windows":
|
||||
subprocess.call(
|
||||
args,
|
||||
stdout=subprocess.DEVNULL,
|
||||
startupinfo=femutils.startProgramInfo("hide")
|
||||
args, stdout=subprocess.DEVNULL, startupinfo=femutils.startProgramInfo("hide")
|
||||
)
|
||||
else:
|
||||
subprocess.call(args, stdout=subprocess.DEVNULL)
|
||||
if num_cores > 1:
|
||||
args = argsBasic
|
||||
args.extend(["-partdual", "-metiskway", str(num_cores),
|
||||
"-out", self.directory])
|
||||
args.extend(["-partdual", "-metiskway", str(num_cores), "-out", self.directory])
|
||||
if system() == "Windows":
|
||||
subprocess.call(
|
||||
args,
|
||||
stdout=subprocess.DEVNULL,
|
||||
startupinfo=femutils.startProgramInfo("hide")
|
||||
startupinfo=femutils.startProgramInfo("hide"),
|
||||
)
|
||||
else:
|
||||
subprocess.call(args, stdout=subprocess.DEVNULL)
|
||||
@@ -281,10 +280,10 @@ class Writer(object):
|
||||
tools.write_geo()
|
||||
if self.testmode:
|
||||
Console.PrintMessage(
|
||||
"Solver Elmer testmode, Gmsh will not be used. "
|
||||
"It might not be installed.\n"
|
||||
"Solver Elmer testmode, Gmsh will not be used. It might not be installed.\n"
|
||||
)
|
||||
import shutil
|
||||
|
||||
shutil.copyfile(geoPath, os.path.join(self.directory, "group_mesh.geo"))
|
||||
else:
|
||||
tools.get_gmsh_command()
|
||||
@@ -307,14 +306,13 @@ class Writer(object):
|
||||
permittivity = float(objs[0].VacuumPermittivity.getValueAs("F/m"))
|
||||
# since the base unit of FC is in mm, we must scale it to get plain SI
|
||||
permittivity = permittivity * 1e-9
|
||||
Console.PrintLog("Overwriting vacuum permittivity with: {}\n".format(permittivity))
|
||||
Console.PrintLog(f"Overwriting vacuum permittivity with: {permittivity}\n")
|
||||
self.constsdef["PermittivityOfVacuum"] = "{} {}".format(permittivity, "F/m")
|
||||
self.handled(objs[0])
|
||||
elif len(objs) > 1:
|
||||
Console.PrintError(
|
||||
"More than one permittivity constant overwriting objects ({} objs). "
|
||||
"The permittivity constant overwriting is ignored.\n"
|
||||
.format(len(objs))
|
||||
"The permittivity constant overwriting is ignored.\n".format(len(objs))
|
||||
)
|
||||
|
||||
def _handleSimulation(self):
|
||||
@@ -336,18 +334,9 @@ class Writer(object):
|
||||
self._simulation("Coordinate Scaling", 0.001)
|
||||
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("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("BDF Order", self.solver.BDFOrder)
|
||||
self._simulation("Output Intervals", self.solver.OutputIntervals)
|
||||
self._simulation("Timestep Intervals", self.solver.TimestepIntervals)
|
||||
@@ -359,10 +348,7 @@ class Writer(object):
|
||||
# updates older simulations
|
||||
if not hasattr(self.solver, "CoordinateSystem"):
|
||||
solver.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"CoordinateSystem",
|
||||
"Coordinate System",
|
||||
""
|
||||
"App::PropertyEnumeration", "CoordinateSystem", "Coordinate System", ""
|
||||
)
|
||||
solver.CoordinateSystem = solverClass.COORDINATE_SYSTEM
|
||||
solver.CoordinateSystem = "Cartesian"
|
||||
@@ -371,32 +357,21 @@ class Writer(object):
|
||||
"App::PropertyIntegerConstraint",
|
||||
"BDFOrder",
|
||||
"Timestepping",
|
||||
"Order of time stepping method 'BDF'"
|
||||
"Order of time stepping method 'BDF'",
|
||||
)
|
||||
solver.BDFOrder = (2, 1, 5, 1)
|
||||
if not hasattr(self.solver, "ElmerTimeResults"):
|
||||
solver.addProperty(
|
||||
"App::PropertyLinkList",
|
||||
"ElmerTimeResults",
|
||||
"Base",
|
||||
"",
|
||||
4 | 8
|
||||
)
|
||||
solver.addProperty("App::PropertyLinkList", "ElmerTimeResults", "Base", "", 4 | 8)
|
||||
if not hasattr(self.solver, "OutputIntervals"):
|
||||
solver.addProperty(
|
||||
"App::PropertyIntegerList",
|
||||
"OutputIntervals",
|
||||
"Timestepping",
|
||||
"After how many time steps a result file is output"
|
||||
"After how many time steps a result file is output",
|
||||
)
|
||||
solver.OutputIntervals = [1]
|
||||
if not hasattr(self.solver, "SimulationType"):
|
||||
solver.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"SimulationType",
|
||||
"Type",
|
||||
""
|
||||
)
|
||||
solver.addProperty("App::PropertyEnumeration", "SimulationType", "Type", "")
|
||||
solver.SimulationType = solverClass.SIMULATION_TYPE
|
||||
solver.SimulationType = "Steady State"
|
||||
if not hasattr(self.solver, "TimestepIntervals"):
|
||||
@@ -407,7 +382,7 @@ class Writer(object):
|
||||
(
|
||||
"List of maximum optimization rounds if 'Simulation Type'\n"
|
||||
"is either 'Scanning' or 'Transient'"
|
||||
)
|
||||
),
|
||||
)
|
||||
solver.TimestepIntervals = [100]
|
||||
if not hasattr(self.solver, "TimestepSizes"):
|
||||
@@ -418,7 +393,7 @@ class Writer(object):
|
||||
(
|
||||
"List of time steps of optimization if 'Simulation Type'\n"
|
||||
"is either 'Scanning' or 'Transient'"
|
||||
)
|
||||
),
|
||||
)
|
||||
solver.TimestepSizes = [0.1]
|
||||
|
||||
@@ -622,8 +597,9 @@ class Writer(object):
|
||||
raise WriteError(
|
||||
"The coordinate setting '{}'\n is not "
|
||||
"supported by the equation 'Magnetodynamic2D'.\n\n"
|
||||
"Possible is:\n'Cartesian 2D' or 'Axi Symmetric'"
|
||||
.format(self.solver.CoordinateSystem)
|
||||
"Possible is:\n'Cartesian 2D' or 'Axi Symmetric'".format(
|
||||
self.solver.CoordinateSystem
|
||||
)
|
||||
)
|
||||
|
||||
solverSection = MgDyn2D.getMagnetodynamic2DSolver(equation)
|
||||
@@ -661,14 +637,14 @@ class Writer(object):
|
||||
"Disable the linear system.\n"
|
||||
"Only use for special cases\n"
|
||||
"and consult the Elmer docs."
|
||||
)
|
||||
),
|
||||
)
|
||||
if not hasattr(equation, "IdrsParameter"):
|
||||
equation.addProperty(
|
||||
"App::PropertyIntegerConstraint",
|
||||
"IdrsParameter",
|
||||
"Linear System",
|
||||
"Parameter for iterative method 'Idrs'"
|
||||
"Parameter for iterative method 'Idrs'",
|
||||
)
|
||||
equation.IdrsParameter = (2, 1, 10, 1)
|
||||
|
||||
@@ -682,25 +658,17 @@ class Writer(object):
|
||||
if equation.LinearSystemSolverDisabled is True:
|
||||
s["Linear System Solver Disabled"] = equation.LinearSystemSolverDisabled
|
||||
if equation.LinearSolverType == "Direct":
|
||||
s["Linear System Direct Method"] = \
|
||||
equation.LinearDirectMethod
|
||||
s["Linear System Direct Method"] = equation.LinearDirectMethod
|
||||
elif equation.LinearSolverType == "Iterative":
|
||||
s["Linear System Iterative Method"] = \
|
||||
equation.LinearIterativeMethod
|
||||
s["Linear System Iterative Method"] = equation.LinearIterativeMethod
|
||||
if equation.LinearIterativeMethod == "BiCGStabl":
|
||||
s["BiCGstabl polynomial degree"] = \
|
||||
equation.BiCGstablDegree
|
||||
s["BiCGstabl polynomial degree"] = equation.BiCGstablDegree
|
||||
if equation.LinearIterativeMethod == "Idrs":
|
||||
s["Idrs Parameter"] = \
|
||||
equation.IdrsParameter
|
||||
s["Linear System Max Iterations"] = \
|
||||
equation.LinearIterations
|
||||
s["Linear System Convergence Tolerance"] = \
|
||||
equation.LinearTolerance
|
||||
s["Linear System Preconditioning"] = \
|
||||
equation.LinearPreconditioning
|
||||
s["Steady State Convergence Tolerance"] = \
|
||||
equation.SteadyStateTolerance
|
||||
s["Idrs Parameter"] = equation.IdrsParameter
|
||||
s["Linear System Max Iterations"] = equation.LinearIterations
|
||||
s["Linear System Convergence Tolerance"] = equation.LinearTolerance
|
||||
s["Linear System Preconditioning"] = equation.LinearPreconditioning
|
||||
s["Steady State Convergence Tolerance"] = equation.SteadyStateTolerance
|
||||
s["Linear System Abort Not Converged"] = False
|
||||
s["Linear System Residual Output"] = 1
|
||||
s["Linear System Precondition Recompute"] = 1
|
||||
@@ -711,8 +679,7 @@ class Writer(object):
|
||||
equation.setExpression("NonlinearTolerance", str(equation.NonlinearTolerance))
|
||||
if self._hasExpression(equation) != equation.NonlinearNewtonAfterTolerance:
|
||||
equation.setExpression(
|
||||
"NonlinearNewtonAfterTolerance",
|
||||
str(equation.NonlinearNewtonAfterTolerance)
|
||||
"NonlinearNewtonAfterTolerance", str(equation.NonlinearNewtonAfterTolerance)
|
||||
)
|
||||
|
||||
def createNonlinearSolver(self, equation):
|
||||
@@ -721,16 +688,11 @@ class Writer(object):
|
||||
# write the linear solver
|
||||
s = self.createLinearSolver(equation)
|
||||
# write the nonlinear solver
|
||||
s["Nonlinear System Max Iterations"] = \
|
||||
equation.NonlinearIterations
|
||||
s["Nonlinear System Convergence Tolerance"] = \
|
||||
equation.NonlinearTolerance
|
||||
s["Nonlinear System Relaxation Factor"] = \
|
||||
equation.RelaxationFactor
|
||||
s["Nonlinear System Newton After Iterations"] = \
|
||||
equation.NonlinearNewtonAfterIterations
|
||||
s["Nonlinear System Newton After Tolerance"] = \
|
||||
equation.NonlinearNewtonAfterTolerance
|
||||
s["Nonlinear System Max Iterations"] = equation.NonlinearIterations
|
||||
s["Nonlinear System Convergence Tolerance"] = equation.NonlinearTolerance
|
||||
s["Nonlinear System Relaxation Factor"] = equation.RelaxationFactor
|
||||
s["Nonlinear System Newton After Iterations"] = equation.NonlinearNewtonAfterIterations
|
||||
s["Nonlinear System Newton After Tolerance"] = equation.NonlinearNewtonAfterTolerance
|
||||
return s
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
@@ -777,7 +739,7 @@ class Writer(object):
|
||||
return density
|
||||
|
||||
def _hasExpression(self, equation):
|
||||
for (obj, exp) in equation.ExpressionEngine:
|
||||
for obj, exp in equation.ExpressionEngine:
|
||||
if obj == equation:
|
||||
return exp
|
||||
return None
|
||||
@@ -824,10 +786,7 @@ class Writer(object):
|
||||
# To get it back in the original size we let Elmer scale it back
|
||||
s["Coordinate Scaling Revert"] = True
|
||||
s["Equation"] = "ResultOutput"
|
||||
if (
|
||||
self.solver.SimulationType == "Scanning"
|
||||
or self.solver.SimulationType == "Transient"
|
||||
):
|
||||
if self.solver.SimulationType == "Scanning" or self.solver.SimulationType == "Transient":
|
||||
# we must execute the post solver every time we output a result
|
||||
# therefore we must use the same as self.solver.OutputIntervals
|
||||
s["Exec Intervals"] = self.solver.OutputIntervals
|
||||
@@ -892,4 +851,5 @@ class Writer(object):
|
||||
class WriteError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
Reference in New Issue
Block a user