FEM: code formating, max line length < 100, fem solver

This commit is contained in:
Bernd Hahnebach
2019-05-20 12:31:34 +02:00
parent 070277c210
commit 508a65f115
10 changed files with 992 additions and 294 deletions

View File

@@ -58,16 +58,27 @@ class Proxy(solverbase.Proxy):
super(Proxy, self).__init__(obj)
obj.Proxy = self
# fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") # not needed ATM
# not needed ATM
# fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
obj.addProperty("App::PropertyEnumeration", "AnalysisType", "Fem", "Type of the analysis")
obj.addProperty(
"App::PropertyEnumeration",
"AnalysisType",
"Fem",
"Type of the analysis"
)
obj.AnalysisType = ANALYSIS_TYPES
analysis_type = ccx_prefs.GetInt("AnalysisType", 0)
obj.AnalysisType = ANALYSIS_TYPES[analysis_type]
choices_geom_nonlinear = ["linear", "nonlinear"]
obj.addProperty("App::PropertyEnumeration", "GeometricalNonlinearity", "Fem", "Set geometrical nonlinearity")
obj.addProperty(
"App::PropertyEnumeration",
"GeometricalNonlinearity",
"Fem",
"Set geometrical nonlinearity"
)
obj.GeometricalNonlinearity = choices_geom_nonlinear
nonlinear_geom = ccx_prefs.GetBool("NonlinearGeometry", False)
if nonlinear_geom is True:
@@ -76,43 +87,93 @@ class Proxy(solverbase.Proxy):
obj.GeometricalNonlinearity = choices_geom_nonlinear[0] # linear
choices_material_nonlinear = ["linear", "nonlinear"]
obj.addProperty("App::PropertyEnumeration", "MaterialNonlinearity", "Fem", "Set material nonlinearity (needs geometrical nonlinearity)")
obj.addProperty(
"App::PropertyEnumeration",
"MaterialNonlinearity",
"Fem",
"Set material nonlinearity (needs geometrical nonlinearity)"
)
obj.MaterialNonlinearity = choices_material_nonlinear
obj.MaterialNonlinearity = choices_material_nonlinear[0]
obj.addProperty("App::PropertyIntegerConstraint", "EigenmodesCount", "Fem", "Number of modes for frequency calculations")
obj.addProperty(
"App::PropertyIntegerConstraint",
"EigenmodesCount",
"Fem",
"Number of modes for frequency calculations"
)
noe = ccx_prefs.GetInt("EigenmodesCount", 10)
obj.EigenmodesCount = (noe, 1, 100, 1)
obj.addProperty("App::PropertyFloatConstraint", "EigenmodeLowLimit", "Fem", "Low frequency limit for eigenmode calculations")
obj.addProperty(
"App::PropertyFloatConstraint",
"EigenmodeLowLimit",
"Fem",
"Low frequency limit for eigenmode calculations"
)
ell = ccx_prefs.GetFloat("EigenmodeLowLimit", 0.0)
obj.EigenmodeLowLimit = (ell, 0.0, 1000000.0, 10000.0)
obj.addProperty("App::PropertyFloatConstraint", "EigenmodeHighLimit", "Fem", "High frequency limit for eigenmode calculations")
obj.addProperty(
"App::PropertyFloatConstraint",
"EigenmodeHighLimit",
"Fem",
"High frequency limit for eigenmode calculations"
)
ehl = ccx_prefs.GetFloat("EigenmodeHighLimit", 1000000.0)
obj.EigenmodeHighLimit = (ehl, 0.0, 1000000.0, 10000.0)
obj.addProperty("App::PropertyIntegerConstraint", "IterationsThermoMechMaximum", "Fem", "Maximum Number of thermo mechanical iterations in each time step before stopping jobs")
obj.addProperty(
"App::PropertyIntegerConstraint",
"IterationsThermoMechMaximum",
"Fem",
"Maximum Number of thermo mechanical iterations in each time step before stopping job"
)
niter = ccx_prefs.GetInt("AnalysisMaxIterations", 200)
obj.IterationsThermoMechMaximum = niter
obj.addProperty("App::PropertyFloatConstraint", "TimeInitialStep", "Fem", "Initial time steps")
obj.addProperty(
"App::PropertyFloatConstraint",
"TimeInitialStep",
"Fem",
"Initial time steps"
)
ini = ccx_prefs.GetFloat("AnalysisTimeInitialStep", 1.0)
obj.TimeInitialStep = ini
obj.addProperty("App::PropertyFloatConstraint", "TimeEnd", "Fem", "End time analysis")
obj.addProperty(
"App::PropertyFloatConstraint",
"TimeEnd",
"Fem",
"End time analysis"
)
eni = ccx_prefs.GetFloat("AnalysisTime", 1.0)
obj.TimeEnd = eni
obj.addProperty("App::PropertyBool", "ThermoMechSteadyState", "Fem", "Choose between steady state thermo mech or transient thermo mech analysis")
obj.addProperty(
"App::PropertyBool",
"ThermoMechSteadyState",
"Fem",
"Choose between steady state thermo mech or transient thermo mech analysis"
)
sted = ccx_prefs.GetBool("StaticAnalysis", True)
obj.ThermoMechSteadyState = sted
obj.addProperty("App::PropertyBool", "IterationsControlParameterTimeUse", "Fem", "Use the user defined time incrementation control parameter")
obj.addProperty(
"App::PropertyBool",
"IterationsControlParameterTimeUse",
"Fem",
"Use the user defined time incrementation control parameter"
)
use_non_ccx_iterations_param = ccx_prefs.GetInt("UseNonCcxIterationParam", False)
obj.IterationsControlParameterTimeUse = use_non_ccx_iterations_param
obj.addProperty("App::PropertyBool", "SplitInputWriter", "Fem", "Split writing of ccx input file")
obj.addProperty(
"App::PropertyBool",
"SplitInputWriter",
"Fem",
"Split writing of ccx input file"
)
split = ccx_prefs.GetBool("SplitInputWriter", False)
obj.SplitInputWriter = split
@@ -138,28 +199,88 @@ class Proxy(solverbase.Proxy):
'D_D': 1.5,
'W_G': None}
p = ccx_default_time_incrementation_control_parameter
p_iter = '{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}'.format(p['I_0'], p['I_R'], p['I_P'], p['I_C'], p['I_L'], p['I_G'], '', p['I_A'], '', '')
p_cutb = '{0},{1},{2},{3},{4},{5},{6},{7}'.format(p['D_f'], p['D_C'], p['D_B'], p['D_A'], '', '', p['D_D'], '')
obj.addProperty("App::PropertyString", "IterationsControlParameterIter", "Fem", "User defined time incrementation iterations control parameter")
p_iter = '{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}'.format(
p['I_0'],
p['I_R'],
p['I_P'],
p['I_C'],
p['I_L'],
p['I_G'],
'',
p['I_A'],
'',
''
)
p_cutb = '{0},{1},{2},{3},{4},{5},{6},{7}'.format(
p['D_f'],
p['D_C'],
p['D_B'],
p['D_A'],
'',
'',
p['D_D'],
''
)
obj.addProperty(
"App::PropertyString",
"IterationsControlParameterIter",
"Fem",
"User defined time incrementation iterations control parameter"
)
obj.IterationsControlParameterIter = p_iter
obj.addProperty("App::PropertyString", "IterationsControlParameterCutb", "Fem", "User defined time incrementation cutbacks control parameter")
obj.addProperty(
"App::PropertyString",
"IterationsControlParameterCutb",
"Fem",
"User defined time incrementation cutbacks control parameter"
)
obj.IterationsControlParameterCutb = p_cutb
stringIterationsUserDefinedIncrementations = "Set to True to switch off the ccx automatic incrementation completely (ccx parameter DIRECT). Use with care. Analysis may not converge!"
obj.addProperty("App::PropertyBool", "IterationsUserDefinedIncrementations", "Fem", stringIterationsUserDefinedIncrementations)
stringIterationsUserDefinedIncrementations = (
"Set to True to switch off the ccx automatic incrementation completely "
"(ccx parameter DIRECT). Use with care. Analysis may not converge!"
)
obj.addProperty(
"App::PropertyBool",
"IterationsUserDefinedIncrementations",
"Fem",
stringIterationsUserDefinedIncrementations)
obj.IterationsUserDefinedIncrementations = False
stringIterationsUserDefinedTimeStepLength = "Set to True to use the user defined time steps. The time steps are set with TimeInitialStep and TimeEnd"
obj.addProperty("App::PropertyBool", "IterationsUserDefinedTimeStepLength", "Fem", stringIterationsUserDefinedTimeStepLength)
stringIterationsUserDefinedTimeStepLength = (
"Set to True to use the user defined time steps. "
"The time steps are set with TimeInitialStep and TimeEnd"
)
obj.addProperty(
"App::PropertyBool",
"IterationsUserDefinedTimeStepLength",
"Fem",
stringIterationsUserDefinedTimeStepLength
)
obj.IterationsUserDefinedTimeStepLength = False
known_ccx_solver_types = ["default", "spooles", "iterativescaling", "iterativecholesky"]
obj.addProperty("App::PropertyEnumeration", "MatrixSolverType", "Fem", "Type of solver to use")
known_ccx_solver_types = [
"default",
"spooles",
"iterativescaling",
"iterativecholesky"
]
obj.addProperty(
"App::PropertyEnumeration",
"MatrixSolverType",
"Fem",
"Type of solver to use"
)
obj.MatrixSolverType = known_ccx_solver_types
solver_type = ccx_prefs.GetInt("Solver", 0)
obj.MatrixSolverType = known_ccx_solver_types[solver_type]
obj.addProperty("App::PropertyBool", "BeamShellResultOutput3D", "Fem", "Output 3D results for 1D and 2D analysis ")
obj.addProperty(
"App::PropertyBool",
"BeamShellResultOutput3D",
"Fem",
"Output 3D results for 1D and 2D analysis "
)
dimout = ccx_prefs.GetBool("BeamShellOutput", False)
obj.BeamShellResultOutput3D = dimout

View File

@@ -96,7 +96,8 @@ class Solve(run.Solve):
def run(self):
if not _inputFileName:
# TODO do not run solver, do not try to read results in a smarter way than an Exception
# TODO do not run solver
# do not try to read results in a smarter way than an Exception
raise Exception('Error on writing CalculiX input file.\n')
self.pushStatus("Executing solver...\n")
binary = settings.get_binary("Calculix")
@@ -118,7 +119,8 @@ class Results(run.Results):
def run(self):
if not _inputFileName:
# TODO do not run solver, do not try to read results in a smarter way than an Exception
# TODO do not run solver
# do not try to read results in a smarter way than an Exception
raise Exception('Error on writing CalculiX input file.\n')
prefs = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/Fem/General")
@@ -173,29 +175,70 @@ class _Container(object):
self.mesh = mesh
else:
if FreeCAD.GuiUp:
QtGui.QMessageBox.critical(None, "Missing prerequisite", message)
QtGui.QMessageBox.critical(
None,
"Missing prerequisite",
message
)
raise Exception(message + '\n')
# get member
self.materials_linear = self.get_several_member('Fem::Material')
self.materials_nonlinear = self.get_several_member('Fem::MaterialMechanicalNonlinear')
# materials
self.materials_linear = self.get_several_member(
'Fem::Material'
)
self.materials_nonlinear = self.get_several_member(
'Fem::MaterialMechanicalNonlinear'
)
self.beam_sections = self.get_several_member('Fem::FemElementGeometry1D')
self.beam_rotations = self.get_several_member('Fem::FemElementRotation1D')
self.fluid_sections = self.get_several_member('Fem::FemElementFluid1D')
self.shell_thicknesses = self.get_several_member('Fem::FemElementGeometry2D')
# geometries
self.beam_sections = self.get_several_member(
'Fem::FemElementGeometry1D'
)
self.beam_rotations = self.get_several_member(
'Fem::FemElementRotation1D'
)
self.fluid_sections = self.get_several_member(
'Fem::FemElementFluid1D'
)
self.shell_thicknesses = self.get_several_member(
'Fem::FemElementGeometry2D'
)
self.constraints_contact = self.get_several_member('Fem::ConstraintContact')
self.constraints_displacement = self.get_several_member('Fem::ConstraintDisplacement')
self.constraints_fixed = self.get_several_member('Fem::ConstraintFixed')
self.constraints_force = self.get_several_member('Fem::ConstraintForce')
self.constraints_heatflux = self.get_several_member('Fem::ConstraintHeatflux')
self.constraints_initialtemperature = self.get_several_member('Fem::ConstraintInitialTemperature')
self.constraints_planerotation = self.get_several_member('Fem::ConstraintPlaneRotation')
self.constraints_pressure = self.get_several_member('Fem::ConstraintPressure')
self.constraints_selfweight = self.get_several_member('Fem::ConstraintSelfWeight')
self.constraints_temperature = self.get_several_member('Fem::ConstraintTemperature')
self.constraints_transform = self.get_several_member('Fem::ConstraintTransform')
# constraints
self.constraints_contact = self.get_several_member(
'Fem::ConstraintContact'
)
self.constraints_displacement = self.get_several_member(
'Fem::ConstraintDisplacement'
)
self.constraints_fixed = self.get_several_member(
'Fem::ConstraintFixed'
)
self.constraints_force = self.get_several_member(
'Fem::ConstraintForce'
)
self.constraints_heatflux = self.get_several_member(
'Fem::ConstraintHeatflux'
)
self.constraints_initialtemperature = self.get_several_member(
'Fem::ConstraintInitialTemperature'
)
self.constraints_planerotation = self.get_several_member(
'Fem::ConstraintPlaneRotation'
)
self.constraints_pressure = self.get_several_member(
'Fem::ConstraintPressure'
)
self.constraints_selfweight = self.get_several_member(
'Fem::ConstraintSelfWeight'
)
self.constraints_temperature = self.get_several_member(
'Fem::ConstraintTemperature'
)
self.constraints_transform = self.get_several_member(
'Fem::ConstraintTransform'
)
def get_several_member(self, t):
return femutils.get_several_member(self.analysis, t)

View File

@@ -91,10 +91,19 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
self.main_file_name = self.mesh_object.Name + '.inp'
self.file_name = join(self.dir_name, self.main_file_name)
self.FluidInletoutlet_ele = []
self.fluid_inout_nodes_file = join(self.dir_name, (self.mesh_object.Name + '_inout_nodes.txt'))
FreeCAD.Console.PrintLog('writerbaseCcx --> self.dir_name --> ' + self.dir_name + '\n')
FreeCAD.Console.PrintLog('writerbaseCcx --> self.main_file_name --> ' + self.main_file_name + '\n')
FreeCAD.Console.PrintMessage('writerbaseCcx --> self.file_name --> ' + self.file_name + '\n')
self.fluid_inout_nodes_file = join(
self.dir_name,
'{}_inout_nodes.txt'.format(self.mesh_object.Name)
)
FreeCAD.Console.PrintLog(
'writerbaseCcx --> self.dir_name --> ' + self.dir_name + '\n'
)
FreeCAD.Console.PrintLog(
'writerbaseCcx --> self.main_file_name --> ' + self.main_file_name + '\n'
)
FreeCAD.Console.PrintMessage(
'writerbaseCcx --> self.file_name --> ' + self.file_name + '\n'
)
def write_calculix_input_file(self):
timestart = time.clock()
@@ -111,7 +120,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
return self.file_name
else:
FreeCAD.Console.PrintMessage(writing_time_string + ' \n')
FreeCAD.Console.PrintError("Problems on writing input file, check report prints.\n\n")
FreeCAD.Console.PrintError(
"Problems on writing input file, check report prints.\n\n"
)
return ""
def write_calculix_one_input_file(self):
@@ -150,7 +161,11 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
if self.fluidsection_objects:
if is_fluid_section_inlet_outlet(self.ccx_elsets) is True:
inpfile.close()
meshtools.use_correct_fluidinout_ele_def(self.FluidInletoutlet_ele, self.file_name, self.fluid_inout_nodes_file)
meshtools.use_correct_fluidinout_ele_def(
self.FluidInletoutlet_ele,
self.file_name,
self.fluid_inout_nodes_file
)
inpfile = open(self.file_name, 'a')
# constraints independent from steps
@@ -204,8 +219,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
def write_calculix_splitted_input_file(self):
# reopen file with "append" and add the analysis definition
# first open file with "write" to ensure that each new iteration of writing of inputfile starts in new file
# first open file with "write" to ensure that the .writeABAQUS also writes in inputfile
# first open file with "write" to ensure
# that each new iteration of writing of inputfile starts in new file
# first open file with "write" to ensure
# that the .writeABAQUS also writes in inputfile
inpfileMain = open(self.file_name, 'w')
inpfileMain.close()
inpfileMain = open(self.file_name, 'a')
@@ -298,14 +315,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# Fluid section: Inlet and Outlet requires special element definition
if self.fluidsection_objects:
if is_fluid_section_inlet_outlet(self.ccx_elsets) is True:
<<<<<<< HEAD
FemMeshTools.use_correct_fluidinout_ele_def(self.FluidInletoutlet_ele, name + "_Node_Elem_sets.inp", self.fluid_inout_nodes_file)
=======
meshtools.use_correct_fluidinout_ele_def(
self.FluidInletoutlet_ele, name + "_Node_Elem_sets.inp",
self.fluid_inout_nodes_file
)
>>>>>>> 5e4bf5b587... FEM: solver calculix writer and solver writer base, use small character for import identifier
# constraints independent from steps
if self.planerotation_objects:
@@ -406,7 +419,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# we only could do this for volumes, if a mesh contains volumes
# we're going to use them in the analysis
# but a mesh could contain the element faces of the volumes as faces
# and the edges of the faces as edges, there we have to check for some geometric objects
# and the edges of the faces as edges
# there we have to check for some geometric objects
self.get_ccx_elsets_single_mat_solid()
if len(self.shellthickness_objects) == 1:
self.get_ccx_elsets_single_mat_single_shell()
@@ -425,8 +439,11 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# we only could do this for volumes, if a mseh contains volumes
# we're going to use them in the analysis
# but a mesh could contain the element faces of the volumes as faces
# and the edges of the faces as edges, there we have to check for some geometric objects
self.get_ccx_elsets_multiple_mat_solid() # volume is a bit special, because retrieving ids from group mesh data is implemented
# and the edges of the faces as edges
# there we have to check for some geometric objects
# volume is a bit special
# because retrieving ids from group mesh data is implemented
self.get_ccx_elsets_multiple_mat_solid()
if len(self.shellthickness_objects) == 1:
self.get_ccx_elsets_multiple_mat_single_shell()
elif len(self.shellthickness_objects) > 1:
@@ -443,25 +460,37 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# TODO: some elementIDs are collected for 1D-Flow calculation,
# this should be a def somewhere else, preferable inside the get_ccx_elsets_... methods
for ccx_elset in self.ccx_elsets:
if ccx_elset['ccx_elset'] and not isinstance(ccx_elset['ccx_elset'], six.string_types): # use six to be sure to be Python 2.7 and 3.x compatible
# use six to be sure to be Python 2.7 and 3.x compatible
if ccx_elset['ccx_elset'] \
and not isinstance(ccx_elset['ccx_elset'], six.string_types):
if 'fluidsection_obj'in ccx_elset:
fluidsec_obj = ccx_elset['fluidsection_obj']
if fluidsec_obj.SectionType == 'Liquid':
if (fluidsec_obj.LiquidSectionType == "PIPE INLET") or (fluidsec_obj.LiquidSectionType == "PIPE OUTLET"):
if (fluidsec_obj.LiquidSectionType == "PIPE INLET") \
or (fluidsec_obj.LiquidSectionType == "PIPE OUTLET"):
elsetchanged = False
counter = 0
for elid in ccx_elset['ccx_elset']:
counter = counter + 1
if (elsetchanged is False) and (fluidsec_obj.LiquidSectionType == "PIPE INLET"):
self.FluidInletoutlet_ele.append([str(elid), fluidsec_obj.LiquidSectionType, 0]) # 3rd index is to track which line number the element is defined
if (elsetchanged is False) \
and (fluidsec_obj.LiquidSectionType == "PIPE INLET"):
# 3rd index is to track which line nr the element is defined
self.FluidInletoutlet_ele.append(
[str(elid), fluidsec_obj.LiquidSectionType, 0]
)
elsetchanged = True
elif (fluidsec_obj.LiquidSectionType == "PIPE OUTLET") and (counter == len(ccx_elset['ccx_elset'])):
self.FluidInletoutlet_ele.append([str(elid), fluidsec_obj.LiquidSectionType, 0]) # 3rd index is to track which line number the element is defined
elif (fluidsec_obj.LiquidSectionType == "PIPE OUTLET") \
and (counter == len(ccx_elset['ccx_elset'])):
# 3rd index is to track which line nr the element is defined
self.FluidInletoutlet_ele.append(
[str(elid), fluidsec_obj.LiquidSectionType, 0]
)
# write ccx_elsets to file
for ccx_elset in self.ccx_elsets:
f.write('*ELSET,ELSET=' + ccx_elset['ccx_elset_name'] + '\n')
if isinstance(ccx_elset['ccx_elset'], six.string_types): # use six to be sure to be Python 2.7 and 3.x compatible
# use six to be sure to be Python 2.7 and 3.x compatible
if isinstance(ccx_elset['ccx_elset'], six.string_types):
f.write(ccx_elset['ccx_elset'] + '\n')
else:
for elid in ccx_elset['ccx_elset']:
@@ -474,10 +503,12 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Node sets for fixed constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.fixed_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.fixed_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
fix_obj = femobj['Object']
f.write('** ' + fix_obj.Label + '\n')
if self.femmesh.Volumes and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
if self.femmesh.Volumes \
and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
if len(femobj['NodesSolid']) > 0:
f.write('*NSET,NSET=' + fix_obj.Name + 'Solid\n')
for n in femobj['NodesSolid']:
@@ -498,7 +529,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Node sets for prescribed displacement constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.displacement_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.displacement_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
disp_obj = femobj['Object']
f.write('** ' + disp_obj.Label + '\n')
f.write('*NSET,NSET=' + disp_obj.Name + '\n')
@@ -515,10 +547,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('** Node sets for plane rotation constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
# info about self.constraint_conflict_nodes:
# is used to check if MPC and constraint fixed and constraint displacement share same nodes,
# because MPC's and constraints fixed and constraints displacement can't share same nodes.
# Thus call write_node_sets_constraints_planerotation has to be after constraint fixed and constraint displacement
for femobj in self.planerotation_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
# is used to check if MPC and constraint fixed and
# constraint displacement share same nodes
# because MPC's and constraints fixed and
# constraints displacement can't share same nodes.
# Thus call write_node_sets_constraints_planerotation has to be
# after constraint fixed and constraint displacement
for femobj in self.planerotation_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
l_nodes = femobj['Nodes']
fric_obj = femobj['Object']
f.write('** ' + fric_obj.Label + '\n')
@@ -526,7 +562,12 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# Code to extract nodes and coordinates on the PlaneRotation support face
nodes_coords = []
for node in l_nodes:
nodes_coords.append((node, self.femnodes_mesh[node].x, self.femnodes_mesh[node].y, self.femnodes_mesh[node].z))
nodes_coords.append((
node,
self.femnodes_mesh[node].x,
self.femnodes_mesh[node].y,
self.femnodes_mesh[node].z
))
node_planerotation = meshtools.get_three_non_colinear_nodes(nodes_coords)
for i in range(len(l_nodes)):
if l_nodes[i] not in node_planerotation:
@@ -549,7 +590,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('** Surfaces for contact constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
obj = 0
for femobj in self.contact_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.contact_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
contact_obj = femobj['Object']
f.write('** ' + contact_obj.Label + '\n')
cnt = 0
@@ -575,7 +617,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Node sets for transform constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.transform_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.transform_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
trans_obj = femobj['Object']
f.write('** ' + trans_obj.Label + '\n')
if trans_obj.TransformType == "Rectangular":
@@ -592,7 +635,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Node sets for temperature constraints\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.temperature_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.temperature_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
temp_obj = femobj['Object']
f.write('** ' + temp_obj.Label + '\n')
f.write('*NSET,NSET=' + temp_obj.Name + '\n')
@@ -604,12 +648,15 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('** Materials\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
f.write('** Young\'s modulus unit is MPa = N/mm2\n')
if self.analysis_type == "frequency" or self.selfweight_objects or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
if self.analysis_type == "frequency" \
or self.selfweight_objects \
or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
f.write('** Density\'s unit is t/mm^3\n')
if self.analysis_type == "thermomech":
f.write('** Thermal conductivity unit is kW/mm/K = t*mm/K*s^3\n')
f.write('** Specific Heat unit is kJ/t/K = mm^2/s^2/K\n')
for femobj in self.material_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.material_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
mat_obj = femobj['Object']
mat_info_name = mat_obj.Material['Name']
mat_name = mat_obj.Name
@@ -619,14 +666,19 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
YM = FreeCAD.Units.Quantity(mat_obj.Material['YoungsModulus'])
YM_in_MPa = float(YM.getValueAs('MPa'))
PR = float(mat_obj.Material['PoissonRatio'])
if self.analysis_type == "frequency" or self.selfweight_objects or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
if self.analysis_type == "frequency" \
or self.selfweight_objects \
or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
density = FreeCAD.Units.Quantity(mat_obj.Material['Density'])
density_in_tonne_per_mm3 = float(density.getValueAs('t/mm^3'))
if self.analysis_type == "thermomech":
TC = FreeCAD.Units.Quantity(mat_obj.Material['ThermalConductivity'])
TC_in_WmK = float(TC.getValueAs('W/m/K')) # SvdW: Add factor to force units to results' base units of t/mm/s/K - W/m/K results in no factor needed
# SvdW: Add factor to force units to results' base units
# of t/mm/s/K - W/m/K results in no factor needed
TC_in_WmK = float(TC.getValueAs('W/m/K'))
SH = FreeCAD.Units.Quantity(mat_obj.Material['SpecificHeat'])
SH_in_JkgK = float(SH.getValueAs('J/kg/K')) * 1e+06 # SvdW: Add factor to force units to results' base units of t/mm/s/K
# SvdW: Add factor to force units to results' base units of t/mm/s/K
SH_in_JkgK = float(SH.getValueAs('J/kg/K')) * 1e+06
if mat_obj.Category == 'Solid':
TEC = FreeCAD.Units.Quantity(mat_obj.Material['ThermalExpansionCoefficient'])
TEC_in_mmK = float(TEC.getValueAs('mm/mm/K'))
@@ -641,7 +693,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('*ELASTIC\n')
f.write('{0:.0f}, {1:.3f}\n'.format(YM_in_MPa, PR))
if self.analysis_type == "frequency" or self.selfweight_objects or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
if self.analysis_type == "frequency" \
or self.selfweight_objects \
or (self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState):
f.write('*DENSITY\n')
f.write('{0:.3e}\n'.format(density_in_tonne_per_mm3))
if self.analysis_type == "thermomech":
@@ -658,7 +712,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# nonlinear material properties
if self.solver_obj.MaterialNonlinearity == 'nonlinear':
for femobj in self.material_nonlinear_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.material_nonlinear_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
nl_mat_obj = femobj['Object']
if nl_mat_obj.LinearBaseMaterial == mat_obj:
if nl_mat_obj.MaterialModelNonlinearity == "simple hardening":
@@ -678,7 +733,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('*INITIAL CONDITIONS,TYPE=TEMPERATURE\n')
for itobj in self.initialtemperature_objects: # Should only be one
inittemp_obj = itobj['Object']
f.write('{0},{1}\n'.format(self.ccx_nall, inittemp_obj.initialTemperature)) # OvG: Initial temperature
# OvG: Initial temperature
f.write('{0},{1}\n'.format(self.ccx_nall, inittemp_obj.initialTemperature))
def write_femelementsets(self, f):
f.write('\n***********************************************************\n')
@@ -696,21 +752,45 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
width = beamsec_obj.RectWidth.getValueAs('mm')
section_type = ', SECTION=RECT'
setion_geo = str(height) + ', ' + str(width) + '\n'
setion_def = '*BEAM SECTION, ' + elsetdef + material + section_type + '\n'
setion_nor = str(normal[0]) + ', ' + str(normal[1]) + ', ' + str(normal[2]) + '\n'
setion_def = '*BEAM SECTION, {}{}{}\n'.format(
elsetdef,
material,
section_type
)
setion_nor = '{}, {}, {}\n'.format(
normal[0],
normal[1],
normal[2]
)
elif beamsec_obj.SectionType == 'Circular':
radius = 0.5 * beamsec_obj.CircDiameter.getValueAs('mm')
section_type = ', SECTION=CIRC'
setion_geo = str(radius) + '\n'
setion_def = '*BEAM SECTION, ' + elsetdef + material + section_type + '\n'
setion_nor = str(normal[0]) + ', ' + str(normal[1]) + ', ' + str(normal[2]) + '\n'
setion_def = '*BEAM SECTION, {}{}{}\n'.format(
elsetdef,
material,
section_type
)
setion_nor = '{}, {}, {}\n'.format(
normal[0],
normal[1],
normal[2]
)
elif beamsec_obj.SectionType == 'Pipe':
radius = 0.5 * beamsec_obj.PipeDiameter.getValueAs('mm')
thickness = beamsec_obj.PipeThickness.getValueAs('mm')
section_type = ', SECTION=PIPE'
setion_geo = str(radius) + ', ' + str(thickness) + '\n'
setion_def = '*BEAM GENERAL SECTION, ' + elsetdef + material + section_type + '\n'
setion_nor = str(normal[0]) + ', ' + str(normal[1]) + ', ' + str(normal[2]) + '\n'
setion_def = '*BEAM GENERAL SECTION, {}{}{}\n'.format(
elsetdef,
material,
section_type
)
setion_nor = '{}, {}, {}\n'.format(
normal[0],
normal[1],
normal[2]
)
f.write(setion_def)
f.write(setion_geo)
f.write(setion_nor)
@@ -722,7 +802,11 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
section_type = fluidsec_obj.LiquidSectionType
if (section_type == "PIPE INLET") or (section_type == "PIPE OUTLET"):
section_type = "PIPE INOUT"
setion_def = '*FLUID SECTION, ' + elsetdef + 'TYPE=' + section_type + ', ' + material + '\n'
setion_def = '*FLUID SECTION, {}TYPE={}, {}\n'.format(
elsetdef,
section_type,
material
)
setion_geo = liquid_section_def(fluidsec_obj, section_type)
elif fluidsec_obj.SectionType == 'Gas':
section_type = fluidsec_obj.GasSectionType
@@ -752,14 +836,19 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
step = '*STEP'
if self.solver_obj.GeometricalNonlinearity == "nonlinear":
if self.analysis_type == 'static' or self.analysis_type == 'thermomech':
step += ', NLGEOM' # https://www.comsol.com/blogs/what-is-geometric-nonlinearity/
# https://www.comsol.com/blogs/what-is-geometric-nonlinearity
step += ', NLGEOM'
elif self.analysis_type == 'frequency':
FreeCAD.Console.PrintMessage('Analysis type frequency and geometrical nonlinear analysis are not allowed together, linear is used instead!\n')
FreeCAD.Console.PrintMessage(
'Analysis type frequency and geometrical nonlinear '
'analysis are not allowed together, linear is used instead!\n'
)
if self.solver_obj.IterationsThermoMechMaximum:
if self.analysis_type == 'thermomech':
step += ', INC=' + str(self.solver_obj.IterationsThermoMechMaximum)
elif self.analysis_type == 'static' or self.analysis_type == 'frequency':
pass # parameter is for thermomechanical analysis only, see ccx manual *STEP
# parameter is for thermomechanical analysis only, see ccx manual *STEP
pass
# write step line
f.write(step + '\n')
# CONTROLS line
@@ -787,34 +876,54 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
analysis_type += ', SOLVER=ITERATIVE SCALING'
elif self.solver_obj.MatrixSolverType == "iterativecholesky":
analysis_type += ', SOLVER=ITERATIVE CHOLESKY'
# analysis line --> user defined incrementations --> parameter DIRECT --> completely switch off ccx automatic incrementation
# analysis line --> user defined incrementations --> parameter DIRECT
# --> completely switch off ccx automatic incrementation
if self.solver_obj.IterationsUserDefinedIncrementations:
if self.analysis_type == 'static':
analysis_type += ', DIRECT'
elif self.analysis_type == 'thermomech':
analysis_type += ', DIRECT'
elif self.analysis_type == 'frequency':
FreeCAD.Console.PrintMessage('Analysis type frequency and IterationsUserDefinedIncrementations are not allowed together, it is ignored\n')
FreeCAD.Console.PrintMessage(
'Analysis type frequency and IterationsUserDefinedIncrementations '
'are not allowed together, it is ignored\n'
)
# analysis line --> steadystate --> thermomech only
if self.solver_obj.ThermoMechSteadyState:
if self.analysis_type == 'thermomech': # bernd: I do not know if STEADY STATE is allowed with DIRECT but since time steps are 1.0 it makes no sense IMHO
# bernd: I do not know if STEADY STATE is allowed with DIRECT
# but since time steps are 1.0 it makes no sense IMHO
if self.analysis_type == 'thermomech':
analysis_type += ', STEADY STATE'
self.solver_obj.TimeInitialStep = 1.0 # Set time to 1 and ignore user inputs for steady state
# Set time to 1 and ignore user inputs for steady state
self.solver_obj.TimeInitialStep = 1.0
self.solver_obj.TimeEnd = 1.0
elif self.analysis_type == 'static' or self.analysis_type == 'frequency':
pass # not supported for static and frequency!
# ANALYSIS parameter line
analysis_parameter = ''
if self.analysis_type == 'static' or self.analysis_type == 'check':
if self.solver_obj.IterationsUserDefinedIncrementations is True or self.solver_obj.IterationsUserDefinedTimeStepLength is True:
analysis_parameter = '{},{}'.format(self.solver_obj.TimeInitialStep, self.solver_obj.TimeEnd)
if self.solver_obj.IterationsUserDefinedIncrementations is True \
or self.solver_obj.IterationsUserDefinedTimeStepLength is True:
analysis_parameter = '{},{}'.format(
self.solver_obj.TimeInitialStep,
self.solver_obj.TimeEnd
)
elif self.analysis_type == 'frequency':
if self.solver_obj.EigenmodeLowLimit == 0.0 and self.solver_obj.EigenmodeHighLimit == 0.0:
if self.solver_obj.EigenmodeLowLimit == 0.0 \
and self.solver_obj.EigenmodeHighLimit == 0.0:
analysis_parameter = '{}\n'.format(self.solver_obj.EigenmodesCount)
else:
analysis_parameter = '{},{},{}\n'.format(self.solver_obj.EigenmodesCount, self.solver_obj.EigenmodeLowLimit, self.solver_obj.EigenmodeHighLimit)
analysis_parameter = '{},{},{}\n'.format(
self.solver_obj.EigenmodesCount,
self.solver_obj.EigenmodeLowLimit,
self.solver_obj.EigenmodeHighLimit
)
elif self.analysis_type == 'thermomech':
analysis_parameter = '{},{}'.format(self.solver_obj.TimeInitialStep, self.solver_obj.TimeEnd) # OvG: 1.0 increment, total time 1 for steady state will cut back automatically
# OvG: 1.0 increment, total time 1 for steady state will cut back automatically
analysis_parameter = '{},{}'.format(
self.solver_obj.TimeInitialStep,
self.solver_obj.TimeEnd
)
# write analysis type line, analysis parameter line
f.write(analysis_type + '\n')
f.write(analysis_parameter + '\n')
@@ -823,10 +932,12 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Fixed Constraints\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.fixed_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.fixed_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
f.write('** ' + femobj['Object'].Label + '\n')
fix_obj_name = femobj['Object'].Name
if self.femmesh.Volumes and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
if self.femmesh.Volumes \
and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
if len(femobj['NodesSolid']) > 0:
f.write('*BOUNDARY\n')
f.write(fix_obj_name + 'Solid' + ',1\n')
@@ -857,7 +968,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Displacement constraint applied\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.displacement_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.displacement_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
f.write('** ' + femobj['Object'].Label + '\n')
disp_obj = femobj['Object']
disp_obj_name = disp_obj.Name
@@ -895,7 +1007,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('** Contact Constraints\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
obj = 0
for femobj in self.contact_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.contact_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
obj = obj + 1
contact_obj = femobj['Object']
f.write('** ' + contact_obj.Label + '\n')
@@ -917,7 +1030,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** PlaneRotation Constraints\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.planerotation_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.planerotation_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
f.write('** ' + femobj['Object'].Label + '\n')
fric_obj_name = femobj['Object'].Name
f.write('*MPC\n')
@@ -943,15 +1057,25 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Self weight Constraint\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.selfweight_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.selfweight_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
selwei_obj = femobj['Object']
f.write('** ' + selwei_obj.Label + '\n')
f.write('*DLOAD\n')
f.write(self.ccx_eall + ',GRAV,9810,' + str(selwei_obj.Gravity_x) + ',' + str(selwei_obj.Gravity_y) + ',' + str(selwei_obj.Gravity_z) + '\n')
f.write(
'{},GRAV,9810,{},{},{}\n'
.format(
self.ccx_eall,
selwei_obj.Gravity_x,
selwei_obj.Gravity_y,
selwei_obj.Gravity_z
)
)
f.write('\n')
# grav (erdbeschleunigung) is equal for all elements
# should be only one constraint
# different element sets for different density are written in the material element sets already
# different element sets for different density
# are written in the material element sets already
def write_constraints_force(self, f):
# check shape type of reference shape and get node loads
@@ -961,7 +1085,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('** Node loads Constraints\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
f.write('*CLOAD\n')
for femobj in self.force_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.force_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
f.write('** ' + femobj['Object'].Label + '\n')
direction_vec = femobj['Object'].DirectionVector
for ref_shape in femobj['NodeLoadTable']:
@@ -987,7 +1112,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n***********************************************************\n')
f.write('** Element + CalculiX face + load in [MPa]\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.pressure_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
prs_obj = femobj['Object']
f.write('** ' + prs_obj.Label + '\n')
rev = -1 if prs_obj.Reversed else 1
@@ -997,9 +1123,13 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for face, fno in ref_shape[1]:
if fno > 0: # solid mesh face
f.write("{},P{},{}\n".format(face, fno, rev * prs_obj.Pressure))
elif fno == 0: # on shell mesh face: fno == 0 --> normal of element face == face normal
# on shell mesh face: fno == 0
# normal of element face == face normal
elif fno == 0:
f.write("{},P,{}\n".format(face, rev * prs_obj.Pressure))
elif fno == -1: # on shell mesh face: fno == -1 --> normal of element face opposite direction face normal
# on shell mesh face: fno == -1
# normal of element face opposite direction face normal
elif fno == -1:
f.write("{},P,{}\n".format(face, -1 * rev * prs_obj.Pressure))
def write_constraints_temperature(self, f):
@@ -1016,7 +1146,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('\n')
elif fixedtemp_obj.ConstraintType == "CFlux":
f.write('*CFLUX\n')
f.write('{},11,{}\n'.format(fixedtemp_obj.Name, fixedtemp_obj.CFlux * 0.001 / NumberOfNodes))
f.write('{},11,{}\n'.format(
fixedtemp_obj.Name,
fixedtemp_obj.CFlux * 0.001 / NumberOfNodes
))
f.write('\n')
def write_constraints_heatflux(self, f):
@@ -1035,8 +1168,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
v = self.mesh_object.FemMesh.getccxVolumesByFace(ho)
f.write("** Heat flux on face {}\n".format(elem))
for i in v:
# SvdW: add factor to force heatflux to units system of t/mm/s/K # OvG: Only write out the VolumeIDs linked to a particular face
f.write("{},F{},{},{}\n".format(i[0], i[1], heatflux_obj.AmbientTemp, heatflux_obj.FilmCoef * 0.001))
# SvdW: add factor to force heatflux to units system of t/mm/s/K
# OvG: Only write out the VolumeIDs linked to a particular face
f.write("{},F{},{},{}\n".format(
i[0],
i[1],
heatflux_obj.AmbientTemp,
heatflux_obj.FilmCoef * 0.001
))
elif heatflux_obj.ConstraintType == "DFlux":
f.write('*DFLUX\n')
for o, elem_tup in heatflux_obj.References:
@@ -1046,7 +1185,11 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
v = self.mesh_object.FemMesh.getccxVolumesByFace(ho)
f.write("** Heat flux on face {}\n".format(elem))
for i in v:
f.write("{},S{},{}\n".format(i[0], i[1], heatflux_obj.DFlux * 0.001))
f.write("{},S{},{}\n".format(
i[0],
i[1],
heatflux_obj.DFlux * 0.001
))
def write_constraints_fluidsection(self, f):
f.write('\n***********************************************************\n')
@@ -1057,10 +1200,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
lines = inout_nodes_file.readlines()
inout_nodes_file.close()
else:
FreeCAD.Console.PrintError("1DFlow inout nodes file not found: " + self.fluid_inout_nodes_file + '\n')
FreeCAD.Console.PrintError(
"1DFlow inout nodes file not found: {}\n"
.format(self.fluid_inout_nodes_file)
)
# get nodes
self.get_constraints_fluidsection_nodes()
for femobj in self.fluidsection_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
for femobj in self.fluidsection_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
fluidsection_obj = femobj['Object']
f.write('** ' + fluidsection_obj.Label + '\n')
if fluidsection_obj.SectionType == 'Liquid':
@@ -1072,15 +1219,27 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for line in lines:
b = line.split(',')
if int(b[0]) == n and b[3] == 'PIPE INLET\n':
f.write(b[0] + ',2,2,' + str(fluidsection_obj.InletPressure) + '\n') # degree of freedom 2 is for defining pressure
# degree of freedom 2 is for defining pressure
f.write('{},{},{},{}\n'.format(
b[0],
'2',
'2',
fluidsection_obj.InletPressure
))
if fluidsection_obj.InletFlowRateActive is True:
f.write('*BOUNDARY,MASS FLOW \n')
for n in femobj['Nodes']:
for line in lines:
b = line.split(',')
if int(b[0]) == n and b[3] == 'PIPE INLET\n':
# degree of freedom 1 is for defining flow rate, factor applied to convert unit from kg/s to t/s
f.write(b[1] + ',1,1,' + str(fluidsection_obj.InletFlowRate * 0.001) + '\n')
# degree of freedom 1 is for defining flow rate
# factor applied to convert unit from kg/s to t/s
f.write('{},{},{},{}\n'.format(
b[1],
'1',
'1',
fluidsection_obj.InletFlowRate * 0.001
))
elif fluidsection_obj.LiquidSectionType == 'PIPE OUTLET':
f.write('**Fluid Section Outlet \n')
if fluidsection_obj.OutletPressureActive is True:
@@ -1089,15 +1248,27 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for line in lines:
b = line.split(',')
if int(b[0]) == n and b[3] == 'PIPE OUTLET\n':
f.write(b[0] + ',2,2,' + str(fluidsection_obj.OutletPressure) + '\n') # degree of freedom 2 is for defining pressure
# degree of freedom 2 is for defining pressure
f.write('{},{},{},{}\n'.format(
b[0],
'2',
'2',
fluidsection_obj.OutletPressure
))
if fluidsection_obj.OutletFlowRateActive is True:
f.write('*BOUNDARY,MASS FLOW \n')
for n in femobj['Nodes']:
for line in lines:
b = line.split(',')
if int(b[0]) == n and b[3] == 'PIPE OUTLET\n':
# degree of freedom 1 is for defining flow rate, factor applied to convert unit from kg/s to t/s
f.write(b[1] + ',1,1,' + str(fluidsection_obj.OutletFlowRate * 0.001) + '\n')
# degree of freedom 1 is for defining flow rate
# factor applied to convert unit from kg/s to t/s
f.write('{},{},{},{}\n'.format(
b[1],
'1',
'1',
fluidsection_obj.OutletFlowRate * 0.001
))
def write_outputs_types(self, f):
f.write('\n***********************************************************\n')
@@ -1110,7 +1281,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('*NODE FILE, OUTPUT=3d\n')
else:
f.write('*NODE FILE\n')
if self.analysis_type == "thermomech": # MPH write out nodal temperatures if thermomechanical
# MPH write out nodal temperatures if thermomechanical
if self.analysis_type == "thermomech":
if not self.fluidsection_objects:
f.write('U, NT\n')
else:
@@ -1123,7 +1295,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
f.write('S, E, PEEQ\n')
else:
f.write('S, E\n')
# there is no need to write all integration point results as long as there is no reader for this
# there is no need to write all integration point results
# as long as there is no reader for this
# see https://forum.freecadweb.org/viewtopic.php?f=18&t=29060
# f.write('** outputs --> dat file\n')
# f.write('*NODE PRINT , NSET=' + self.ccx_nall + '\n')
@@ -1139,11 +1312,23 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
def write_footer(self, f):
f.write('\n***********************************************************\n')
f.write('** CalculiX Input file\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
f.write('** written by --> FreeCAD ' + self.fc_ver[0] + '.' + self.fc_ver[1] + '.' + self.fc_ver[2] + '\n')
f.write('** written on --> ' + time.ctime() + '\n')
f.write('** file name --> ' + os.path.basename(FreeCAD.ActiveDocument.FileName) + '\n')
f.write('** analysis name --> ' + self.analysis.Name + '\n')
f.write('** written by {} function\n'.format(
sys._getframe().f_code.co_name
))
f.write('** written by --> FreeCAD {}.{}.{}\n'.format(
self.fc_ver[0],
self.fc_ver[1],
self.fc_ver[2]
))
f.write('** written on --> {}\n'.format(
time.ctime()
))
f.write('** file name --> {}\n'.format(
os.path.basename(FreeCAD.ActiveDocument.FileName)
))
f.write('** analysis name --> {}\n'.format(
self.analysis.Name
))
f.write('**\n')
f.write('**\n')
f.write('**\n')
@@ -1168,14 +1353,20 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# beam
# TODO support multiple beamrotations
# we do not need any more any data from the rotation document object, thus we do not need to save the rotation document object name in the else
# we do not need any more any data from the rotation document object,
# thus we do not need to save the rotation document object name in the else
def get_ccx_elsets_single_mat_single_beam(self):
mat_obj = self.material_objects[0]['Object']
beamsec_obj = self.beamsection_objects[0]['Object']
beamrot_data = self.beamrotation_objects[0]
for i, beamdirection in enumerate(beamrot_data['FEMRotations1D']):
elset_data = beamdirection['ids'] # ID's for this direction
names = [{'short': 'M0'}, {'short': 'B0'}, {'short': beamrot_data['ShortName']}, {'short': 'D' + str(i)}]
names = [
{'short': 'M0'},
{'short': 'B0'},
{'short': beamrot_data['ShortName']},
{'short': 'D' + str(i)}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_short(names)
@@ -1193,9 +1384,15 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
beamsec_ids = set(beamsec_data['FEMElements'])
for i, beamdirection in enumerate(beamrot_data['FEMRotations1D']):
beamdir_ids = set(beamdirection['ids'])
elset_data = list(sorted(beamsec_ids.intersection(beamdir_ids))) # empty intersection sets possible
# empty intersection sets possible
elset_data = list(sorted(beamsec_ids.intersection(beamdir_ids)))
if elset_data:
names = [{'short': 'M0'}, {'short': beamsec_data['ShortName']}, {'short': beamrot_data['ShortName']}, {'short': 'D' + str(i)}]
names = [
{'short': 'M0'},
{'short': beamsec_data['ShortName']},
{'short': beamrot_data['ShortName']},
{'short': 'D' + str(i)}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_short(names)
@@ -1215,14 +1412,20 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
beamdir_ids = set(beamdirection['ids'])
elset_data = list(sorted(mat_ids.intersection(beamdir_ids)))
if elset_data:
names = [{'short': mat_data['ShortName']}, {'short': 'B0'}, {'short': beamrot_data['ShortName']}, {'short': 'D' + str(i)}]
names = [
{'short': mat_data['ShortName']},
{'short': 'B0'},
{'short': beamrot_data['ShortName']},
{'short': 'D' + str(i)}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_short(names)
ccx_elset['mat_obj_name'] = mat_obj.Name
ccx_elset['ccx_mat_name'] = mat_obj.Material['Name']
ccx_elset['beamsection_obj'] = beamsec_obj
ccx_elset['beam_normal'] = beamdirection['normal'] # normal for this direction
# normal for this direction
ccx_elset['beam_normal'] = beamdirection['normal']
self.ccx_elsets.append(ccx_elset)
def get_ccx_elsets_multiple_mat_multiple_beam(self):
@@ -1235,16 +1438,25 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
mat_ids = set(mat_data['FEMElements'])
for i, beamdirection in enumerate(beamrot_data['FEMRotations1D']):
beamdir_ids = set(beamdirection['ids'])
elset_data = list(sorted(beamsec_ids.intersection(mat_ids).intersection(beamdir_ids))) # empty intersection sets possible
# empty intersection sets possible
elset_data = list(sorted(
beamsec_ids.intersection(mat_ids).intersection(beamdir_ids)
))
if elset_data:
names = [{'short': mat_data['ShortName']}, {'short': beamsec_data['ShortName']}, {'short': beamrot_data['ShortName']}, {'short': 'D' + str(i)}]
names = [
{'short': mat_data['ShortName']},
{'short': beamsec_data['ShortName']},
{'short': beamrot_data['ShortName']},
{'short': 'D' + str(i)}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_short(names)
ccx_elset['mat_obj_name'] = mat_obj.Name
ccx_elset['ccx_mat_name'] = mat_obj.Material['Name']
ccx_elset['beamsection_obj'] = beamsec_obj
ccx_elset['beam_normal'] = beamdirection['normal'] # normal for this direction
# normal for this direction
ccx_elset['beam_normal'] = beamdirection['normal']
self.ccx_elsets.append(ccx_elset)
# fluid
@@ -1296,9 +1508,13 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
mat_obj = mat_data['Object']
fluidsec_ids = set(fluidsec_data['FEMElements'])
mat_ids = set(mat_data['FEMElements'])
elset_data = list(sorted(fluidsec_ids.intersection(mat_ids))) # empty intersection sets possible
# empty intersection sets possible
elset_data = list(sorted(fluidsec_ids.intersection(mat_ids)))
if elset_data:
names = [{'short': mat_data['ShortName']}, {'short': fluidsec_data['ShortName']}]
names = [
{'short': mat_data['ShortName']},
{'short': fluidsec_data['ShortName']}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_short(names)
@@ -1312,7 +1528,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
mat_obj = self.material_objects[0]['Object']
shellth_obj = self.shellthickness_objects[0]['Object']
elset_data = self.ccx_efaces
names = [{'long': mat_obj.Name, 'short': 'M0'}, {'long': shellth_obj.Name, 'short': 'S0'}]
names = [
{'long': mat_obj.Name, 'short': 'M0'},
{'long': shellth_obj.Name, 'short': 'S0'}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1326,7 +1545,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for shellth_data in self.shellthickness_objects:
shellth_obj = shellth_data['Object']
elset_data = shellth_data['FEMElements']
names = [{'long': mat_obj.Name, 'short': 'M0'}, {'long': shellth_obj.Name, 'short': shellth_data['ShortName']}]
names = [
{'long': mat_obj.Name, 'short': 'M0'},
{'long': shellth_obj.Name, 'short': shellth_data['ShortName']}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1340,7 +1562,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for mat_data in self.material_objects:
mat_obj = mat_data['Object']
elset_data = mat_data['FEMElements']
names = [{'long': mat_obj.Name, 'short': mat_data['ShortName']}, {'long': shellth_obj.Name, 'short': 'S0'}]
names = [
{'long': mat_obj.Name, 'short': mat_data['ShortName']},
{'long': shellth_obj.Name, 'short': 'S0'}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1356,9 +1581,13 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
mat_obj = mat_data['Object']
shellth_ids = set(shellth_data['FEMElements'])
mat_ids = set(mat_data['FEMElements'])
elset_data = list(sorted(shellth_ids.intersection(mat_ids))) # empty intersection sets possible
# empty intersection sets possible
elset_data = list(sorted(shellth_ids.intersection(mat_ids)))
if elset_data:
names = [{'long': mat_obj.Name, 'short': mat_data['ShortName']}, {'long': shellth_obj.Name, 'short': shellth_data['ShortName']}]
names = [
{'long': mat_obj.Name, 'short': mat_data['ShortName']},
{'long': shellth_obj.Name, 'short': shellth_data['ShortName']}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = ccx_elset
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1371,7 +1600,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
def get_ccx_elsets_single_mat_solid(self):
mat_obj = self.material_objects[0]['Object']
elset_data = self.ccx_evolumes
names = [{'long': mat_obj.Name, 'short': 'M0'}, {'long': 'Solid', 'short': 'Solid'}]
names = [
{'long': mat_obj.Name, 'short': 'M0'},
{'long': 'Solid', 'short': 'Solid'}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1383,7 +1615,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
for mat_data in self.material_objects:
mat_obj = mat_data['Object']
elset_data = mat_data['FEMElements']
names = [{'long': mat_obj.Name, 'short': mat_data['ShortName']}, {'long': 'Solid', 'short': 'Solid'}]
names = [
{'long': mat_obj.Name, 'short': mat_data['ShortName']},
{'long': 'Solid', 'short': 'Solid'}
]
ccx_elset = {}
ccx_elset['ccx_elset'] = elset_data
ccx_elset['ccx_elset_name'] = get_ccx_elset_name_standard(names)
@@ -1393,7 +1628,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# Helpers
# ccx elset names: M .. Material, B .. Beam, R .. BeamRotation, D ..Direction, F .. Fluid, S .. Shell, TODO write comment into input file to elset ids and elset attributes
# ccx elset names:
# M .. Material
# B .. Beam
# R .. BeamRotation
# D ..Direction
# F .. Fluid
# S .. Shell,
# TODO write comment into input file to elset ids and elset attributes
def get_ccx_elset_name_standard(names):
# standard max length = 80
ccx_elset_name = ''
@@ -1408,7 +1650,11 @@ def get_ccx_elset_name_standard(names):
if len(ccx_elset_name) < 81:
return ccx_elset_name
else:
error = 'FEM: Trouble in ccx input file, because an elset name is longer than 80 character!' + ' ' + ccx_elset_name + '\n'
error = (
'FEM: Trouble in ccx input file, because an '
'elset name is longer than 80 character! {}\n'
.format(ccx_elset_name)
)
raise Exception(error)
@@ -1420,7 +1666,11 @@ def get_ccx_elset_name_short(names):
if len(ccx_elset_name) < 21:
return ccx_elset_name
else:
error = 'FEM: Trouble in ccx input file, because a beam elset name is longer than 20 character!' + ' ' + ccx_elset_name + '\n'
error = (
'FEM: Trouble in ccx input file, because an'
'beam elset name is longer than 20 character! {}\n'
.format(ccx_elset_name)
)
raise Exception(error)
@@ -1432,7 +1682,8 @@ def is_fluid_section_inlet_outlet(ccx_elsets):
if 'fluidsection_obj'in ccx_elset: # fluid mesh
fluidsec_obj = ccx_elset['fluidsection_obj']
if fluidsec_obj.SectionType == "Liquid":
if (fluidsec_obj.LiquidSectionType == "PIPE INLET") or (fluidsec_obj.LiquidSectionType == "PIPE OUTLET"):
if (fluidsec_obj.LiquidSectionType == "PIPE INLET") \
or (fluidsec_obj.LiquidSectionType == "PIPE OUTLET"):
return True
return False
@@ -1469,7 +1720,12 @@ def liquid_section_def(obj, section_type):
bend_radius_diameter = str(obj.BendRadiusDiameter)
bend_angle = str(obj.BendAngle)
bend_loss_coefficient = str(obj.BendLossCoefficient)
section_geo = bend_pipe_area + ',' + bend_radius_diameter + ',' + bend_angle + ',' + bend_loss_coefficient + '\n'
section_geo = ('{},{},{},{}\n'.format(
bend_pipe_area,
bend_radius_diameter,
bend_angle,
bend_loss_coefficient
))
return section_geo
elif section_type == 'PIPE GATE VALVE':
gatevalve_pipe_area = str(obj.GateValvePipeArea.getValueAs('mm^2').Value)
@@ -1481,7 +1737,13 @@ def liquid_section_def(obj, section_type):
colebrooke_diameter = str(2 * obj.ColebrookeRadius.getValueAs('mm'))
colebrooke_grain_diameter = str(obj.ColebrookeGrainDiameter.getValueAs('mm'))
colebrooke_form_factor = str(obj.ColebrookeFormFactor)
section_geo = colebrooke_area + ',' + colebrooke_diameter + ',-1,' + colebrooke_grain_diameter + ',' + colebrooke_form_factor + '\n'
section_geo = ('{},{},{},{},{}\n'.format(
colebrooke_area,
colebrooke_diameter,
'-1',
colebrooke_grain_diameter,
colebrooke_form_factor
))
return section_geo
elif section_type == 'LIQUID PUMP':
section_geo = ''

View File

@@ -398,14 +398,16 @@ class _Writer(object):
return _TYPE_INTEGER
if issubclass(dataType, float):
return _TYPE_REAL
if issubclass(dataType, six.string_types): # use six to be sure to be Python 2.7 and 3.x compatible
# use six to be sure to be Python 2.7 and 3.x compatible
if issubclass(dataType, six.string_types):
return _TYPE_STRING
raise ValueError("Unsupported data type: %s" % dataType)
def _preprocess(self, data, dataType):
if issubclass(dataType, Section):
return str(self._idMgr.getId(data))
if issubclass(dataType, six.string_types): # use six to be sure to be Python 2.7 and 3.x compatible
# use six to be sure to be Python 2.7 and 3.x compatible
if issubclass(dataType, six.string_types):
return '"%s"' % data
return str(data)

View File

@@ -266,7 +266,8 @@ class Writer(object):
if obj is not None:
for name in bodies:
heatSource = getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3")
# according Elmer forum W/kg is correct, http://www.elmerfem.org/forum/viewtopic.php?f=7&t=1765
# according Elmer forum W/kg is correct
# http://www.elmerfem.org/forum/viewtopic.php?f=7&t=1765
# 1 watt = kg * m2 / s3 ... W/kg = m2 / s3
self._bodyForce(name, "Heat Source", heatSource)
self._handled(obj)
@@ -479,7 +480,9 @@ class Writer(object):
densityQuantity = Units.Quantity(m["Density"])
dimension = "M/L^3"
if name.startswith("Edge"):
density = None # not tested, but it seems needed because denisty does not exist (IMHO, bernd)
# not tested, but it seems needed
# because denisty does not exist (IMHO, bernd)
density = None
if density:
density.Unit = Units.Unit(-2, 1)
dimension = "M/L^2"

View File

@@ -65,7 +65,14 @@ else:
xdmffile.read(self.mesh)
xdmffile.close()
def readCellExpression(self, group_value_dict, value_type="scalar", overlap=lambda x: x[0], *args, **kwargs):
def readCellExpression(
self,
group_value_dict,
value_type="scalar",
overlap=lambda x: x[0],
*args,
**kwargs
):
"""
Reads cell expression and returns it.
"""
@@ -76,14 +83,24 @@ else:
self.readMesh()
xdmffile = fenics.XDMFFile(self.xdmffilename)
cf = value_type_dictionary[value_type.lower()](group_value_dict,
overlap=overlap,
*args, **kwargs)
cf = value_type_dictionary[value_type.lower()](
group_value_dict,
overlap=overlap,
*args, **kwargs
)
cf.init()
for (key, value) in cf.group_value_dict.items():
cf.markers[key] = fenics.MeshFunction("size_t", self.mesh, self.mesh.topology().dim())
cf.markers[key] = fenics.MeshFunction(
"size_t",
self.mesh,
self.mesh.topology().dim()
)
xdmffile.read(cf.markers[key], key)
cf.dx[key] = fenics.Measure("dx", domain=self.mesh, subdomain_data=cf.markers[key])
cf.dx[key] = fenics.Measure(
"dx",
domain=self.mesh,
subdomain_data=cf.markers[key]
)
xdmffile.close()
return cf
@@ -96,10 +113,18 @@ else:
ff = FacetFunctionFromXDMF(group_value_dict, *args, **kwargs)
ff.init()
for (key, value) in ff.group_value_dict.items():
ff.markers[key] = fenics.MeshFunction("size_t", self.mesh, self.mesh.topology().dim() - 1)
ff.markers[key] = fenics.MeshFunction(
"size_t",
self.mesh,
self.mesh.topology().dim() - 1
)
xdmffile.read(ff.markers[key], key)
ff.marked[key] = value.get("marked", 1)
ff.ds[key] = fenics.Measure("ds", domain=self.mesh, subdomain_data=ff.markers[key])
ff.ds[key] = fenics.Measure(
"ds",
domain=self.mesh,
subdomain_data=ff.markers[key]
)
ff.bcs[key] = value
xdmffile.close()
return ff
@@ -108,10 +133,13 @@ else:
"""
Creates cell function expression from XDMF file.
"""
def __init__(self, group_value_dict,
default=lambda x: 0.,
check_marked=(lambda x: x == 1), overlap=lambda x: x[0],
**kwargs):
def __init__(
self, group_value_dict,
default=lambda x: 0.,
check_marked=(lambda x: x == 1),
overlap=lambda x: x[0],
**kwargs
):
self.init()
self.group_value_dict = group_value_dict
self.check_marked = check_marked
@@ -127,8 +155,10 @@ else:
def eval_cell_backend(self, values, x, cell):
values_list = [func(x) for (key, func) in self.group_value_dict.items()
if self.check_marked(self.markers[key][cell.index])]
values_list = [
func(x) for (key, func) in self.group_value_dict.items()
if self.check_marked(self.markers[key][cell.index])
]
return_value = self.overlap(values_list)
if values_list:
@@ -146,13 +176,20 @@ else:
class ScalarCellExpressionFromXDMF(fenics.Expression, CellExpressionFromXDMF):
def __init__(self, group_value_dict,
default=lambda x: 0.,
check_marked=(lambda x: x == 1), overlap=lambda x: x[0], **kwargs):
CellExpressionFromXDMF.__init__(self, group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap)
def __init__(
self,
group_value_dict,
default=lambda x: 0.,
check_marked=(lambda x: x == 1),
overlap=lambda x: x[0],
**kwargs
):
CellExpressionFromXDMF.__init__(
self, group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap
)
def eval_cell(self, values, x, cell):
self.eval_cell_backend(values, x, cell)
@@ -162,13 +199,19 @@ else:
class Vector3DCellExpressionFromXDMF(fenics.Expression, CellExpressionFromXDMF):
def __init__(self, group_value_dict,
default=lambda x: np.zeros((3,)),
check_marked=(lambda x: x == 1), overlap=lambda x: x[0], **kwargs):
CellExpressionFromXDMF.__init__(self, group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap)
def __init__(
self,
group_value_dict,
default=lambda x: np.zeros((3,)),
check_marked=(lambda x: x == 1),
overlap=lambda x: x[0], **kwargs
):
CellExpressionFromXDMF.__init__(
self, group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap
)
def eval_cell(self, values, x, cell):
self.eval_cell_backend(values, x, cell)
@@ -178,13 +221,21 @@ else:
class Vector2DCellExpressionFromXDMF(fenics.Expression, CellExpressionFromXDMF):
def __init__(self, group_value_dict,
default=lambda x: np.zeros((2,)),
check_marked=(lambda x: x == 1), overlap=lambda x: x[0], **kwargs):
CellExpressionFromXDMF.__init__(self, group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap)
def __init__(
self,
group_value_dict,
default=lambda x: np.zeros((2,)),
check_marked=(lambda x: x == 1),
overlap=lambda x: x[0],
**kwargs
):
CellExpressionFromXDMF.__init__(
self,
group_value_dict,
default=default,
check_marked=check_marked,
overlap=overlap
)
def eval_cell(self, values, x, cell):
self.eval_cell_backend(values, x, cell)
@@ -210,7 +261,13 @@ else:
dbcs = []
for (dict_key, dict_value) in self.bcs.items():
if dict_value["type"] == "Dirichlet":
bc = fenics.DirichletBC(vectorspace, dict_value["value"], self.markers[dict_key], dict_value.get("marked", 1), *args, **kwargs)
bc = fenics.DirichletBC(
vectorspace,
dict_value["value"],
self.markers[dict_key],
dict_value.get("marked", 1),
*args, **kwargs
)
dbcs.append(bc)
return dbcs
# TODO: write some functions to return integrals for Neumann and Robin

View File

@@ -65,7 +65,8 @@ class _SolverDlg(object):
def get_binary(self):
# set the binary path to the FreeCAD defaults, ATM pure unix shell commands without path names are used
# set the binary path to the FreeCAD defaults
# ATM pure unix shell commands without path names are used
# TODO see todo on use_default later in this module
binary = self.default
FreeCAD.Console.PrintLog('Solver binary path: {} \n'.format(binary))
@@ -86,12 +87,14 @@ class _SolverDlg(object):
'''
default:
default command to run the binary, this one is taken if the UseStandardXXXLocation is not given or set to True
default command to run the binary
this one is taken if the UseStandardXXXLocationis not given or set to True
param:
path where these settings are saved, in FEM normally one path in one Tab in Preferences GUI
use_default:
the UseStandardXXXLocation parameter identifier
if this parameter is set to True FreeCAD standards for the binary are used, or FreeCAD tries to find the binary
if this parameter is set to True FreeCAD standards
for the binary are usedor FreeCAD tries to find the binary
TODO: see method setup_ccx in ccx tools module, which sets up ccx binary for various os
custom_path:
the xxxBinaryPath parameter identifier
@@ -128,7 +131,9 @@ def get_binary(name):
return binary
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in solver settings modules _SOLVER_PARAM dirctionary.\n'.format(name)
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
.format(name)
)
return None
@@ -138,7 +143,9 @@ def get_write_comments(name):
return _SOLVER_PARAM[name].get_write_comments()
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in solver settings modules _SOLVER_PARAM dirctionary.\n'.format(name)
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
.format(name)
)
return None

View File

@@ -82,8 +82,13 @@ class FemInputWriter():
# if dir_name was not given or if it exists but isn't empty: create a temporary dir
# Purpose: makes sure the analysis can be run even on wired situation
if not dir_name:
FreeCAD.Console.PrintError('Error: FemInputWriter has no working_dir --> we are going to make a temporary one!\n')
self.dir_name = FreeCAD.ActiveDocument.TransientDir.replace('\\', '/') + '/FemAnl_' + analysis_obj.Uid[-4:]
FreeCAD.Console.PrintError(
'Error: FemInputWriter has no working_dir --> '
'we are going to make a temporary one!\n'
)
self.dir_name = FreeCAD.ActiveDocument.TransientDir.replace(
'\\', '/'
) + '/FemAnl_' + analysis_obj.Uid[-4:]
if not os.path.isdir(self.dir_name):
os.mkdir(self.dir_name)
@@ -102,7 +107,9 @@ class FemInputWriter():
self.theshape = self.mesh_object.Part
self.femmesh = self.mesh_object.FemMesh
else:
FreeCAD.Console.PrintError('No finite elemente mesh object was given to the writer class. In rare cases this might not be an error.\n')
FreeCAD.Console.PrintError(
'No finite elemente mesh object was given to the writer class. '
'In rare cases this might not be an error.\n')
self.femnodes_mesh = {}
self.femelement_table = {}
self.constraint_conflict_nodes = []
@@ -116,18 +123,29 @@ class FemInputWriter():
def get_constraints_fixed_nodes(self):
# get nodes
for femobj in self.fixed_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint fixed:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.fixed_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint fixed:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
# add nodes to constraint_conflict_nodes, needed by constraint plane rotation
for node in femobj['Nodes']:
self.constraint_conflict_nodes.append(node)
# if mixed mesh with solids the node set needs to be split because solid nodes do not have rotational degree of freedom
if self.femmesh.Volumes and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
# if mixed mesh with solids the node set needs to be split
# because solid nodes do not have rotational degree of freedom
if self.femmesh.Volumes \
and (len(self.shellthickness_objects) > 0 or len(self.beamsection_objects) > 0):
print('We need to find the solid nodes.')
if not self.femelement_volumes_table:
self.femelement_volumes_table = meshtools.get_femelement_volumes_table(self.femmesh)
for femobj in self.fixed_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
self.femelement_volumes_table = meshtools.get_femelement_volumes_table(
self.femmesh
)
for femobj in self.fixed_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
nds_solid = []
nds_faceedge = []
for n in femobj['Nodes']:
@@ -144,77 +162,145 @@ class FemInputWriter():
def get_constraints_displacement_nodes(self):
# get nodes
for femobj in self.displacement_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint displacement:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.displacement_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint displacement:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
# add nodes to constraint_conflict_nodes, needed by constraint plane rotation
for node in femobj['Nodes']:
self.constraint_conflict_nodes.append(node)
def get_constraints_planerotation_nodes(self):
# get nodes
for femobj in self.planerotation_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint plane rotation:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.planerotation_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint plane rotation:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
def get_constraints_transform_nodes(self):
# get nodes
for femobj in self.transform_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint transform nodes:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.transform_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint transform nodes:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
def get_constraints_temperature_nodes(self):
# get nodes
for femobj in self.temperature_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint temperature:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.temperature_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint temperature:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
def get_constraints_fluidsection_nodes(self):
# get nodes
for femobj in self.fluidsection_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint fluid section:" + ' ' + femobj['Object'].Name + '\n')
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(self.femmesh, femobj)
for femobj in self.fluidsection_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint fluid section:" + ' ' + femobj['Object'].Name + '\n'
)
femobj['Nodes'] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
def get_constraints_force_nodeloads(self):
# check shape type of reference shape
for femobj in self.force_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint force:" + ' ' + femobj['Object'].Name + '\n')
for femobj in self.force_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint force:" + ' ' + femobj['Object'].Name + '\n'
)
frc_obj = femobj['Object']
if femobj['RefShapeType'] == 'Vertex':
# print("load on vertices --> we do not need the femelement_table and femnodes_mesh for node load calculation")
pass
elif femobj['RefShapeType'] == 'Face' and meshtools.is_solid_femmesh(self.femmesh) and not meshtools.has_no_face_data(self.femmesh):
# print("solid_mesh with face data --> we do not need the femelement_table but we need the femnodes_mesh for node load calculation")
FreeCAD.Console.PrintLog(
"load on vertices --> we do not need the "
"femelement_table and femnodes_mesh for node load calculation"
)
elif femobj['RefShapeType'] == 'Face' \
and meshtools.is_solid_femmesh(self.femmesh) \
and not meshtools.has_no_face_data(self.femmesh):
FreeCAD.Console.PrintLog(
"solid_mesh with face data --> we do not need the "
"femelement_table but we need the femnodes_mesh for node load calculation"
)
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
else:
# print("mesh without needed data --> we need the femelement_table and femnodes_mesh for node load calculation")
FreeCAD.Console.PrintLog(
"mesh without needed data --> we need the "
"femelement_table and femnodes_mesh for node load calculation"
)
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
if not self.femelement_table:
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
self.femelement_table = meshtools.get_femelement_table(
self.femmesh
)
# get node loads
FreeCAD.Console.PrintMessage(" Finite element mesh nodes will be retrieved by searching the appropriate nodes in the finite element mesh.\n")
FreeCAD.Console.PrintMessage(" The appropriate finite element mesh node load values will be calculated according to the finite element definition.\n")
for femobj in self.force_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
" Finite element mesh nodes will be retrieved by searching "
"the appropriate nodes in the finite element mesh.\n"
)
FreeCAD.Console.PrintMessage(
" The appropriate finite element mesh node load values will "
"be calculated according to the finite element definition.\n"
)
for femobj in self.force_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
frc_obj = femobj['Object']
if frc_obj.Force == 0:
FreeCAD.Console.PrintMessage(' Warning --> Force = 0\n')
if femobj['RefShapeType'] == 'Vertex': # point load on vertices
femobj['NodeLoadTable'] = meshtools.get_force_obj_vertex_nodeload_table(self.femmesh, frc_obj)
femobj['NodeLoadTable'] = meshtools.get_force_obj_vertex_nodeload_table(
self.femmesh,
frc_obj
)
elif femobj['RefShapeType'] == 'Edge': # line load on edges
femobj['NodeLoadTable'] = meshtools.get_force_obj_edge_nodeload_table(self.femmesh, self.femelement_table, self.femnodes_mesh, frc_obj)
femobj['NodeLoadTable'] = meshtools.get_force_obj_edge_nodeload_table(
self.femmesh,
self.femelement_table,
self.femnodes_mesh, frc_obj
)
elif femobj['RefShapeType'] == 'Face': # area load on faces
femobj['NodeLoadTable'] = meshtools.get_force_obj_face_nodeload_table(self.femmesh, self.femelement_table, self.femnodes_mesh, frc_obj)
femobj['NodeLoadTable'] = meshtools.get_force_obj_face_nodeload_table(
self.femmesh,
self.femelement_table,
self.femnodes_mesh, frc_obj
)
def get_constraints_pressure_faces(self):
# TODO see comments in get_constraints_force_nodeloads(), it applies here too. Mhh it applies to all constraints ...
# TODO see comments in get_constraints_force_nodeloads()
# it applies here too. Mhh it applies to all constraints ...
'''
# depreciated version
# get the faces and face numbers
for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
femobj['PressureFaces'] = meshtools.get_pressure_obj_faces_depreciated(self.femmesh, femobj)
for femobj in self.pressure_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
femobj['PressureFaces'] = meshtools.get_pressure_obj_faces_depreciated(
self.femmesh,
femobj
)
# print(femobj['PressureFaces'])
'''
@@ -223,11 +309,21 @@ class FemInputWriter():
if not self.femelement_table:
self.femelement_table = meshtools.get_femelement_table(self.femmesh)
if not self.femnodes_ele_table:
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table)
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
self.femnodes_mesh,
self.femelement_table
)
for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage("Constraint pressure: " + femobj['Object'].Name + '\n')
pressure_faces = meshtools.get_pressure_obj_faces(self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj)
for femobj in self.pressure_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
FreeCAD.Console.PrintMessage(
"Constraint pressure: " + femobj['Object'].Name + '\n'
)
pressure_faces = meshtools.get_pressure_obj_faces(
self.femmesh,
self.femelement_table,
self.femnodes_ele_table, femobj
)
femobj['PressureFaces'] = [(femobj['Object'].Name + ': face load', pressure_faces)]
FreeCAD.Console.PrintLog('{}\n'.format(femobj['PressureFaces']))
@@ -235,42 +331,74 @@ class FemInputWriter():
# get element ids and write them into the objects
FreeCAD.Console.PrintMessage('Shell thicknesses\n')
if not self.femelement_faces_table:
self.femelement_faces_table = meshtools.get_femelement_faces_table(self.femmesh)
meshtools.get_femelement_sets(self.femmesh, self.femelement_faces_table, self.shellthickness_objects)
self.femelement_faces_table = meshtools.get_femelement_faces_table(
self.femmesh
)
meshtools.get_femelement_sets(
self.femmesh,
self.femelement_faces_table,
self.shellthickness_objects
)
def get_element_geometry1D_elements(self):
# get element ids and write them into the objects
FreeCAD.Console.PrintMessage('Beam sections\n')
if not self.femelement_edges_table:
self.femelement_edges_table = meshtools.get_femelement_edges_table(self.femmesh)
meshtools.get_femelement_sets(self.femmesh, self.femelement_edges_table, self.beamsection_objects)
self.femelement_edges_table = meshtools.get_femelement_edges_table(
self.femmesh
)
meshtools.get_femelement_sets(
self.femmesh,
self.femelement_edges_table,
self.beamsection_objects
)
def get_element_rotation1D_elements(self):
# get for each geometry edge direction the element ids and rotation norma
FreeCAD.Console.PrintMessage('Beam rotations\n')
if not self.femelement_edges_table:
self.femelement_edges_table = meshtools.get_femelement_edges_table(self.femmesh)
meshtools.get_femelement_direction1D_set(self.femmesh, self.femelement_edges_table, self.beamrotation_objects, self.theshape)
self.femelement_edges_table = meshtools.get_femelement_edges_table(
self.femmesh
)
meshtools.get_femelement_direction1D_set(
self.femmesh,
self.femelement_edges_table,
self.beamrotation_objects,
self.theshape
)
def get_element_fluid1D_elements(self):
# get element ids and write them into the objects
FreeCAD.Console.PrintMessage('Fluid sections\n')
if not self.femelement_edges_table:
self.femelement_edges_table = meshtools.get_femelement_edges_table(self.femmesh)
meshtools.get_femelement_sets(self.femmesh, self.femelement_edges_table, self.fluidsection_objects)
self.femelement_edges_table = meshtools.get_femelement_edges_table(
self.femmesh
)
meshtools.get_femelement_sets(
self.femmesh,
self.femelement_edges_table,
self.fluidsection_objects
)
def get_material_elements(self):
# it only works if either Volumes or Shellthicknesses or Beamsections are in the material objects
# it means it does not work for mixed meshes and multiple materials, this is checked in check_prerequisites
# the femelement_table is only calculated for the highest dimension in get_femelement_table
# it only works if either Volumes or Shellthicknesses or Beamsections
# are in the material objects, it means it does not work
# for mixed meshes and multiple materials, this is checked in check_prerequisites
# the femelement_table is only calculated for
# the highest dimension in get_femelement_table
FreeCAD.Console.PrintMessage('Materials\n')
if self.femmesh.Volumes:
# we only could do this for volumes, if a mesh contains volumes we're going to use them in the analysis
# but a mesh could contain the element faces of the volumes as faces and the edges of the faces as edges,
# we only could do this for volumes, if a mesh contains volumes
# we're going to use them in the analysis
# but a mesh could contain the element faces of the volumes as faces
# and the edges of the faces as edges
# there we have to check of some geometric objects
all_found = False
if self.femmesh.GroupCount:
all_found = meshtools.get_femelement_sets_from_group_data(self.femmesh, self.material_objects)
all_found = meshtools.get_femelement_sets_from_group_data(
self.femmesh,
self.material_objects
)
FreeCAD.Console.PrintMessage(all_found)
FreeCAD.Console.PrintMessage('\n')
if all_found is False:
@@ -281,17 +409,38 @@ class FemInputWriter():
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
if not self.femnodes_ele_table:
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table)
control = meshtools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects, self.femnodes_ele_table)
if (self.femelement_count_test is True) and (control is False): # we only need to set it, if it is still True
self.femnodes_ele_table = meshtools.get_femnodes_ele_table(
self.femnodes_mesh,
self.femelement_table
)
control = meshtools.get_femelement_sets(
self.femmesh,
self.femelement_table,
self.material_objects,
self.femnodes_ele_table
)
# we only need to set it, if it is still True
if (self.femelement_count_test is True) and (control is False):
self.femelement_count_test = False
if self.shellthickness_objects:
if not self.femelement_faces_table:
self.femelement_faces_table = meshtools.get_femelement_faces_table(self.femmesh)
meshtools.get_femelement_sets(self.femmesh, self.femelement_faces_table, self.material_objects)
self.femelement_faces_table = meshtools.get_femelement_faces_table(
self.femmesh
)
meshtools.get_femelement_sets(
self.femmesh,
self.femelement_faces_table,
self.material_objects
)
if self.beamsection_objects or self.fluidsection_objects:
if not self.femelement_edges_table:
self.femelement_edges_table = meshtools.get_femelement_edges_table(self.femmesh)
meshtools.get_femelement_sets(self.femmesh, self.femelement_edges_table, self.material_objects)
self.femelement_edges_table = meshtools.get_femelement_edges_table(
self.femmesh
)
meshtools.get_femelement_sets(
self.femmesh,
self.femelement_edges_table,
self.material_objects
)
## @}

View File

@@ -91,7 +91,8 @@ class Solve(run.Solve):
def run(self):
# AFAIK: z88r needs to be run twice, once in test mode and once in real solve mode
# the subprocess was just copied, it seems to work :-)
# TODO: search out for "Vektor GS" and "Vektor KOI" and print values, may be compared with the used ones
# TODO: search out for "Vektor GS" and "Vektor KOI" and print values
# may be compared with the used ones
self.pushStatus("Executing test solver...\n")
binary = settings.get_binary("Z88")
self._process = subprocess.Popen(
@@ -159,22 +160,39 @@ class _Container(object):
self.mesh = mesh
else:
if FreeCAD.GuiUp:
QtGui.QMessageBox.critical(None, "Missing prerequisite", message)
QtGui.QMessageBox.critical(
None,
"Missing prerequisite",
message
)
raise Exception(message + '\n')
# get member, empty lists are not supported by z88
self.materials_linear = self.get_several_member('Fem::Material')
# materials
self.materials_linear = self.get_several_member(
'Fem::Material'
)
self.materials_nonlinear = []
self.beam_sections = self.get_several_member('Fem::FemElementGeometry1D')
# geometries
self.beam_sections = self.get_several_member(
'Fem::FemElementGeometry1D'
)
self.beam_rotations = []
self.fluid_sections = []
self.shell_thicknesses = self.get_several_member('Fem::FemElementGeometry2D')
self.shell_thicknesses = self.get_several_member(
'Fem::FemElementGeometry2D'
)
# constraints
self.constraints_contact = []
self.constraints_displacement = []
self.constraints_fixed = self.get_several_member('Fem::ConstraintFixed')
self.constraints_force = self.get_several_member('Fem::ConstraintForce')
self.constraints_fixed = self.get_several_member(
'Fem::ConstraintFixed'
)
self.constraints_force = self.get_several_member(
'Fem::ConstraintForce'
)
self.constraints_heatflux = []
self.constraints_initialtemperature = []
self.constraints_pressure = []

View File

@@ -84,8 +84,12 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
)
from os.path import join
self.file_name = join(self.dir_name, 'z88')
FreeCAD.Console.PrintLog('FemInputWriterZ88 --> self.dir_name --> ' + self.dir_name + '\n')
FreeCAD.Console.PrintMessage('FemInputWriterZ88 --> self.file_name --> ' + self.file_name + '\n')
FreeCAD.Console.PrintLog(
'FemInputWriterZ88 --> self.dir_name --> ' + self.dir_name + '\n'
)
FreeCAD.Console.PrintMessage(
'FemInputWriterZ88 --> self.file_name --> ' + self.file_name + '\n'
)
def write_z88_input(self):
timestart = time.clock()
@@ -103,7 +107,10 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
self.write_z88_integration_properties()
self.write_z88_memory_parameter()
self.write_z88_solver_parameter()
writing_time_string = "Writing time input file: " + str(round((time.clock() - timestart), 2)) + " seconds"
writing_time_string = (
"Writing time input file: {} seconds"
.format(round((time.clock() - timestart), 2))
)
FreeCAD.Console.PrintMessage(writing_time_string + ' \n\n')
return self.dir_name
@@ -118,7 +125,10 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
z8810 = {'INTORD': '3', 'INTOS': '0', 'IHFLAG': '0', 'ISFLAG': '0'} # hexa20 --> volume10
param = {4: z8804, 24: z8824, 23: z8823, 17: z8817, 16: z8816, 1: z8801, 10: z8810}
# elemente 17, 16, 10, INTORD etc ... testen !!!
self.z88_element_type = importZ88Mesh.get_z88_element_type(self.femmesh, self.femelement_table)
self.z88_element_type = importZ88Mesh.get_z88_element_type(
self.femmesh,
self.femelement_table
)
if self.z88_element_type in param:
self.z88_elparam = param[self.z88_element_type]
else:
@@ -129,7 +139,12 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
def write_z88_mesh(self):
mesh_file_path = self.file_name + 'i1.txt'
f = open(mesh_file_path, 'w')
importZ88Mesh.write_z88_mesh_to_file(self.femnodes_mesh, self.femelement_table, self.z88_element_type, f)
importZ88Mesh.write_z88_mesh_to_file(
self.femnodes_mesh,
self.femelement_table,
self.z88_element_type,
f
)
f.close()
def write_z88_contraints(self):
@@ -138,7 +153,7 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
# fixed constraints
# get nodes
self.get_constraints_fixed_nodes()
# write nodes to constraints_data (different from writing to file in ccxInpWriter)
# write nodes to constraints_data (different from writing to file in ccxInpWriter
for femobj in self.fixed_objects:
for n in femobj['Nodes']:
constraints_data.append((n, str(n) + ' 1 2 0\n'))
@@ -148,8 +163,10 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
# forces constraints
# check shape type of reference shape and get node loads
self.get_constraints_force_nodeloads()
# write node loads to constraints_data (a bit different from writing to file for ccxInpWriter)
for femobj in self.force_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
# write node loads to constraints_data
# a bit different from writing to file for ccxInpWriter
for femobj in self.force_objects:
# femobj --> dict, FreeCAD document object is femobj['Object']
direction_vec = femobj['Object'].DirectionVector
for ref_shape in femobj['NodeLoadTable']:
for n in sorted(ref_shape[1]):
@@ -210,17 +227,25 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
width = beam_obj.RectWidth.getValueAs('mm')
height = beam_obj.RectHeight.getValueAs('mm')
area = str(width * height)
elements_data.append('1 ' + str(self.element_count) + ' ' + area + ' 0 0 0 0 0 0 ')
FreeCAD.Console.PrintMessage("Be aware, only trusses are supported for edge meshes!\n")
elements_data.append(
'1 ' + str(self.element_count) + ' ' + area + ' 0 0 0 0 0 0 '
)
FreeCAD.Console.PrintMessage(
"Be aware, only trusses are supported for edge meshes!\n"
)
else:
FreeCAD.Console.PrintError("Multiple beamsections for Z88 not yet supported!\n")
elif FemMeshTools.is_face_femmesh(self.femmesh):
if len(self.shellthickness_objects) == 1:
thick_obj = self.shellthickness_objects[0]['Object']
thickness = str(thick_obj.Thickness.getValueAs('mm'))
elements_data.append('1 ' + str(self.element_count) + ' ' + thickness + ' 0 0 0 0 0 0 ')
elements_data.append(
'1 ' + str(self.element_count) + ' ' + thickness + ' 0 0 0 0 0 0 '
)
else:
FreeCAD.Console.PrintError("Multiple thicknesses for Z88 not yet supported!\n")
FreeCAD.Console.PrintError(
"Multiple thicknesses for Z88 not yet supported!\n"
)
elif FemMeshTools.is_solid_femmesh(self.femmesh):
elements_data.append('1 ' + str(self.element_count) + ' 0 0 0 0 0 0 0')
else:
@@ -234,7 +259,11 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
def write_z88_integration_properties(self):
integration_data = []
integration_data.append('1 ' + str(self.element_count) + ' ' + self.z88_elparam['INTORD'] + ' ' + self.z88_elparam['INTOS'])
integration_data.append('1 {} {} {}'.format(
self.element_count,
self.z88_elparam['INTORD'],
self.z88_elparam['INTOS']
))
integration_properties_file_path = self.file_name + 'int.txt'
f = open(integration_properties_file_path, 'w')
f.write(str(len(integration_data)) + '\n')
@@ -245,8 +274,12 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
def write_z88_solver_parameter(self):
global z88_man_template
z88_man_template = z88_man_template.replace("$z88_param_ihflag", str(self.z88_elparam['IHFLAG']))
z88_man_template = z88_man_template.replace("$z88_param_isflag", str(self.z88_elparam['ISFLAG']))
z88_man_template = z88_man_template.replace(
"$z88_param_ihflag", str(self.z88_elparam['IHFLAG'])
)
z88_man_template = z88_man_template.replace(
"$z88_param_isflag", str(self.z88_elparam['ISFLAG'])
)
solver_parameter_file_path = self.file_name + 'man.txt'
f = open(solver_parameter_file_path, 'w')
f.write(z88_man_template)
@@ -256,7 +289,10 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
# self.z88_param_maxgs = 6000000
self.z88_param_maxgs = 50000000 # vierkantrohr
global z88_dyn_template
z88_dyn_template = z88_dyn_template.replace("$z88_param_maxgs", str(self.z88_param_maxgs))
z88_dyn_template = z88_dyn_template.replace(
"$z88_param_maxgs",
str(self.z88_param_maxgs)
)
solver_parameter_file_path = self.file_name + '.dyn'
f = open(solver_parameter_file_path, 'w')
f.write(z88_dyn_template)