Merge pull request #438 from berndhahnebach/bhbdev063

FEM
This commit is contained in:
wwmayer
2017-01-14 16:06:00 +01:00
committed by GitHub
10 changed files with 114 additions and 42 deletions

View File

@@ -307,6 +307,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
self.shell_thicknesses.append(shell_thickness_dict)
def check_prerequisites(self):
import Units
message = ""
# analysis
if not self.analysis:
@@ -352,20 +353,27 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
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:

View File

@@ -52,6 +52,10 @@ frequency_analysis_inp_file = test_file_dir + '/' + frequency_base_name + '.inp'
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'
@@ -76,7 +80,7 @@ class FemTest(unittest.TestCase):
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):
@@ -134,6 +138,9 @@ class FemTest(unittest.TestCase):
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:
@@ -146,12 +153,12 @@ class FemTest(unittest.TestCase):
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)
@@ -181,6 +188,7 @@ class FemTest(unittest.TestCase):
return False
def test_new_analysis(self):
# static
fcc_print('--------------- Start of FEM tests ---------------')
fcc_print('Checking FEM new analysis...')
self.create_new_analysis()
@@ -263,6 +271,11 @@ class FemTest(unittest.TestCase):
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")
@@ -307,7 +320,11 @@ class FemTest(unittest.TestCase):
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")
@@ -336,6 +353,7 @@ class TherMechFemTest(unittest.TestCase):
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'
@@ -392,6 +410,9 @@ class TherMechFemTest(unittest.TestCase):
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:
@@ -518,26 +539,46 @@ class TherMechFemTest(unittest.TestCase):
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_cube_test_results():
def create_test_results():
# run FEM unit tests
run_fem_unittests()
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
@@ -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)
@@ -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)
@@ -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

View File

@@ -231,15 +231,15 @@ class _TaskPanelShowResult:
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

View File

@@ -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])

Binary file not shown.

View File

@@ -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
**
**
**

Binary file not shown.

View File

@@ -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
**
**
**

View File

@@ -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)