# *************************************************************************** # * Copyright (c) 2018 - FreeCAD Developers * # * Author: Bernd Hahnebach * # * * # * This file is part of the FreeCAD CAx development system. * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * FreeCAD is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with FreeCAD; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # ***************************************************************************/ __title__ = "Tools for FEM unit tests" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" import os import unittest import tempfile import FreeCAD from os.path import join def get_fem_test_home_dir( ): return join(FreeCAD.getHomePath(), 'Mod', 'Fem', 'femtest', 'testfiles') def get_fem_test_tmp_dir( ): temp_dir = join(tempfile.gettempdir(), 'FEM_unittests') if not os.path.exists(temp_dir): os.makedirs(temp_dir) return(temp_dir) def get_unit_test_tmp_dir( temp_dir, unittestdir ): testdir = join(temp_dir, unittestdir) if not os.path.exists(testdir): os.makedirs(testdir) return testdir def fcc_print( message ): FreeCAD.Console.PrintMessage('{} \n'.format(message)) def get_defmake_count( fem_vtk_post=True ): ''' count the def make in module ObjectsFem could also be done in bash with grep -c "def make" src/Mod/Fem/ObjectsFem.py ''' name_modfile = join(FreeCAD.getHomePath(), 'Mod', 'Fem', 'ObjectsFem.py') modfile = open(name_modfile, 'r') lines_modefile = modfile.readlines() modfile.close() lines_defmake = [l for l in lines_modefile if l.startswith('def make')] if not fem_vtk_post: # FEM VTK post processing is disabled # we are not able to create VTK post objects new_lines = [] for l in lines_defmake: if "PostVtk" not in l: new_lines.append(l) lines_defmake = new_lines return len(lines_defmake) def get_fem_test_defs( inout='out' ): test_path = join(FreeCAD.getHomePath(), 'Mod', 'Fem', 'femtest') collected_test_modules = [] collected_test_methods = [] for tfile in sorted(os.listdir(test_path)): if tfile.startswith("test") and tfile.endswith(".py"): collected_test_modules.append(join(test_path, tfile)) for f in collected_test_modules: tfile = open(f, 'r') module_name = os.path.splitext(os.path.basename(f))[0] class_name = '' for ln in tfile: ln = ln.lstrip() ln = ln.rstrip() if ln.startswith('class '): ln = ln.lstrip('class ') ln = ln.split('(')[0] class_name = ln if ln.startswith('def test'): ln = ln.lstrip('def ') ln = ln.split('(')[0] collected_test_methods.append( 'femtest.{}.{}.{}'.format(module_name, class_name, ln) ) tfile.close() print('') for m in collected_test_methods: run_outside_fc = './bin/FreeCADCmd --run-test "{}"'.format(m) run_inside_fc = ( 'unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("{}"))' .format(m) ) if inout == 'in': print('\nimport unittest') print(run_inside_fc) else: print(run_outside_fc) def compare_inp_files( file_name1, file_name2 ): file1 = open(file_name1, 'r') f1 = file1.readlines() file1.close() # l.startswith('17671.0,1') is a temporary workaround # for python3 problem with 1DFlow input # TODO as soon as the 1DFlow result reading is fixed # this should be triggered in the 1DFlow unit test lf1 = [l for l in f1 if not ( l.startswith('** written ') or l.startswith('** file ') or l.startswith('17671.0,1') )] lf1 = force_unix_line_ends(lf1) file2 = open(file_name2, 'r') f2 = file2.readlines() file2.close() # TODO see comment on file1 lf2 = [l for l in f2 if not ( l.startswith('** written ') or l.startswith('** file ') or l.startswith('17671.0,1') )] lf2 = force_unix_line_ends(lf2) import difflib diff = difflib.unified_diff(lf1, lf2, n=0) result = '' for l in diff: result += l if result: result = ( "Comparing {} to {} failed!\n" .format(file_name1, file_name2) + result ) return result def compare_files( file_name1, file_name2 ): file1 = open(file_name1, 'r') f1 = file1.readlines() file1.close() # workaround to compare geos of elmer test and temporary file path # (not only names change, path changes with operating system) lf1 = [l for l in f1 if not ( l.startswith('Merge "') or l.startswith('Save "') or l.startswith('// ') )] lf1 = 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('Merge "') or l.startswith('Save "') or l.startswith('// ') )] lf2 = force_unix_line_ends(lf2) import difflib diff = difflib.unified_diff(lf1, lf2, n=0) result = '' for l in diff: result += l if result: result = "Comparing {} to {} failed!\n".format(file_name1, file_name2) + result return result def compare_stats( fea, stat_file, res_obj_name, loc_stat_types=None ): import femresult.resulttools as resulttools # get the stat types which should be compared stat_types = [ "U1", "U2", "U3", "Uabs", "Sabs", "MaxPrin", "MidPrin", "MinPrin", "MaxShear", "Peeq", "Temp", "MFlow", "NPress" ] if not loc_stat_types: loc_stat_types = stat_types # get stats from result obj which should be compared obj = FreeCAD.ActiveDocument.getObject(res_obj_name) # fcc_print(obj) if obj: # fcc_print(obj.Name) stats = [] for s in loc_stat_types: statval = resulttools.get_stats(obj, s) stats.append( "{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n" .format(s, statval[0], statval[1], statval[2]) ) else: fcc_print("Result object not found. Name: {}".format(res_obj_name)) return False # get stats to compare with sf = open(stat_file, 'r') sf_content = [] for l in sf.readlines(): for st in loc_stat_types: if l.startswith(st): sf_content.append(l) sf.close() sf_content = force_unix_line_ends(sf_content) # compare stats 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 force_unix_line_ends( line_list ): new_line_list = [] for ln in line_list: if ln.endswith("\r\n"): ln = ln[:-2] + '\n' new_line_list.append(ln) return new_line_list def collect_python_modules( femsubdir=None ): if not femsubdir: pydir = join(FreeCAD.ConfigGet("AppHomePath"), 'Mod', 'Fem') else: pydir = join(FreeCAD.ConfigGet("AppHomePath"), 'Mod', 'Fem', femsubdir) collected_modules = [] fcc_print(pydir) for pyfile in sorted(os.listdir(pydir)): if pyfile.endswith(".py") and not pyfile.startswith('Init'): if not femsubdir: collected_modules.append( os.path.splitext(os.path.basename(pyfile))[0] ) else: collected_modules.append( femsubdir.replace('/', '.') + '.' + os.path.splitext( os.path.basename(pyfile) )[0] ) return collected_modules def all_test_files( ): # open all files cube_frequency() cube_static() Flow1D_thermomech() multimat() spine_thermomech() # run the specific test case of the file # open the file in FreeCAD GUI and return the doc identifier def cube_frequency( ): testname = "femtest.testccxtools.TestCcxTools.test_3_freq_analysis" unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName(testname)) doc = FreeCAD.open(join( get_fem_test_tmp_dir(), 'FEM_ccx_frequency', 'cube_frequency.FCStd') ) return doc def cube_static( ): testname = "femtest.testccxtools.TestCcxTools.test_1_static_analysis" unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName(testname)) doc = FreeCAD.open( join(get_fem_test_tmp_dir(), 'FEM_ccx_static', 'cube_static.FCStd') ) return doc def Flow1D_thermomech( ): testname = "femtest.testccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis" unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName(testname)) doc = FreeCAD.open(join( get_fem_test_tmp_dir(), 'FEM_ccx_Flow1D_thermomech', 'Flow1D_thermomech.FCStd') ) return doc def multimat( ): testname = "femtest.testccxtools.TestCcxTools.test_2_static_multiple_material" unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName(testname)) doc = FreeCAD.open(join( get_fem_test_tmp_dir(), 'FEM_ccx_multimat', 'multimat.FCStd') ) return doc def spine_thermomech( ): testname = "femtest.testccxtools.TestCcxTools.test_4_thermomech_analysis" unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName(testname)) doc = FreeCAD.open(join( get_fem_test_tmp_dir(), 'FEM_ccx_thermomech', 'spine_thermomech.FCStd') ) return doc