@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
BIN
src/Mod/Fem/test_files/ccx/cube_frequency.fcstd
Normal file
BIN
src/Mod/Fem/test_files/ccx/cube_frequency.fcstd
Normal file
Binary file not shown.
@@ -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
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
BIN
src/Mod/Fem/test_files/ccx/cube_static.fcstd
Normal file
BIN
src/Mod/Fem/test_files/ccx/cube_static.fcstd
Normal file
Binary file not shown.
@@ -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
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
Binary file not shown.
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user