Skip to content

Commit

Permalink
FEM: FemTest rework
Browse files Browse the repository at this point in the history
- move test files to a separate directory
- use real life model to generate .inp files (model included)
- change format of csv node/volume files to allow direct copy&paste from .inp files
- use pre prepared real-life .dat & .frd files to test analysis results loading functions
- much more fine grained error reporting
- remove empty lines for output
- add helper function to print to console

Example run of the FEM test:

--------------- Start of FEM tests ---------------
Checking FEM new analysis...
Checking FEM new mesh...
sh: SMDS_MemoryLimit: command not found
Checking FEM new material...
Checking FEM new fixed constraint...
Checking FEM new force constraint...
Checking FEM new pressure constraint...
Checking FEM inp file prerequisites...
Checking FEM inp file write...
Setting up working directory /tmp/FEM_static
Writing /tmp/FEM_static/Mesh.inp for static analysis
Comparing /home/przemo/software/FreeCAD/build/Mod/Fem/test_files/cube_static.inp to /tmp/FEM_static/Mesh.inp
Setting up working directory to /home/przemo/software/FreeCAD/build/Mod/Fem/test_files in order to read simulated calculations
Setting base name to read test cube_static.frd file...
Checking FEM frd file read from static analysis...
Result object created as "Results"
Reading stats from result object for static analysis...
Setting analysis type to 'frequency"
Setting up working directory /tmp/FEM_frequency
Writing /tmp/FEM_frequency/Mesh.inp for frequency analysis
Comparing /home/przemo/software/FreeCAD/build/Mod/Fem/test_files/cube_frequency.inp to /tmp/FEM_frequency/Mesh.inp
Setting working directory to read simulated calculations...
Setting base name to read test cube_frequency.frd file...
Checking FEM frd file read from frequency analysis...
Last result object created as "Mode_10_results"
Reading stats from result object for frequency analysis...
--------------- End of FEM tests ---------------

Signed-off-by: Przemo Firszt <przemo@firszt.eu>
  • Loading branch information
PrzemoF authored and yorikvanhavre committed Sep 21, 2015
1 parent 14b15ac commit b25d2cd
Show file tree
Hide file tree
Showing 19 changed files with 21,423 additions and 425 deletions.
20 changes: 16 additions & 4 deletions src/Mod/Fem/App/CMakeLists.txt
Expand Up @@ -73,10 +73,6 @@ SET(FemScripts_SRCS
ccxInpWriter.py
TestFem.py
FemTools.py
mesh_points.csv
mesh_volumes.csv
static_analysis.inp
frequency_analysis.inp
MechanicalAnalysis.ui
MechanicalAnalysis.py
MechanicalMaterial.ui
Expand All @@ -85,6 +81,21 @@ SET(FemScripts_SRCS
)
#SOURCE_GROUP("Scripts" FILES ${FemScripts_SRCS})

SET(FemTests_SRCS
test_files/mesh_points.csv
test_files/mesh_volumes.csv
test_files/static_analysis.inp
test_files/frequency_analysis.inp
test_files/cube_frequency.inp
test_files/cube_frequency.dat
test_files/cube_frequency.frd
test_files/cube_frequency_expected_values
test_files/cube_static.inp
test_files/cube_static.dat
test_files/cube_static.frd
test_files/cube_static_expected_values
)

SET(FemBase_SRCS
FemMeshObject.cpp
FemMeshObject.h
Expand Down Expand Up @@ -158,6 +169,7 @@ fc_target_copy_resource(Fem
${CMAKE_BINARY_DIR}/Mod/Fem
Init.py
${FemScripts_SRCS}
${FemTests_SRCS}
)

SET_BIN_DIR(Fem Fem /Mod/Fem)
Expand Down
21 changes: 17 additions & 4 deletions src/Mod/Fem/CMakeLists.txt
Expand Up @@ -14,10 +14,6 @@ INSTALL(
ccxInpWriter.py
FemTools.py
TestFem.py
mesh_points.csv
mesh_volumes.csv
static_analysis.inp
frequency_analysis.inp
FemExample.py
MechanicalAnalysis.py
MechanicalMaterial.py
Expand All @@ -28,3 +24,20 @@ INSTALL(
Mod/Fem
)

INSTALL(
FILES
test_files/mesh_points.csv
test_files/mesh_volumes.csv
test_files/static_analysis.inp
test_files/frequency_analysis.inp
test_files/cube_frequency.inp
test_files/cube_frequency.dat
test_files/cube_frequency.frd
test_files/cube_frequency_expected_values
test_files/cube_static.inp
test_files/cube_static.dat
test_files/cube_static.frd
test_files/cube_static_expected_values
DESTINATION
Mod/Fem/test_files
)
4 changes: 2 additions & 2 deletions src/Mod/Fem/FemTools.py
Expand Up @@ -243,8 +243,8 @@ def load_results(self):
import ccxFrdReader
import os
self.results_present = False
result_file = self.base_name + ".frd"
if os.path.isfile(self.base_name + ".frd"):
result_file = self.working_dir + '/' + self.base_name + ".frd"
if os.path.isfile(result_file):
ccxFrdReader.importFrd(result_file, self.analysis)
for m in self.analysis.Member:
if m.isDerivedFrom("Fem::FemResultObject"):
Expand Down
148 changes: 118 additions & 30 deletions src/Mod/Fem/TestFem.py
Expand Up @@ -33,12 +33,25 @@
import unittest

mesh_name = 'Mesh'
static_analysis_dir = tempfile.gettempdir() + '/FEM_static/'
frequency_analysis_dir = tempfile.gettempdir() + '/FEM_frequency/'
static_analysis_inp_file = FreeCAD.getHomePath() + 'Mod/Fem/static_analysis.inp'
frequency_analysis_inp_file = FreeCAD.getHomePath() + 'Mod/Fem/frequency_analysis.inp'
mesh_points_file = FreeCAD.getHomePath() + 'Mod/Fem/mesh_points.csv'
mesh_volumes_file = FreeCAD.getHomePath() + 'Mod/Fem/mesh_volumes.csv'

home_path = FreeCAD.getHomePath()
temp_dir = tempfile.gettempdir()
test_file_dir = home_path + 'Mod/Fem/test_files'

static_base_name = 'cube_static'
frequency_base_name = 'cube_frequency'
static_analysis_dir = temp_dir + '/FEM_static'
frequency_analysis_dir = temp_dir + '/FEM_frequency'
static_analysis_inp_file = test_file_dir + '/' + static_base_name + '.inp'
static_expected_values = test_file_dir + "/cube_static_expected_values"
frequency_analysis_inp_file = test_file_dir + '/' + frequency_base_name + '.inp'
frequency_expected_values = test_file_dir + "/cube_frequency_expected_values"
mesh_points_file = test_file_dir + '/mesh_points.csv'
mesh_volumes_file = test_file_dir + '/mesh_volumes.csv'


def fcc_print(message):
FreeCAD.Console.PrintMessage(message + '\n')


class FemTest(unittest.TestCase):
Expand All @@ -64,24 +77,24 @@ def create_new_mesh(self):
with open(mesh_points_file, 'r') as points_file:
reader = csv.reader(points_file)
for p in reader:
self.mesh.addNode(float(p[0]), float(p[1]), float(p[2]), int(p[3]))
self.mesh.addNode(float(p[1]), float(p[2]), float(p[3]), int(p[0]))

with open(mesh_volumes_file, 'r') as volumes_file:
reader = csv.reader(volumes_file)
for _v in reader:
v = [int(x) for x in _v]
self.mesh.addVolume([v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]])

for v in reader:
self.mesh.addVolume([int(v[2]), int(v[1]), int(v[3]), int(v[4]), int(v[5]),
int(v[7]), int(v[6]), int(v[9]), int(v[8]), int(v[10])],
int(v[0]))
self.mesh_object.FemMesh = self.mesh
self.active_doc.recompute()

def create_new_material(self):
self.new_material_object = self.active_doc.addObject("App::MaterialObjectPython", 'MechanicalMaterial')
mat = self.new_material_object.Material
mat['Name'] = "TestMaterial"
mat['YoungsModulus'] = "20000 MPa"
mat['PoissonRatio'] = "0.36"
mat['Density'] = "1000 kg/m^3"
mat['Name'] = "Steel"
mat['YoungsModulus'] = "200000 MPa"
mat['PoissonRatio'] = "0.30"
mat['Density'] = "7900 kg/m^3"
self.new_material_object.Material = mat

def create_fixed_constraint(self):
Expand All @@ -90,14 +103,14 @@ def create_fixed_constraint(self):

def create_force_constraint(self):
self.force_constraint = self.active_doc.addObject("Fem::ConstraintForce", "FemConstraintForce")
self.force_constraint.References = [(self.box, "Face3")]
self.force_constraint.References = [(self.box, "Face2")]
self.force_constraint.Force = 10.000000
self.force_constraint.Direction = (self.box, ["Edge12"])
self.force_constraint.Direction = (self.box, ["Edge5"])
self.force_constraint.Reversed = True

def create_pressure_constraint(self):
self.pressure_constraint = self.active_doc.addObject("Fem::ConstraintPressure", "FemConstraintPressure")
self.pressure_constraint.References = [(self.box, "Face4")]
self.pressure_constraint.References = [(self.box, "Face2")]
self.pressure_constraint.Pressure = 10.000000
self.pressure_constraint.Reversed = True

Expand All @@ -117,57 +130,132 @@ def compare_inp_files(self, file_name1, file_name2):
file2.close()
return result

def compare_stats(self, fea, stat_file=None):
if stat_file:
sf = open(stat_file, 'r')
sf_content = sf.readlines()
sf.close()
stat_types = ["U1", "U2", "U3", "Uabs", "Sabs"]
stats = []
for s in stat_types:
stats.append("{}: {}\n".format(s, fea.get_stats(s)))
if sf_content != stats:
fcc_print("Expected stats from {}".format(stat_file))
fcc_print(sf_content)
fcc_print("Stats read from {}.frd file".format(fea.base_name))
fcc_print(stats)
return True
return False

def test_new_analysis(self):
FreeCAD.Console.PrintMessage('\nChecking FEM new analysis...\n')
fcc_print('--------------- Start of FEM tests ---------------')
fcc_print('Checking FEM new analysis...')
self.create_new_analysis()
self.assertTrue(self.analysis, "FemTest of new analysis failed")

FreeCAD.Console.PrintMessage('\nChecking FEM new mesh...\n')
fcc_print('Checking FEM new mesh...')
self.create_new_mesh()
self.assertTrue(self.mesh, "FemTest of new mesh failed")
self.analysis.Member = self.analysis.Member + [self.mesh_object]

FreeCAD.Console.PrintMessage('\nChecking FEM new material...\n')
fcc_print('Checking FEM new material...')
self.create_new_material()
self.assertTrue(self.new_material_object, "FemTest of new material failed")
self.analysis.Member = self.analysis.Member + [self.new_material_object]

FreeCAD.Console.PrintMessage('\nChecking FEM new fixed constraint...\n')
fcc_print('Checking FEM new fixed constraint...')
self.create_fixed_constraint()
self.assertTrue(self.fixed_constraint, "FemTest of new fixed constraint failed")
self.analysis.Member = self.analysis.Member + [self.fixed_constraint]

FreeCAD.Console.PrintMessage('\nChecking FEM new force constraint...\n')
fcc_print('Checking FEM new force constraint...')
self.create_force_constraint()
self.assertTrue(self.force_constraint, "FemTest of new force constraint failed")
self.analysis.Member = self.analysis.Member + [self.force_constraint]

FreeCAD.Console.PrintMessage('\nChecking FEM new pressure constraint...\n')
fcc_print('Checking FEM new pressure constraint...')
self.create_pressure_constraint()
self.assertTrue(self.pressure_constraint, "FemTest of new pressure constraint failed")
self.analysis.Member = self.analysis.Member + [self.pressure_constraint]

fea = FemTools.FemTools(self.analysis)
FreeCAD.Console.PrintMessage('\nChecking FEM inp file prerequisites...\n')
fcc_print('Checking FEM inp file prerequisites...')
error = fea.check_prerequisites()
self.assertFalse(error, "FemTools check_prerequisites returned error message: {}".format(error))

FreeCAD.Console.PrintMessage('\nChecking FEM inp file write...\n')
fcc_print('Checking FEM inp file write...')

fcc_print('Setting up working directory {}'.format(static_analysis_dir))
fea.setup_working_dir(static_analysis_dir)
FreeCAD.Console.PrintMessage('\nWriting {}/{}.inp for static analysis\n'.format(static_analysis_dir, mesh_name))
self.assertTrue(True if fea.working_dir == static_analysis_dir else False,
"Setting working directory {} failed".format(static_analysis_dir))

fcc_print('Writing {}/{}.inp for static analysis'.format(static_analysis_dir, mesh_name))
error = fea.write_inp_file()
FreeCAD.Console.PrintMessage('\nComparing {} to {}/{}.inp\n'.format(static_analysis_inp_file, static_analysis_dir, mesh_name))
self.assertFalse(error, "Writing failed")

fcc_print('Comparing {} to {}/{}.inp'.format(static_analysis_inp_file, static_analysis_dir, mesh_name))
ret = self.compare_inp_files(static_analysis_inp_file, static_analysis_dir + "/" + mesh_name + '.inp')
self.assertFalse(ret, "FemTools write_inp_file test failed.\n{}".format(ret))

fcc_print('Setting up working directory to {} in order to read simulated calculations'.format(test_file_dir))
fea.setup_working_dir(test_file_dir)
self.assertTrue(True if fea.working_dir == test_file_dir else False,
"Setting working directory {} failed".format(test_file_dir))

fcc_print('Setting base name to read test {}.frd file...'.format('cube_static'))
fea.set_base_name(static_base_name)
self.assertTrue(True if fea.base_name == static_base_name else False,
"Setting base name to {} failed".format(static_base_name))

fcc_print('Checking FEM frd file read from static analysis...')
fea.load_results()
fcc_print('Result object created as \"{}\"'.format(fea.result_object.Name))
self.assertTrue(fea.results_present, "Cannot read results from {}.frd frd file".format(fea.base_name))

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

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

fcc_print('Setting up working directory to {} in order to write frequency calculations'.format(frequency_analysis_dir))
fea.setup_working_dir(frequency_analysis_dir)
FreeCAD.Console.PrintMessage('\nWriting {}/{}.inp for frequency analysis\n'.format(frequency_analysis_dir, mesh_name))
self.assertTrue(True if fea.working_dir == frequency_analysis_dir else False,
"Setting working directory {} failed".format(frequency_analysis_dir))

fcc_print('Writing {}/{}.inp for frequency analysis'.format(frequency_analysis_dir, mesh_name))
error = fea.write_inp_file()
FreeCAD.Console.PrintMessage('\nComparing {} to {}/{}.inp\n'.format(frequency_analysis_inp_file, frequency_analysis_dir, mesh_name))
self.assertFalse(error, "Writing failed")

fcc_print('Comparing {} to {}/{}.inp'.format(frequency_analysis_inp_file, frequency_analysis_dir, mesh_name))
ret = self.compare_inp_files(frequency_analysis_inp_file, frequency_analysis_dir + "/" + mesh_name + '.inp')
self.assertFalse(ret, "FemTools write_inp_file test failed.\n{}".format(ret))

fcc_print('Setting up working directory to {} in order to read simulated calculations'.format(test_file_dir))
fea.setup_working_dir(test_file_dir)
self.assertTrue(True if fea.working_dir == test_file_dir else False,
"Setting working directory {} failed".format(test_file_dir))

fcc_print('Setting base name to read test {}.frd file...'.format(frequency_base_name))
fea.set_base_name(frequency_base_name)
self.assertTrue(True if fea.base_name == frequency_base_name else False,
"Setting base name to {} failed".format(frequency_base_name))

fcc_print('Checking FEM frd file read from frequency analysis...')
fea.load_results()

fcc_print('Last result object created as \"{}\"'.format(fea.result_object.Name))
self.assertTrue(fea.results_present, "Cannot read results from {}.frd frd file".format(fea.base_name))

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

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

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

0 comments on commit b25d2cd

Please sign in to comment.