Skip to content

Commit

Permalink
Merge pull request #438 from berndhahnebach/bhbdev063
Browse files Browse the repository at this point in the history
FEM
  • Loading branch information
wwmayer committed Jan 14, 2017
2 parents e441c2a + e2b5623 commit 6115e78
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 42 deletions.
18 changes: 13 additions & 5 deletions src/Mod/Fem/FemTools.py
Expand Up @@ -307,6 +307,7 @@ def update_objects(self):
self.shell_thicknesses.append(shell_thickness_dict)

def check_prerequisites(self):
import Units
message = ""
# analysis
if not self.analysis:
Expand Down Expand Up @@ -352,20 +353,27 @@ def check_prerequisites(self):
has_no_references = True
for m in self.materials_linear:
mat_map = m['Object'].Material
if 'YoungsModulus' not in mat_map:
if 'YoungsModulus' in mat_map:
# print Units.Quantity(mat_map['YoungsModulus']).Value
if not Units.Quantity(mat_map['YoungsModulus']).Value:
message += "Value of YoungsModulus is set to 0.0.\n"
else:
message += "No YoungsModulus defined for at least one material.\n"
if 'PoissonRatio' not in mat_map:
message += "No PoissonRatio defined for at least one material.\n"
message += "No PoissonRatio defined for at least one material.\n" # PoissonRatio is allowed to be 0.0 (in ccx), but it should be set anyway.
if self.analysis_type == "frequency" or self.selfweight_constraints:
if 'Density' not in mat_map:
message += "No Density defined for at least one material.\n"
if self.analysis_type == "thermomech":
if 'ThermalConductivity' not in mat_map:
if 'ThermalConductivity' in mat_map:
if not Units.Quantity(mat_map['ThermalConductivity']).Value:
message += "Value of ThermalConductivity is set to 0.0.\n"
else:
message += "Thermomechanical analysis: No ThermalConductivity defined for at least one material.\n"
if 'ThermalExpansionCoefficient' not in mat_map:
message += "Thermomechanical analysis: No ThermalExpansionCoefficient defined for at least one material.\n"
message += "Thermomechanical analysis: No ThermalExpansionCoefficient defined for at least one material.\n" # allowed to be 0.0 (in ccx)
if 'SpecificHeat' not in mat_map:
message += "Thermomechanical analysis: No SpecificHeat defined for at least one material.\n"
message += "Thermomechanical analysis: No SpecificHeat defined for at least one material.\n" # allowed to be 0.0 (in ccx)
for m in self.materials_linear:
has_nonlinear_material = False
for nlm in self.materials_nonlinear:
Expand Down
112 changes: 90 additions & 22 deletions src/Mod/Fem/TestFem.py
Expand Up @@ -52,6 +52,10 @@
frequency_expected_values = test_file_dir + "/cube_frequency_expected_values"
thermomech_analysis_inp_file = test_file_dir + '/' + thermomech_base_name + '.inp'
thermomech_expected_values = test_file_dir + "/spine_thermomech_expected_values"
static_save_fc_file = static_analysis_dir + '/' + static_base_name + '.fcstd'
frequency_save_fc_file = frequency_analysis_dir + '/' + frequency_base_name + '.fcstd'
thermomech_save_fc_file = thermomech_analysis_dir + '/' + thermomech_base_name + '.fcstd'

mesh_points_file = test_file_dir + '/mesh_points.csv'
mesh_volumes_file = test_file_dir + '/mesh_volumes.csv'
spine_points_file = test_file_dir + '/spine_points.csv'
Expand All @@ -76,7 +80,7 @@ def setUp(self):
self.active_doc.recompute()

def create_new_analysis(self):
self.analysis = FemAnalysis.makeFemAnalysis('MechanicalAnalysis')
self.analysis = FemAnalysis.makeFemAnalysis('Analysis')
self.active_doc.recompute()

def create_new_solver(self):
Expand Down Expand Up @@ -134,6 +138,9 @@ def create_pressure_constraint(self):
self.pressure_constraint.Pressure = 1000.0
self.pressure_constraint.Reversed = False

def save_file(self, fc_file_name):
self.active_doc.saveAs(fc_file_name)

def force_unix_line_ends(self, line_list):
new_line_list = []
for l in line_list:
Expand All @@ -146,12 +153,12 @@ def compare_inp_files(self, file_name1, file_name2):
file1 = open(file_name1, 'r')
f1 = file1.readlines()
file1.close()
lf1 = [l for l in f1 if not l.startswith('** written ')]
lf1 = [l for l in f1 if not (l.startswith('** written ') or l.startswith('** file '))]
lf1 = self.force_unix_line_ends(lf1)
file2 = open(file_name2, 'r')
f2 = file2.readlines()
file2.close()
lf2 = [l for l in f2 if not l.startswith('** written ')]
lf2 = [l for l in f2 if not (l.startswith('** written ') or l.startswith('** file '))]
lf2 = self.force_unix_line_ends(lf2)
import difflib
diff = difflib.unified_diff(lf1, lf2, n=0)
Expand Down Expand Up @@ -181,6 +188,7 @@ def compare_stats(self, fea, stat_file=None):
return False

def test_new_analysis(self):
# static
fcc_print('--------------- Start of FEM tests ---------------')
fcc_print('Checking FEM new analysis...')
self.create_new_analysis()
Expand Down Expand Up @@ -263,6 +271,11 @@ def test_new_analysis(self):
ret = self.compare_stats(fea, static_expected_values)
self.assertFalse(ret, "Invalid results read from .frd file")

fcc_print('Save FreeCAD file for static analysis to {}...'.format(static_save_fc_file))
self.save_file(static_save_fc_file)
self.assertTrue(self.save_file, "FemTest saving of file {} failed ...".format(static_save_fc_file))

# frequency
fcc_print('Setting analysis type to \'frequency\"')
fea.set_analysis_type("frequency")
self.assertTrue(True if fea.analysis_type == 'frequency' else False, "Setting anlysis type to \'frequency\' failed")
Expand Down Expand Up @@ -307,7 +320,11 @@ def test_new_analysis(self):
ret = self.compare_stats(fea, frequency_expected_values)
self.assertFalse(ret, "Invalid results read from .frd file")

fcc_print('--------------- End of FEM tests ---------------')
fcc_print('Save FreeCAD file for frequency analysis to {}...'.format(frequency_save_fc_file))
self.save_file(frequency_save_fc_file)
self.assertTrue(self.save_file, "FemTest saving of file {} failed ...".format(frequency_save_fc_file))

fcc_print('--------------- End of FEM tests static and frequency analysis ---------------')

def tearDown(self):
FreeCAD.closeDocument("FemTest")
Expand Down Expand Up @@ -336,6 +353,7 @@ def create_new_analysis(self):

def create_new_solver(self):
self.solver_object = FemSolverCalculix.makeFemSolverCalculix('CalculiX')
self.solver_object.AnalysisType = 'thermomech'
self.solver_object.GeometricalNonlinearity = 'linear'
self.solver_object.ThermoMechSteadyState = True
self.solver_object.MatrixSolverType = 'default'
Expand Down Expand Up @@ -392,6 +410,9 @@ def create_heatflux_constraint(self):
self.heatflux_constraint.AmbientTemp = 255.3722
self.heatflux_constraint.FilmCoef = 5.678

def save_file(self, fc_file_name):
self.active_doc.saveAs(fc_file_name)

def force_unix_line_ends(self, line_list):
new_line_list = []
for l in line_list:
Expand Down Expand Up @@ -518,26 +539,46 @@ def test_new_analysis(self):
self.assertTrue(True if fea.inp_file_name == thermomech_analysis_inp_file else False,
"Setting inp file name to {} failed".format(thermomech_analysis_inp_file))

fcc_print('Checking FEM frd file read from thermomech analysis...')
fea.load_results()
self.assertTrue(fea.results_present, "Cannot read results from {}.frd frd file".format(fea.base_name))

fcc_print('Reading stats from result object for thermomech analysis...')
ret = self.compare_stats(fea, thermomech_expected_values)
self.assertFalse(ret, "Invalid results read from .frd file")

fcc_print('Save FreeCAD file for thermomech analysis to {}...'.format(thermomech_save_fc_file))
self.save_file(thermomech_save_fc_file)
self.assertTrue(self.save_file, "FemTest saving of file {} failed ...".format(thermomech_save_fc_file))

fcc_print('--------------- End of FEM tests thermomech analysis ---------------')

def tearDown(self):
FreeCAD.closeDocument("TherMechFemTest")
pass


# helpers
def open_cube_test():
cube_file = test_file_dir + '/cube.fcstd'
FreeCAD.open(cube_file)
def run_fem_unittests():
import unittest
suite = unittest.TestSuite()
suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestFem"))
r = unittest.TextTestRunner()
r.run(suite)


def create_test_results():
# run FEM unit tests
run_fem_unittests()

def create_cube_test_results():
import os
import shutil
cube_file = test_file_dir + '/cube.fcstd'

FreeCAD.open(cube_file)
import FemGui
FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.MechanicalAnalysis)
import FemToolsCcx

# static and frequency cube
FreeCAD.open(static_save_fc_file)
FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis)
fea = FemToolsCcx.FemToolsCcx()

# static
Expand All @@ -549,7 +590,7 @@ def create_cube_test_results():
stats_static = [] # we only have one result object so we are fine
for s in stat_types:
stats_static.append("{}: {}\n".format(s, fea.get_stats(s)))
static_expected_values_file = temp_dir + '/cube_static_expected_values'
static_expected_values_file = static_analysis_dir + '/cube_static_expected_values'
f = open(static_expected_values_file, 'w')
for s in stats_static:
f.write(s)
Expand All @@ -559,8 +600,8 @@ def create_cube_test_results():
frd_result_file = os.path.splitext(fea.inp_file_name)[0] + '.frd'
dat_result_file = os.path.splitext(fea.inp_file_name)[0] + '.dat'

frd_static_test_result_file = temp_dir + '/cube_static.frd'
dat_static_test_result_file = temp_dir + '/cube_static.dat'
frd_static_test_result_file = static_analysis_dir + '/cube_static.frd'
dat_static_test_result_file = static_analysis_dir + '/cube_static.dat'
shutil.copyfile(frd_result_file, frd_static_test_result_file)
shutil.copyfile(dat_result_file, dat_static_test_result_file)

Expand All @@ -574,28 +615,55 @@ def create_cube_test_results():
stats_frequency = [] # since we set eigenmodeno. we only have one result object so we are fine
for s in stat_types:
stats_frequency.append("{}: {}\n".format(s, fea.get_stats(s)))
frequency_expected_values_file = temp_dir + '/cube_frequency_expected_values'
frequency_expected_values_file = frequency_analysis_dir + '/cube_frequency_expected_values'
f = open(frequency_expected_values_file, 'w')
for s in stats_frequency:
f.write(s)
f.close()

frd_frequency_test_result_file = temp_dir + '/cube_frequency.frd'
dat_frequency_test_result_file = temp_dir + '/cube_frequency.dat'
frd_frequency_test_result_file = frequency_analysis_dir + '/cube_frequency.frd'
dat_frequency_test_result_file = frequency_analysis_dir + '/cube_frequency.dat'
shutil.copyfile(frd_result_file, frd_frequency_test_result_file)
shutil.copyfile(dat_result_file, dat_frequency_test_result_file)

print('Results copied to: ' + temp_dir)
# thermomech
FreeCAD.open(thermomech_save_fc_file)
FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis)
fea = FemToolsCcx.FemToolsCcx()
fea.reset_all()
fea.run()

fea.load_results()
stat_types = ["U1", "U2", "U3", "Uabs", "Sabs"]
stats_thermomech = [] # we only have one result object so we are fine
for s in stat_types:
stats_thermomech.append("{}: {}\n".format(s, fea.get_stats(s)))
thermomech_expected_values_file = thermomech_analysis_dir + '/expected_values_thermomech'
f = open(thermomech_expected_values_file, 'w')
for s in stats_thermomech:
f.write(s)
f.close()

# could be added in FemToolsCcx to the self object as an Attribut
frd_result_file = os.path.splitext(fea.inp_file_name)[0] + '.frd'
dat_result_file = os.path.splitext(fea.inp_file_name)[0] + '.dat'

frd_thermomech_test_result_file = thermomech_analysis_dir + '/spine_thermomech.frd'
dat_thermomech_test_result_file = thermomech_analysis_dir + '/spine_thermomech.dat'
shutil.copyfile(frd_result_file, frd_thermomech_test_result_file)
shutil.copyfile(dat_result_file, dat_thermomech_test_result_file)

print('Results copied to the appropriate FEM test dirs in: ' + temp_dir)


'''
update the results in FEM untit tests:
start FreeCAD
import TestFem
TestFem.create_cube_test_results()
TestFem.create_test_results()
copy result files from /tmp into the src dirctory
copy result files from FEM test directories into the src dirctory
compare the results with git difftool
run make
start FreeCAD and run FEM unit test
if FEM unit test is fine --> commit new FEM unit test results
Expand Down
6 changes: 3 additions & 3 deletions src/Mod/Fem/_TaskPanelShowResult.py
Expand Up @@ -231,15 +231,15 @@ def calculate(self):
x = np.array(dispvectors[:, 0])
y = np.array(dispvectors[:, 1])
z = np.array(dispvectors[:, 2])
stressvectors = np.array(self.result_object.StressVectors)
stressvectors = np.array(self.result_object.StressVectors)
sx = np.array(stressvectors[:, 0])
sy = np.array(stressvectors[:, 1])
sz = np.array(stressvectors[:, 2])
strainvectors = np.array(self.result_object.StrainVectors)
strainvectors = np.array(self.result_object.StrainVectors)
ex = np.array(strainvectors[:, 0])
ey = np.array(strainvectors[:, 1])
ez = np.array(strainvectors[:, 2])
userdefined_eq = x + y + z + T + Von + P1 + P2 + P3 + sx + sy + sz + ex + ey + ez # Dummy equation to get around flake8, varibles not being used
userdefined_eq = x + y + z + T + Von + P1 + P2 + P3 + sx + sy + sz + ex + ey + ez # Dummy equation to get around flake8, varibles not being used
userdefined_eq = self.form.user_def_eq.toPlainText() # Get equation to be used
UserDefinedFormula = eval(userdefined_eq).tolist()
self.result_object.UserDefined = UserDefinedFormula
Expand Down
2 changes: 1 addition & 1 deletion src/Mod/Fem/ccxFrdReader.py
Expand Up @@ -256,7 +256,7 @@ def readResult(frd_input):
elements_seg2[elem] = (nd1, nd2)
elif elemType == 12:
# B32 CalculiX --> seg3 FreeCAD
# Also D element element number
# Also D element element number
# N1, N3 ,N2 Order in outpufile is 1,3,2
nd1 = int(line[3:13])
nd3 = int(line[13:23])
Expand Down
Binary file added src/Mod/Fem/test_files/ccx/cube_frequency.fcstd
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Mod/Fem/test_files/ccx/cube_frequency.inp
Expand Up @@ -525,7 +525,7 @@ S
** written by --> FreeCAD 0.16.5838 +1 (Git)
** written on --> Mon Oct 26 18:34:01 2015
** file name -->
** analysis name --> MechanicalAnalysis
** analysis name --> Analysis
**
**
**
Expand Down
Binary file added src/Mod/Fem/test_files/ccx/cube_static.fcstd
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Mod/Fem/test_files/ccx/cube_static.inp
Expand Up @@ -588,7 +588,7 @@ S
** written by --> FreeCAD 0.16.5838 +1 (Git)
** written on --> Mon Oct 26 18:28:42 2015
** file name -->
** analysis name --> MechanicalAnalysis
** analysis name --> Analysis
**
**
**
Expand Down
Binary file modified src/Mod/Fem/test_files/ccx/spine_thermomech.fcstd
Binary file not shown.
14 changes: 5 additions & 9 deletions src/Mod/Fem/test_files/ccx/spine_thermomech_expected_values
@@ -1,9 +1,5 @@
U1: (-0.000942455, 0.00305855, 0.00729818)
U2: (-0.00163382, 0.000616589, 0.00222318)
U3: (-0.00185329, 0.000543914, 0.00220675)
Uabs: (0, 0.00364478, 0.00732571)
Sabs: (0.307123, 7.74746, 35.8618)
MaxPrin: (-5.82387, 1.31924, 10.9205)
MidPrin: (-37.7671, -4.87764, 10.9098)
MinPrin: (-39.3672, -7.02358, 6.47377)
MaxShear: (0.168182, 4.17141, 18.1004)
U1: (-0.000942455, 0.0030585454755555556, 0.00729818)
U2: (-0.00163382, 0.0006165889555555556, 0.00222318)
U3: (-0.00185329, 0.0005439136222222222, 0.00220675)
Uabs: (0.0, 0.003644782698151031, 0.007325712241135124)
Sabs: (0.30712297252407333, 7.747458526266711, 35.86180372766652)

0 comments on commit 6115e78

Please sign in to comment.