diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index d48b970fbe..f7162009ae 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -115,7 +115,9 @@ SET(FemSolverFenics_SRCS SET(FemTests_SRCS femtest/__init__.py + femtest/testccxtools.py femtest/testfemcommon.py + femtest/testsolverframework.py femtest/testtools.py ) diff --git a/src/Mod/Fem/TestFem.py b/src/Mod/Fem/TestFem.py index c675fe1a37..0deb478aa4 100644 --- a/src/Mod/Fem/TestFem.py +++ b/src/Mod/Fem/TestFem.py @@ -25,6 +25,8 @@ # ***************************************************************************/ +# the order should be as follows: +# common-, object-, mesh-, inout-, ccxtools-, solverframworktests from femtest.testfemcommon import FemTest -from femtest.testfemcommon import FemCcxAnalysisTest -from femtest.testfemcommon import SolverFrameWorkTest +from femtest.testccxtools import FemCcxAnalysisTest +from femtest.testsolverframework import SolverFrameWorkTest diff --git a/src/Mod/Fem/femtest/testccxtools.py b/src/Mod/Fem/femtest/testccxtools.py new file mode 100644 index 0000000000..46edd48c6f --- /dev/null +++ b/src/Mod/Fem/femtest/testccxtools.py @@ -0,0 +1,753 @@ +# Unit test for the FEM module + +# *************************************************************************** +# * Copyright (c) 2015 - FreeCAD Developers * +# * Author: Przemo Firszt * +# * * +# * 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 * +# * * +# ***************************************************************************/ + +import Fem +from femtools import ccxtools +import femresult.resulttools as resulttools +import FreeCAD +import ObjectsFem +import femsolver.run +import tempfile +import unittest +import os +from .testtools import fcc_print +from .testtools import get_defmake_count +from .testtools import compare_inp_files +from .testtools import compare_files +from .testtools import compare_stats +from .testtools import force_unix_line_ends +from .testtools import collect_python_modules + + +mesh_name = 'Mesh' +stat_types = ["U1", "U2", "U3", "Uabs", "Sabs", "MaxPrin", "MidPrin", "MinPrin", "MaxShear", "Peeq", "Temp", "MFlow", "NPress"] + +home_path = FreeCAD.getHomePath() +temp_dir = tempfile.gettempdir() + '/FEM_unittests/' +if not os.path.exists(temp_dir): + os.makedirs(temp_dir) +test_file_dir = home_path + 'Mod/Fem/femtest/testfiles/ccx/' +test_file_dir_elmer = home_path + 'Mod/Fem/femtest/testfiles/elmer/' + +# define some locations fot the analysis tests +# since they are also used in the helper def which create results they should stay global for the module +static_base_name = 'cube_static' +static_analysis_dir = temp_dir + 'FEM_ccx_static/' +static_save_fc_file = static_analysis_dir + static_base_name + '.fcstd' +static_analysis_inp_file = test_file_dir + static_base_name + '.inp' +static_expected_values = test_file_dir + "cube_static_expected_values" + +frequency_base_name = 'cube_frequency' +frequency_analysis_dir = temp_dir + 'FEM_ccx_frequency/' +frequency_save_fc_file = frequency_analysis_dir + frequency_base_name + '.fcstd' +frequency_analysis_inp_file = test_file_dir + frequency_base_name + '.inp' +frequency_expected_values = test_file_dir + "cube_frequency_expected_values" + +thermomech_base_name = 'spine_thermomech' +thermomech_analysis_dir = temp_dir + 'FEM_ccx_thermomech/' +thermomech_save_fc_file = thermomech_analysis_dir + thermomech_base_name + '.fcstd' +thermomech_analysis_inp_file = test_file_dir + thermomech_base_name + '.inp' +thermomech_expected_values = test_file_dir + "spine_thermomech_expected_values" + +Flow1D_thermomech_base_name = 'Flow1D_thermomech' +Flow1D_thermomech_analysis_dir = temp_dir + 'FEM_ccx_Flow1D_thermomech/' +Flow1D_thermomech_save_fc_file = Flow1D_thermomech_analysis_dir + Flow1D_thermomech_base_name + '.fcstd' +Flow1D_thermomech_analysis_inp_file = test_file_dir + Flow1D_thermomech_base_name + '.inp' +Flow1D_thermomech_expected_values = test_file_dir + "Flow1D_thermomech_expected_values" + +solverframework_analysis_dir = temp_dir + 'FEM_solverframework/' +solverframework_save_fc_file = solverframework_analysis_dir + static_base_name + '.fcstd' + + +class FemCcxAnalysisTest(unittest.TestCase): + + def setUp(self): + try: + FreeCAD.setActiveDocument("FemTest") + except: + FreeCAD.newDocument("FemTest") + finally: + FreeCAD.setActiveDocument("FemTest") + self.active_doc = FreeCAD.ActiveDocument + + def test_static_freq_analysis(self): + # static + fcc_print('--------------- Start of FEM tests ---------------') + box = self.active_doc.addObject("Part::Box", "Box") + fcc_print('Checking FEM new analysis...') + analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') + self.assertTrue(analysis, "FemTest of new analysis failed") + + fcc_print('Checking FEM new solver...') + solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') + solver_object.AnalysisType = 'static' + solver_object.GeometricalNonlinearity = 'linear' + solver_object.ThermoMechSteadyState = False + solver_object.MatrixSolverType = 'default' + solver_object.IterationsControlParameterTimeUse = False + solver_object.EigenmodesCount = 10 + solver_object.EigenmodeHighLimit = 1000000.0 + solver_object.EigenmodeLowLimit = 0.0 + self.assertTrue(solver_object, "FemTest of new solver failed") + analysis.addObject(solver_object) + + fcc_print('Checking FEM new material...') + material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') + mat = material_object.Material + mat['Name'] = "Steel-Generic" + mat['YoungsModulus'] = "200000 MPa" + mat['PoissonRatio'] = "0.30" + mat['Density'] = "7900 kg/m^3" + material_object.Material = mat + self.assertTrue(material_object, "FemTest of new material failed") + analysis.addObject(material_object) + + fcc_print('Checking FEM new fixed constraint...') + fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") + fixed_constraint.References = [(box, "Face1")] + self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") + analysis.addObject(fixed_constraint) + + fcc_print('Checking FEM new force constraint...') + force_constraint = self.active_doc.addObject("Fem::ConstraintForce", "FemConstraintForce") + force_constraint.References = [(box, "Face6")] + force_constraint.Force = 40000.0 + force_constraint.Direction = (box, ["Edge5"]) + self.active_doc.recompute() + force_constraint.Reversed = True + self.active_doc.recompute() + self.assertTrue(force_constraint, "FemTest of new force constraint failed") + analysis.addObject(force_constraint) + + fcc_print('Checking FEM new pressure constraint...') + pressure_constraint = self.active_doc.addObject("Fem::ConstraintPressure", "FemConstraintPressure") + pressure_constraint.References = [(box, "Face2")] + pressure_constraint.Pressure = 1000.0 + pressure_constraint.Reversed = False + self.assertTrue(pressure_constraint, "FemTest of new pressure constraint failed") + analysis.addObject(pressure_constraint) + + fcc_print('Checking FEM new mesh...') + from .testfiles.ccx.cube_mesh import create_nodes_cube + from .testfiles.ccx.cube_mesh import create_elements_cube + mesh = Fem.FemMesh() + ret = create_nodes_cube(mesh) + self.assertTrue(ret, "Import of mesh nodes failed") + ret = create_elements_cube(mesh) + self.assertTrue(ret, "Import of mesh volumes failed") + mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) + mesh_object.FemMesh = mesh + self.assertTrue(mesh, "FemTest of new mesh failed") + analysis.addObject(mesh_object) + + self.active_doc.recompute() + + fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True) + fcc_print('Setting up working directory {}'.format(static_analysis_dir)) + fea.setup_working_dir(static_analysis_dir) + self.assertTrue(True if fea.working_dir == static_analysis_dir else False, + "Setting working directory {} failed".format(static_analysis_dir)) + + fcc_print('Checking FEM inp file prerequisites for static analysis...') + error = fea.check_prerequisites() + self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) + + fcc_print('Checking FEM inp file write...') + + fcc_print('Writing {}/{}.inp for static analysis'.format(static_analysis_dir, mesh_name)) + error = fea.write_inp_file() + self.assertFalse(error, "Writing failed") + + fcc_print('Comparing {} to {}/{}.inp'.format(static_analysis_inp_file, static_analysis_dir, mesh_name)) + ret = compare_inp_files(static_analysis_inp_file, static_analysis_dir + mesh_name + '.inp') + self.assertFalse(ret, "ccxtools 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('Setting inp file name to read test {}.frd file...'.format('cube_static')) + fea.set_inp_file_name() + self.assertTrue(True if fea.inp_file_name == static_analysis_inp_file else False, + "Setting inp file name to {} failed".format(static_analysis_inp_file)) + + fcc_print('Checking FEM frd file read from static 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 static analysis...') + ret = compare_stats(fea, static_expected_values, 'CalculiX_static_results') + self.assertFalse(ret, "Invalid results read from .frd file") + + fcc_print('Save FreeCAD file for static analysis to {}...'.format(static_save_fc_file)) + self.active_doc.saveAs(static_save_fc_file) + + # frequency + fcc_print('Reset Statik analysis') + fea.reset_all() + fcc_print('Setting analysis type to \'frequency\"') + solver_object.AnalysisType = 'frequency' + + fcc_print('Setting up working directory to {} in order to write frequency calculations'.format(frequency_analysis_dir)) + fea.setup_working_dir(frequency_analysis_dir) + self.assertTrue(True if fea.working_dir == frequency_analysis_dir else False, + "Setting working directory {} failed".format(frequency_analysis_dir)) + + fcc_print('Checking FEM inp file prerequisites for frequency analysis...') + error = fea.check_prerequisites() + self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) + + fcc_print('Writing {}/{}.inp for frequency analysis'.format(frequency_analysis_dir, mesh_name)) + error = fea.write_inp_file() + self.assertFalse(error, "Writing failed") + + fcc_print('Comparing {} to {}/{}.inp'.format(frequency_analysis_inp_file, frequency_analysis_dir, mesh_name)) + ret = compare_inp_files(frequency_analysis_inp_file, frequency_analysis_dir + mesh_name + '.inp') + self.assertFalse(ret, "ccxtools 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('Setting inp file name to read test {}.frd file...'.format('cube_frequency')) + fea.set_inp_file_name() + self.assertTrue(True if fea.inp_file_name == frequency_analysis_inp_file else False, + "Setting inp file name to {} failed".format(frequency_analysis_inp_file)) + + fcc_print('Checking FEM frd file read from frequency 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 frequency analysis...') + ret = compare_stats(fea, frequency_expected_values, 'CalculiX_frequency_mode_1_results') + self.assertFalse(ret, "Invalid results read from .frd file") + + fcc_print('Save FreeCAD file for frequency analysis to {}...'.format(frequency_save_fc_file)) + self.active_doc.saveAs(frequency_save_fc_file) + fcc_print('--------------- End of FEM tests static and frequency analysis ---------------') + + def test_thermomech_analysis(self): + fcc_print('--------------- Start of FEM tests ---------------') + box = self.active_doc.addObject("Part::Box", "Box") + box.Height = 25.4 + box.Width = 25.4 + box.Length = 203.2 + fcc_print('Checking FEM new analysis...') + analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') + self.assertTrue(analysis, "FemTest of new analysis failed") + + fcc_print('Checking FEM new solver...') + solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') + solver_object.AnalysisType = 'thermomech' + solver_object.GeometricalNonlinearity = 'linear' + solver_object.ThermoMechSteadyState = True + solver_object.MatrixSolverType = 'default' + solver_object.IterationsThermoMechMaximum = 2000 + solver_object.IterationsControlParameterTimeUse = True + self.assertTrue(solver_object, "FemTest of new solver failed") + analysis.addObject(solver_object) + + fcc_print('Checking FEM new material...') + material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') + mat = material_object.Material + mat['Name'] = "Steel-Generic" + mat['YoungsModulus'] = "200000 MPa" + mat['PoissonRatio'] = "0.30" + mat['Density'] = "7900 kg/m^3" + mat['ThermalConductivity'] = "43.27 W/m/K" # SvdW: Change to Ansys model values + mat['ThermalExpansionCoefficient'] = "12 um/m/K" + mat['SpecificHeat'] = "500 J/kg/K" # SvdW: Change to Ansys model values + material_object.Material = mat + self.assertTrue(material_object, "FemTest of new material failed") + analysis.addObject(material_object) + + fcc_print('Checking FEM new fixed constraint...') + fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") + fixed_constraint.References = [(box, "Face1")] + self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") + analysis.addObject(fixed_constraint) + + fcc_print('Checking FEM new initial temperature constraint...') + initialtemperature_constraint = self.active_doc.addObject("Fem::ConstraintInitialTemperature", "FemConstraintInitialTemperature") + initialtemperature_constraint.initialTemperature = 300.0 + self.assertTrue(initialtemperature_constraint, "FemTest of new initial temperature constraint failed") + analysis.addObject(initialtemperature_constraint) + + fcc_print('Checking FEM new temperature constraint...') + temperature_constraint = self.active_doc.addObject("Fem::ConstraintTemperature", "FemConstraintTemperature") + temperature_constraint.References = [(box, "Face1")] + temperature_constraint.Temperature = 310.93 + self.assertTrue(temperature_constraint, "FemTest of new temperature constraint failed") + analysis.addObject(temperature_constraint) + + fcc_print('Checking FEM new heatflux constraint...') + heatflux_constraint = self.active_doc.addObject("Fem::ConstraintHeatflux", "FemConstraintHeatflux") + heatflux_constraint.References = [(box, "Face3"), (box, "Face4"), (box, "Face5"), (box, "Face6")] + heatflux_constraint.AmbientTemp = 255.3722 + heatflux_constraint.FilmCoef = 5.678 + self.assertTrue(heatflux_constraint, "FemTest of new heatflux constraint failed") + analysis.addObject(heatflux_constraint) + + fcc_print('Checking FEM new mesh...') + from .testfiles.ccx.spine_mesh import create_nodes_spine + from .testfiles.ccx.spine_mesh import create_elements_spine + mesh = Fem.FemMesh() + ret = create_nodes_spine(mesh) + self.assertTrue(ret, "Import of mesh nodes failed") + ret = create_elements_spine(mesh) + self.assertTrue(ret, "Import of mesh volumes failed") + mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) + mesh_object.FemMesh = mesh + self.assertTrue(mesh, "FemTest of new mesh failed") + analysis.addObject(mesh_object) + + self.active_doc.recompute() + + fea = ccxtools.FemToolsCcx(analysis, test_mode=True) + fcc_print('Setting up working directory {}'.format(thermomech_analysis_dir)) + fea.setup_working_dir(thermomech_analysis_dir) + self.assertTrue(True if fea.working_dir == thermomech_analysis_dir else False, + "Setting working directory {} failed".format(thermomech_analysis_dir)) + + fcc_print('Checking FEM inp file prerequisites for thermo-mechanical analysis...') + error = fea.check_prerequisites() + self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) + + fcc_print('Checking FEM inp file write...') + + fcc_print('Writing {}/{}.inp for thermomech analysis'.format(thermomech_analysis_dir, mesh_name)) + error = fea.write_inp_file() + self.assertFalse(error, "Writing failed") + + fcc_print('Comparing {} to {}/{}.inp'.format(thermomech_analysis_inp_file, thermomech_analysis_dir, mesh_name)) + ret = compare_inp_files(thermomech_analysis_inp_file, thermomech_analysis_dir + mesh_name + '.inp') + self.assertFalse(ret, "ccxtools 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('spine_thermomech')) + fea.set_base_name(thermomech_base_name) + self.assertTrue(True if fea.base_name == thermomech_base_name else False, + "Setting base name to {} failed".format(thermomech_base_name)) + + fcc_print('Setting inp file name to read test {}.frd file...'.format('spine_thermomech')) + fea.set_inp_file_name() + 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 = compare_stats(fea, thermomech_expected_values, 'CalculiX_thermomech_results') + self.assertFalse(ret, "Invalid results read from .frd file") + + fcc_print('Save FreeCAD file for thermomech analysis to {}...'.format(thermomech_save_fc_file)) + self.active_doc.saveAs(thermomech_save_fc_file) + + fcc_print('--------------- End of FEM tests thermomech analysis ---------------') + + def test_Flow1D_thermomech_analysis(self): + fcc_print('--------------- Start of 1D Flow FEM tests ---------------') + import Draft + p1 = FreeCAD.Vector(0, 0, 50) + p2 = FreeCAD.Vector(0, 0, -50) + p3 = FreeCAD.Vector(0, 0, -4300) + p4 = FreeCAD.Vector(4950, 0, -4300) + p5 = FreeCAD.Vector(5000, 0, -4300) + p6 = FreeCAD.Vector(8535.53, 0, -7835.53) + p7 = FreeCAD.Vector(8569.88, 0, -7870.88) + p8 = FreeCAD.Vector(12105.41, 0, -11406.41) + p9 = FreeCAD.Vector(12140.76, 0, -11441.76) + p10 = FreeCAD.Vector(13908.53, 0, -13209.53) + p11 = FreeCAD.Vector(13943.88, 0, -13244.88) + p12 = FreeCAD.Vector(15046.97, 0, -14347.97) + p13 = FreeCAD.Vector(15046.97, 0, -7947.97) + p14 = FreeCAD.Vector(15046.97, 0, -7847.97) + p15 = FreeCAD.Vector(0, 0, 0) + p16 = FreeCAD.Vector(0, 0, -2175) + p17 = FreeCAD.Vector(2475, 0, -4300) + p18 = FreeCAD.Vector(4975, 0, -4300) + p19 = FreeCAD.Vector(6767.765, 0, -6067.765) + p20 = FreeCAD.Vector(8552.705, 0, -7853.205) + p21 = FreeCAD.Vector(10337.645, 0, -9638.645) + p22 = FreeCAD.Vector(12123.085, 0, -11424.085) + p23 = FreeCAD.Vector(13024.645, 0, -12325.645) + p24 = FreeCAD.Vector(13926.205, 0, -13227.205) + p25 = FreeCAD.Vector(14495.425, 0, -13796.425) + p26 = FreeCAD.Vector(15046.97, 0, -11147.97) + p27 = FreeCAD.Vector(15046.97, 0, -7897.97) + points = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27] + line = Draft.makeWire(points, closed=False, face=False, support=None) + fcc_print('Checking FEM new analysis...') + analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') + self.assertTrue(analysis, "FemTest of new analysis failed") + + fcc_print('Checking FEM new solver...') + solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') + solver_object.AnalysisType = 'thermomech' + solver_object.GeometricalNonlinearity = 'linear' + solver_object.ThermoMechSteadyState = True + solver_object.MatrixSolverType = 'default' + solver_object.IterationsThermoMechMaximum = 2000 + solver_object.IterationsControlParameterTimeUse = False + self.assertTrue(solver_object, "FemTest of new solver failed") + analysis.addObject(solver_object) + + fcc_print('Checking FEM new material...') + material_object = ObjectsFem.makeMaterialFluid(self.active_doc, 'FluidMaterial') + mat = material_object.Material + mat['Name'] = "Water" + mat['Density'] = "998 kg/m^3" + mat['SpecificHeat'] = "4.182 J/kg/K" + mat['DynamicViscosity'] = "1.003e-3 kg/m/s" + mat['VolumetricThermalExpansionCoefficient'] = "2.07e-4 m/m/K" + mat['ThermalConductivity'] = "0.591 W/m/K" + material_object.Material = mat + self.assertTrue(material_object, "FemTest of new material failed") + analysis.addObject(material_object) + + fcc_print('Checking FEM Flow1D inlet constraint...') + Flow1d_inlet = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_inlet.SectionType = 'Liquid' + Flow1d_inlet.LiquidSectionType = 'PIPE INLET' + Flow1d_inlet.InletPressure = 0.1 + Flow1d_inlet.References = [(line, "Edge1")] + self.assertTrue(Flow1d_inlet, "FemTest of new Flow1D inlet constraint failed") + analysis.addObject(Flow1d_inlet) + + fcc_print('Checking FEM new Flow1D entrance constraint...') + Flow1d_entrance = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_entrance.SectionType = 'Liquid' + Flow1d_entrance.LiquidSectionType = 'PIPE ENTRANCE' + Flow1d_entrance.EntrancePipeArea = 31416.00 + Flow1d_entrance.EntranceArea = 25133.00 + Flow1d_entrance.References = [(line, "Edge2")] + self.assertTrue(Flow1d_entrance, "FemTest of new Flow1D entrance constraint failed") + analysis.addObject(Flow1d_entrance) + + fcc_print('Checking FEM new Flow1D manning constraint...') + Flow1d_manning = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_manning.SectionType = 'Liquid' + Flow1d_manning.LiquidSectionType = 'PIPE MANNING' + Flow1d_manning.ManningArea = 31416 + Flow1d_manning.ManningRadius = 50 + Flow1d_manning.ManningCoefficient = 0.002 + Flow1d_manning.References = [(line, "Edge3"), (line, "Edge5")] + self.assertTrue(Flow1d_manning, "FemTest of new Flow1D manning constraint failed") + analysis.addObject(Flow1d_manning) + + fcc_print('Checking FEM new Flow1D bend constraint...') + Flow1d_bend = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_bend.SectionType = 'Liquid' + Flow1d_bend.LiquidSectionType = 'PIPE BEND' + Flow1d_bend.BendPipeArea = 31416 + Flow1d_bend.BendRadiusDiameter = 1.5 + Flow1d_bend.BendAngle = 45 + Flow1d_bend.BendLossCoefficient = 0.4 + Flow1d_bend.References = [(line, "Edge4")] + self.assertTrue(Flow1d_bend, "FemTest of new Flow1D bend constraint failed") + analysis.addObject(Flow1d_bend) + + fcc_print('Checking FEM new Flow1D enlargement constraint...') + Flow1d_enlargement = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_enlargement.SectionType = 'Liquid' + Flow1d_enlargement.LiquidSectionType = 'PIPE ENLARGEMENT' + Flow1d_enlargement.EnlargeArea1 = 31416.00 + Flow1d_enlargement.EnlargeArea2 = 70686.00 + Flow1d_enlargement.References = [(line, "Edge6")] + self.assertTrue(Flow1d_enlargement, "FemTest of new Flow1D enlargement constraint failed") + analysis.addObject(Flow1d_enlargement) + + fcc_print('Checking FEM new Flow1D manning constraint...') + Flow1d_manning1 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_manning1.SectionType = 'Liquid' + Flow1d_manning1.LiquidSectionType = 'PIPE MANNING' + Flow1d_manning1.ManningArea = 70686.00 + Flow1d_manning1.ManningRadius = 75 + Flow1d_manning1.ManningCoefficient = 0.002 + Flow1d_manning1.References = [(line, "Edge7")] + self.assertTrue(Flow1d_manning1, "FemTest of new Flow1D manning constraint failed") + analysis.addObject(Flow1d_manning1) + + fcc_print('Checking FEM new Flow1D contraction constraint...') + Flow1d_contraction = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_contraction.SectionType = 'Liquid' + Flow1d_contraction.LiquidSectionType = 'PIPE CONTRACTION' + Flow1d_contraction.ContractArea1 = 70686 + Flow1d_contraction.ContractArea2 = 17671 + Flow1d_contraction.References = [(line, "Edge8")] + self.assertTrue(Flow1d_contraction, "FemTest of new Flow1D contraction constraint failed") + analysis.addObject(Flow1d_contraction) + + fcc_print('Checking FEM new Flow1D manning constraint...') + Flow1d_manning2 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_manning2.SectionType = 'Liquid' + Flow1d_manning2.LiquidSectionType = 'PIPE MANNING' + Flow1d_manning2.ManningArea = 17671.00 + Flow1d_manning2.ManningRadius = 37.5 + Flow1d_manning2.ManningCoefficient = 0.002 + Flow1d_manning2.References = [(line, "Edge11"), (line, "Edge9")] + self.assertTrue(Flow1d_manning2, "FemTest of new Flow1D manning constraint failed") + analysis.addObject(Flow1d_manning2) + + fcc_print('Checking FEM new Flow1D gate valve constraint...') + Flow1d_gate_valve = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_gate_valve.SectionType = 'Liquid' + Flow1d_gate_valve.LiquidSectionType = 'PIPE GATE VALVE' + Flow1d_gate_valve.GateValvePipeArea = 17671 + Flow1d_gate_valve.GateValveClosingCoeff = 0.5 + Flow1d_gate_valve.References = [(line, "Edge10")] + self.assertTrue(Flow1d_gate_valve, "FemTest of new Flow1D gate valve constraint failed") + analysis.addObject(Flow1d_gate_valve) + + fcc_print('Checking FEM new Flow1D enlargement constraint...') + Flow1d_enlargement1 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_enlargement1.SectionType = 'Liquid' + Flow1d_enlargement1.LiquidSectionType = 'PIPE ENLARGEMENT' + Flow1d_enlargement1.EnlargeArea1 = 17671 + Flow1d_enlargement1.EnlargeArea2 = 1e12 + Flow1d_enlargement1.References = [(line, "Edge12")] + self.assertTrue(Flow1d_enlargement1, "FemTest of new Flow1D enlargement constraint failed") + analysis.addObject(Flow1d_enlargement1) + + fcc_print('Checking FEM Flow1D outlet constraint...') + Flow1d_outlet = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") + Flow1d_outlet.SectionType = 'Liquid' + Flow1d_outlet.LiquidSectionType = 'PIPE OUTLET' + Flow1d_outlet.OutletPressure = 0.1 + Flow1d_outlet.References = [(line, "Edge13")] + self.assertTrue(Flow1d_outlet, "FemTest of new Flow1D inlet constraint failed") + analysis.addObject(Flow1d_outlet) + + fcc_print('Checking FEM self weight constraint...') + Flow1d_self_weight = ObjectsFem.makeConstraintSelfWeight(self.active_doc, "ConstraintSelfWeight") + Flow1d_self_weight.Gravity_x = 0.0 + Flow1d_self_weight.Gravity_y = 0.0 + Flow1d_self_weight.Gravity_z = -1.0 + self.assertTrue(Flow1d_outlet, "FemTest of new Flow1D self weight constraint failed") + analysis.addObject(Flow1d_self_weight) + + fcc_print('Checking FEM new mesh...') + from .testfiles.ccx.Flow1D_mesh import create_nodes_Flow1D + from .testfiles.ccx.Flow1D_mesh import create_elements_Flow1D + mesh = Fem.FemMesh() + ret = create_nodes_Flow1D(mesh) + self.assertTrue(ret, "Import of mesh nodes failed") + ret = create_elements_Flow1D(mesh) + self.assertTrue(ret, "Import of mesh volumes failed") + mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) + mesh_object.FemMesh = mesh + self.assertTrue(mesh, "FemTest of new mesh failed") + analysis.addObject(mesh_object) + + self.active_doc.recompute() + + fea = ccxtools.FemToolsCcx(analysis, test_mode=True) + fcc_print('Setting up working directory {}'.format(Flow1D_thermomech_analysis_dir)) + fea.setup_working_dir(Flow1D_thermomech_analysis_dir) + self.assertTrue(True if fea.working_dir == Flow1D_thermomech_analysis_dir else False, + "Setting working directory {} failed".format(Flow1D_thermomech_analysis_dir)) + + fcc_print('Checking FEM inp file prerequisites for thermo-mechanical analysis...') + error = fea.check_prerequisites() + self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) + + fcc_print('Checking FEM inp file write...') + + fcc_print('Writing {}/{}.inp for thermomech analysis'.format(Flow1D_thermomech_analysis_dir, mesh_name)) + error = fea.write_inp_file() + self.assertFalse(error, "Writing failed") + + fcc_print('Comparing {} to {}/{}.inp'.format(Flow1D_thermomech_analysis_inp_file, Flow1D_thermomech_analysis_dir, mesh_name)) + ret = compare_inp_files(Flow1D_thermomech_analysis_inp_file, Flow1D_thermomech_analysis_dir + mesh_name + '.inp') + self.assertFalse(ret, "ccxtools 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('Flow1D_thermomech')) + fea.set_base_name(Flow1D_thermomech_base_name) + self.assertTrue(True if fea.base_name == Flow1D_thermomech_base_name else False, + "Setting base name to {} failed".format(Flow1D_thermomech_base_name)) + + fcc_print('Setting inp file name to read test {}.frd file...'.format('Flow1D_thermomech')) + fea.set_inp_file_name() + self.assertTrue(True if fea.inp_file_name == Flow1D_thermomech_analysis_inp_file else False, + "Setting inp file name to {} failed".format(Flow1D_thermomech_analysis_inp_file)) + + fcc_print('Checking FEM frd file read from Flow1D 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 Flow1D thermomech analysis...') + ret = compare_stats(fea, Flow1D_thermomech_expected_values, stat_types, 'CalculiX_thermomech_time_1_0_results') + self.assertFalse(ret, "Invalid results read from .frd file") + + fcc_print('Save FreeCAD file for thermomech analysis to {}...'.format(Flow1D_thermomech_save_fc_file)) + self.active_doc.saveAs(Flow1D_thermomech_save_fc_file) + + fcc_print('--------------- End of FEM tests FLow 1D thermomech analysis ---------------') + + def tearDown(self): + FreeCAD.closeDocument("FemTest") + pass + + +def create_test_results(): + print("run FEM unit tests") + runTestFem() + + import shutil + import FemGui + + # static and frequency cube + FreeCAD.open(static_save_fc_file) + FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) + fea = ccxtools.FemToolsCcx() + + print("create static result files") + fea.reset_all() + fea.run() + fea.load_results() + stats_static = [] + for s in stat_types: + statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_static_results'), s) + stats_static.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) + 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) + f.close() + 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 = 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) + + print("create frequency result files") + fea.reset_all() + FreeCAD.ActiveDocument.CalculiX.AnalysisType = 'frequency' + fea.solver.EigenmodesCount = 1 # we should only have one result object + fea.run() + fea.load_results() + stats_frequency = [] + for s in stat_types: + statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_frequency_mode_1_results'), s) + stats_frequency.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) + 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 = 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("create thermomech result files") + FreeCAD.open(thermomech_save_fc_file) + FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) + fea = ccxtools.FemToolsCcx() + fea.reset_all() + fea.run() + fea.load_results() + stats_thermomech = [] + for s in stat_types: + statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_thermomech_results'), s) + stats_thermomech.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) + thermomech_expected_values_file = thermomech_analysis_dir + 'spine_thermomech_expected_values' + f = open(thermomech_expected_values_file, 'w') + for s in stats_thermomech: + f.write(s) + f.close() + 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) + + print("create Flow1D result files") + FreeCAD.open(Flow1D_thermomech_save_fc_file) + FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) + fea = ccxtools.FemToolsCcx() + fea.reset_all() + fea.run() + fea.load_results() + stats_flow1D = [] + for s in stat_types: + statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_thermomech_time_1_0_results'), s) + stats_flow1D.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) + Flow1D_thermomech_expected_values_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech_expected_values' + f = open(Flow1D_thermomech_expected_values_file, 'w') + for s in stats_flow1D: + f.write(s) + f.close() + 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_Flow1D_thermomech_test_result_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech.frd' + dat_Flow1D_thermomech_test_result_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech.dat' + shutil.copyfile(frd_result_file, frd_Flow1D_thermomech_test_result_file) + shutil.copyfile(dat_result_file, dat_Flow1D_thermomech_test_result_file) + print('Flow1D thermomech results copied to the appropriate FEM test dirs in: ' + temp_dir) + + +''' +update the results of FEM unit tests: + +import femtest.testfemcommon +femtest.testfemcommon.create_test_results() + +copy result files from your_temp_directory/FEM_unittests/ test directories into the src directory +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 + +TODO compare the inp file of the helper with the inp file of FEM unit tests +TODO the better way: move the result creation inside the TestFem and add some preference to deactivate this because it needs ccx +''' diff --git a/src/Mod/Fem/femtest/testfemcommon.py b/src/Mod/Fem/femtest/testfemcommon.py index 49c34d4818..cd0301c39a 100644 --- a/src/Mod/Fem/femtest/testfemcommon.py +++ b/src/Mod/Fem/femtest/testfemcommon.py @@ -666,822 +666,3 @@ class FemTest(unittest.TestCase): def tearDown(self): FreeCAD.closeDocument("FemTest") pass - - -class FemCcxAnalysisTest(unittest.TestCase): - - def setUp(self): - try: - FreeCAD.setActiveDocument("FemTest") - except: - FreeCAD.newDocument("FemTest") - finally: - FreeCAD.setActiveDocument("FemTest") - self.active_doc = FreeCAD.ActiveDocument - - def test_static_freq_analysis(self): - # static - fcc_print('--------------- Start of FEM tests ---------------') - box = self.active_doc.addObject("Part::Box", "Box") - fcc_print('Checking FEM new analysis...') - analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') - self.assertTrue(analysis, "FemTest of new analysis failed") - - fcc_print('Checking FEM new solver...') - solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') - solver_object.AnalysisType = 'static' - solver_object.GeometricalNonlinearity = 'linear' - solver_object.ThermoMechSteadyState = False - solver_object.MatrixSolverType = 'default' - solver_object.IterationsControlParameterTimeUse = False - solver_object.EigenmodesCount = 10 - solver_object.EigenmodeHighLimit = 1000000.0 - solver_object.EigenmodeLowLimit = 0.0 - self.assertTrue(solver_object, "FemTest of new solver failed") - analysis.addObject(solver_object) - - fcc_print('Checking FEM new material...') - material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') - mat = material_object.Material - mat['Name'] = "Steel-Generic" - mat['YoungsModulus'] = "200000 MPa" - mat['PoissonRatio'] = "0.30" - mat['Density'] = "7900 kg/m^3" - material_object.Material = mat - self.assertTrue(material_object, "FemTest of new material failed") - analysis.addObject(material_object) - - fcc_print('Checking FEM new fixed constraint...') - fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") - fixed_constraint.References = [(box, "Face1")] - self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") - analysis.addObject(fixed_constraint) - - fcc_print('Checking FEM new force constraint...') - force_constraint = self.active_doc.addObject("Fem::ConstraintForce", "FemConstraintForce") - force_constraint.References = [(box, "Face6")] - force_constraint.Force = 40000.0 - force_constraint.Direction = (box, ["Edge5"]) - self.active_doc.recompute() - force_constraint.Reversed = True - self.active_doc.recompute() - self.assertTrue(force_constraint, "FemTest of new force constraint failed") - analysis.addObject(force_constraint) - - fcc_print('Checking FEM new pressure constraint...') - pressure_constraint = self.active_doc.addObject("Fem::ConstraintPressure", "FemConstraintPressure") - pressure_constraint.References = [(box, "Face2")] - pressure_constraint.Pressure = 1000.0 - pressure_constraint.Reversed = False - self.assertTrue(pressure_constraint, "FemTest of new pressure constraint failed") - analysis.addObject(pressure_constraint) - - fcc_print('Checking FEM new mesh...') - from .testfiles.ccx.cube_mesh import create_nodes_cube - from .testfiles.ccx.cube_mesh import create_elements_cube - mesh = Fem.FemMesh() - ret = create_nodes_cube(mesh) - self.assertTrue(ret, "Import of mesh nodes failed") - ret = create_elements_cube(mesh) - self.assertTrue(ret, "Import of mesh volumes failed") - mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) - mesh_object.FemMesh = mesh - self.assertTrue(mesh, "FemTest of new mesh failed") - analysis.addObject(mesh_object) - - self.active_doc.recompute() - - fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True) - fcc_print('Setting up working directory {}'.format(static_analysis_dir)) - fea.setup_working_dir(static_analysis_dir) - self.assertTrue(True if fea.working_dir == static_analysis_dir else False, - "Setting working directory {} failed".format(static_analysis_dir)) - - fcc_print('Checking FEM inp file prerequisites for static analysis...') - error = fea.check_prerequisites() - self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) - - fcc_print('Checking FEM inp file write...') - fcc_print('Writing {}/{}.inp for static analysis'.format(static_analysis_dir, mesh_name)) - error = fea.write_inp_file() - self.assertFalse(error, "Writing failed") - - fcc_print('Comparing {} to {}/{}.inp'.format(static_analysis_inp_file, static_analysis_dir, mesh_name)) - ret = compare_inp_files(static_analysis_inp_file, static_analysis_dir + mesh_name + '.inp') - self.assertFalse(ret, "ccxtools 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('Setting inp file name to read test {}.frd file...'.format('cube_static')) - fea.set_inp_file_name() - self.assertTrue(True if fea.inp_file_name == static_analysis_inp_file else False, - "Setting inp file name to {} failed".format(static_analysis_inp_file)) - - fcc_print('Checking FEM frd file read from static 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 static analysis...') - ret = compare_stats(fea, static_expected_values, 'CalculiX_static_results') - self.assertFalse(ret, "Invalid results read from .frd file") - - fcc_print('Save FreeCAD file for static analysis to {}...'.format(static_save_fc_file)) - self.active_doc.saveAs(static_save_fc_file) - - # frequency - fcc_print('Reset Statik analysis') - fea.reset_all() - fcc_print('Setting analysis type to \'frequency\"') - solver_object.AnalysisType = 'frequency' - - - fcc_print('Setting up working directory to {} in order to write frequency calculations'.format(frequency_analysis_dir)) - fea.setup_working_dir(frequency_analysis_dir) - self.assertTrue(True if fea.working_dir == frequency_analysis_dir else False, - "Setting working directory {} failed".format(frequency_analysis_dir)) - - fcc_print('Checking FEM inp file prerequisites for frequency analysis...') - error = fea.check_prerequisites() - self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) - - fcc_print('Writing {}/{}.inp for frequency analysis'.format(frequency_analysis_dir, mesh_name)) - error = fea.write_inp_file() - self.assertFalse(error, "Writing failed") - - fcc_print('Comparing {} to {}/{}.inp'.format(frequency_analysis_inp_file, frequency_analysis_dir, mesh_name)) - ret = compare_inp_files(frequency_analysis_inp_file, frequency_analysis_dir + mesh_name + '.inp') - self.assertFalse(ret, "ccxtools 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('Setting inp file name to read test {}.frd file...'.format('cube_frequency')) - fea.set_inp_file_name() - self.assertTrue(True if fea.inp_file_name == frequency_analysis_inp_file else False, - "Setting inp file name to {} failed".format(frequency_analysis_inp_file)) - - fcc_print('Checking FEM frd file read from frequency 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 frequency analysis...') - ret = compare_stats(fea, frequency_expected_values, 'CalculiX_frequency_mode_1_results') - self.assertFalse(ret, "Invalid results read from .frd file") - - fcc_print('Save FreeCAD file for frequency analysis to {}...'.format(frequency_save_fc_file)) - self.active_doc.saveAs(frequency_save_fc_file) - fcc_print('--------------- End of FEM tests static and frequency analysis ---------------') - - def test_thermomech_analysis(self): - fcc_print('--------------- Start of FEM tests ---------------') - box = self.active_doc.addObject("Part::Box", "Box") - box.Height = 25.4 - box.Width = 25.4 - box.Length = 203.2 - fcc_print('Checking FEM new analysis...') - analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') - self.assertTrue(analysis, "FemTest of new analysis failed") - - fcc_print('Checking FEM new solver...') - solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') - solver_object.AnalysisType = 'thermomech' - solver_object.GeometricalNonlinearity = 'linear' - solver_object.ThermoMechSteadyState = True - solver_object.MatrixSolverType = 'default' - solver_object.IterationsThermoMechMaximum = 2000 - solver_object.IterationsControlParameterTimeUse = True - self.assertTrue(solver_object, "FemTest of new solver failed") - analysis.addObject(solver_object) - - fcc_print('Checking FEM new material...') - material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') - mat = material_object.Material - mat['Name'] = "Steel-Generic" - mat['YoungsModulus'] = "200000 MPa" - mat['PoissonRatio'] = "0.30" - mat['Density'] = "7900 kg/m^3" - mat['ThermalConductivity'] = "43.27 W/m/K" # SvdW: Change to Ansys model values - mat['ThermalExpansionCoefficient'] = "12 um/m/K" - mat['SpecificHeat'] = "500 J/kg/K" # SvdW: Change to Ansys model values - material_object.Material = mat - self.assertTrue(material_object, "FemTest of new material failed") - analysis.addObject(material_object) - - fcc_print('Checking FEM new fixed constraint...') - fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") - fixed_constraint.References = [(box, "Face1")] - self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") - analysis.addObject(fixed_constraint) - - fcc_print('Checking FEM new initial temperature constraint...') - initialtemperature_constraint = self.active_doc.addObject("Fem::ConstraintInitialTemperature", "FemConstraintInitialTemperature") - initialtemperature_constraint.initialTemperature = 300.0 - self.assertTrue(initialtemperature_constraint, "FemTest of new initial temperature constraint failed") - analysis.addObject(initialtemperature_constraint) - - fcc_print('Checking FEM new temperature constraint...') - temperature_constraint = self.active_doc.addObject("Fem::ConstraintTemperature", "FemConstraintTemperature") - temperature_constraint.References = [(box, "Face1")] - temperature_constraint.Temperature = 310.93 - self.assertTrue(temperature_constraint, "FemTest of new temperature constraint failed") - analysis.addObject(temperature_constraint) - - fcc_print('Checking FEM new heatflux constraint...') - heatflux_constraint = self.active_doc.addObject("Fem::ConstraintHeatflux", "FemConstraintHeatflux") - heatflux_constraint.References = [(box, "Face3"), (box, "Face4"), (box, "Face5"), (box, "Face6")] - heatflux_constraint.AmbientTemp = 255.3722 - heatflux_constraint.FilmCoef = 5.678 - self.assertTrue(heatflux_constraint, "FemTest of new heatflux constraint failed") - analysis.addObject(heatflux_constraint) - - fcc_print('Checking FEM new mesh...') - from .testfiles.ccx.spine_mesh import create_nodes_spine - from .testfiles.ccx.spine_mesh import create_elements_spine - mesh = Fem.FemMesh() - ret = create_nodes_spine(mesh) - self.assertTrue(ret, "Import of mesh nodes failed") - ret = create_elements_spine(mesh) - self.assertTrue(ret, "Import of mesh volumes failed") - mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) - mesh_object.FemMesh = mesh - self.assertTrue(mesh, "FemTest of new mesh failed") - analysis.addObject(mesh_object) - - self.active_doc.recompute() - - fea = ccxtools.FemToolsCcx(analysis, test_mode=True) - fcc_print('Setting up working directory {}'.format(thermomech_analysis_dir)) - fea.setup_working_dir(thermomech_analysis_dir) - self.assertTrue(True if fea.working_dir == thermomech_analysis_dir else False, - "Setting working directory {} failed".format(thermomech_analysis_dir)) - - fcc_print('Checking FEM inp file prerequisites for thermo-mechanical analysis...') - error = fea.check_prerequisites() - self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) - - fcc_print('Checking FEM inp file write...') - - fcc_print('Writing {}/{}.inp for thermomech analysis'.format(thermomech_analysis_dir, mesh_name)) - error = fea.write_inp_file() - self.assertFalse(error, "Writing failed") - - fcc_print('Comparing {} to {}/{}.inp'.format(thermomech_analysis_inp_file, thermomech_analysis_dir, mesh_name)) - ret = compare_inp_files(thermomech_analysis_inp_file, thermomech_analysis_dir + mesh_name + '.inp') - self.assertFalse(ret, "ccxtools 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('spine_thermomech')) - fea.set_base_name(thermomech_base_name) - self.assertTrue(True if fea.base_name == thermomech_base_name else False, - "Setting base name to {} failed".format(thermomech_base_name)) - - fcc_print('Setting inp file name to read test {}.frd file...'.format('spine_thermomech')) - fea.set_inp_file_name() - 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 = compare_stats(fea, thermomech_expected_values, 'CalculiX_thermomech_results') - self.assertFalse(ret, "Invalid results read from .frd file") - - fcc_print('Save FreeCAD file for thermomech analysis to {}...'.format(thermomech_save_fc_file)) - self.active_doc.saveAs(thermomech_save_fc_file) - - fcc_print('--------------- End of FEM tests thermomech analysis ---------------') - - def test_Flow1D_thermomech_analysis(self): - fcc_print('--------------- Start of 1D Flow FEM tests ---------------') - import Draft - p1 = FreeCAD.Vector(0, 0, 50) - p2 = FreeCAD.Vector(0, 0, -50) - p3 = FreeCAD.Vector(0, 0, -4300) - p4 = FreeCAD.Vector(4950, 0, -4300) - p5 = FreeCAD.Vector(5000, 0, -4300) - p6 = FreeCAD.Vector(8535.53, 0, -7835.53) - p7 = FreeCAD.Vector(8569.88, 0, -7870.88) - p8 = FreeCAD.Vector(12105.41, 0, -11406.41) - p9 = FreeCAD.Vector(12140.76, 0, -11441.76) - p10 = FreeCAD.Vector(13908.53, 0, -13209.53) - p11 = FreeCAD.Vector(13943.88, 0, -13244.88) - p12 = FreeCAD.Vector(15046.97, 0, -14347.97) - p13 = FreeCAD.Vector(15046.97, 0, -7947.97) - p14 = FreeCAD.Vector(15046.97, 0, -7847.97) - p15 = FreeCAD.Vector(0, 0, 0) - p16 = FreeCAD.Vector(0, 0, -2175) - p17 = FreeCAD.Vector(2475, 0, -4300) - p18 = FreeCAD.Vector(4975, 0, -4300) - p19 = FreeCAD.Vector(6767.765, 0, -6067.765) - p20 = FreeCAD.Vector(8552.705, 0, -7853.205) - p21 = FreeCAD.Vector(10337.645, 0, -9638.645) - p22 = FreeCAD.Vector(12123.085, 0, -11424.085) - p23 = FreeCAD.Vector(13024.645, 0, -12325.645) - p24 = FreeCAD.Vector(13926.205, 0, -13227.205) - p25 = FreeCAD.Vector(14495.425, 0, -13796.425) - p26 = FreeCAD.Vector(15046.97, 0, -11147.97) - p27 = FreeCAD.Vector(15046.97, 0, -7897.97) - points = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27] - line = Draft.makeWire(points, closed=False, face=False, support=None) - fcc_print('Checking FEM new analysis...') - analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') - self.assertTrue(analysis, "FemTest of new analysis failed") - - fcc_print('Checking FEM new solver...') - solver_object = ObjectsFem.makeSolverCalculixCcxTools(self.active_doc, 'CalculiX') - solver_object.AnalysisType = 'thermomech' - solver_object.GeometricalNonlinearity = 'linear' - solver_object.ThermoMechSteadyState = True - solver_object.MatrixSolverType = 'default' - solver_object.IterationsThermoMechMaximum = 2000 - solver_object.IterationsControlParameterTimeUse = False - self.assertTrue(solver_object, "FemTest of new solver failed") - analysis.addObject(solver_object) - - fcc_print('Checking FEM new material...') - material_object = ObjectsFem.makeMaterialFluid(self.active_doc, 'FluidMaterial') - mat = material_object.Material - mat['Name'] = "Water" - mat['Density'] = "998 kg/m^3" - mat['SpecificHeat'] = "4.182 J/kg/K" - mat['DynamicViscosity'] = "1.003e-3 kg/m/s" - mat['VolumetricThermalExpansionCoefficient'] = "2.07e-4 m/m/K" - mat['ThermalConductivity'] = "0.591 W/m/K" - material_object.Material = mat - self.assertTrue(material_object, "FemTest of new material failed") - analysis.addObject(material_object) - - fcc_print('Checking FEM Flow1D inlet constraint...') - Flow1d_inlet = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_inlet.SectionType = 'Liquid' - Flow1d_inlet.LiquidSectionType = 'PIPE INLET' - Flow1d_inlet.InletPressure = 0.1 - Flow1d_inlet.References = [(line, "Edge1")] - self.assertTrue(Flow1d_inlet, "FemTest of new Flow1D inlet constraint failed") - analysis.addObject(Flow1d_inlet) - - fcc_print('Checking FEM new Flow1D entrance constraint...') - Flow1d_entrance = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_entrance.SectionType = 'Liquid' - Flow1d_entrance.LiquidSectionType = 'PIPE ENTRANCE' - Flow1d_entrance.EntrancePipeArea = 31416.00 - Flow1d_entrance.EntranceArea = 25133.00 - Flow1d_entrance.References = [(line, "Edge2")] - self.assertTrue(Flow1d_entrance, "FemTest of new Flow1D entrance constraint failed") - analysis.addObject(Flow1d_entrance) - - fcc_print('Checking FEM new Flow1D manning constraint...') - Flow1d_manning = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_manning.SectionType = 'Liquid' - Flow1d_manning.LiquidSectionType = 'PIPE MANNING' - Flow1d_manning.ManningArea = 31416 - Flow1d_manning.ManningRadius = 50 - Flow1d_manning.ManningCoefficient = 0.002 - Flow1d_manning.References = [(line, "Edge3"), (line, "Edge5")] - self.assertTrue(Flow1d_manning, "FemTest of new Flow1D manning constraint failed") - analysis.addObject(Flow1d_manning) - - fcc_print('Checking FEM new Flow1D bend constraint...') - Flow1d_bend = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_bend.SectionType = 'Liquid' - Flow1d_bend.LiquidSectionType = 'PIPE BEND' - Flow1d_bend.BendPipeArea = 31416 - Flow1d_bend.BendRadiusDiameter = 1.5 - Flow1d_bend.BendAngle = 45 - Flow1d_bend.BendLossCoefficient = 0.4 - Flow1d_bend.References = [(line, "Edge4")] - self.assertTrue(Flow1d_bend, "FemTest of new Flow1D bend constraint failed") - analysis.addObject(Flow1d_bend) - - fcc_print('Checking FEM new Flow1D enlargement constraint...') - Flow1d_enlargement = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_enlargement.SectionType = 'Liquid' - Flow1d_enlargement.LiquidSectionType = 'PIPE ENLARGEMENT' - Flow1d_enlargement.EnlargeArea1 = 31416.00 - Flow1d_enlargement.EnlargeArea2 = 70686.00 - Flow1d_enlargement.References = [(line, "Edge6")] - self.assertTrue(Flow1d_enlargement, "FemTest of new Flow1D enlargement constraint failed") - analysis.addObject(Flow1d_enlargement) - - fcc_print('Checking FEM new Flow1D manning constraint...') - Flow1d_manning1 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_manning1.SectionType = 'Liquid' - Flow1d_manning1.LiquidSectionType = 'PIPE MANNING' - Flow1d_manning1.ManningArea = 70686.00 - Flow1d_manning1.ManningRadius = 75 - Flow1d_manning1.ManningCoefficient = 0.002 - Flow1d_manning1.References = [(line, "Edge7")] - self.assertTrue(Flow1d_manning1, "FemTest of new Flow1D manning constraint failed") - analysis.addObject(Flow1d_manning1) - - fcc_print('Checking FEM new Flow1D contraction constraint...') - Flow1d_contraction = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_contraction.SectionType = 'Liquid' - Flow1d_contraction.LiquidSectionType = 'PIPE CONTRACTION' - Flow1d_contraction.ContractArea1 = 70686 - Flow1d_contraction.ContractArea2 = 17671 - Flow1d_contraction.References = [(line, "Edge8")] - self.assertTrue(Flow1d_contraction, "FemTest of new Flow1D contraction constraint failed") - analysis.addObject(Flow1d_contraction) - - fcc_print('Checking FEM new Flow1D manning constraint...') - Flow1d_manning2 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_manning2.SectionType = 'Liquid' - Flow1d_manning2.LiquidSectionType = 'PIPE MANNING' - Flow1d_manning2.ManningArea = 17671.00 - Flow1d_manning2.ManningRadius = 37.5 - Flow1d_manning2.ManningCoefficient = 0.002 - Flow1d_manning2.References = [(line, "Edge11"), (line, "Edge9")] - self.assertTrue(Flow1d_manning2, "FemTest of new Flow1D manning constraint failed") - analysis.addObject(Flow1d_manning2) - - fcc_print('Checking FEM new Flow1D gate valve constraint...') - Flow1d_gate_valve = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_gate_valve.SectionType = 'Liquid' - Flow1d_gate_valve.LiquidSectionType = 'PIPE GATE VALVE' - Flow1d_gate_valve.GateValvePipeArea = 17671 - Flow1d_gate_valve.GateValveClosingCoeff = 0.5 - Flow1d_gate_valve.References = [(line, "Edge10")] - self.assertTrue(Flow1d_gate_valve, "FemTest of new Flow1D gate valve constraint failed") - analysis.addObject(Flow1d_gate_valve) - - fcc_print('Checking FEM new Flow1D enlargement constraint...') - Flow1d_enlargement1 = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_enlargement1.SectionType = 'Liquid' - Flow1d_enlargement1.LiquidSectionType = 'PIPE ENLARGEMENT' - Flow1d_enlargement1.EnlargeArea1 = 17671 - Flow1d_enlargement1.EnlargeArea2 = 1e12 - Flow1d_enlargement1.References = [(line, "Edge12")] - self.assertTrue(Flow1d_enlargement1, "FemTest of new Flow1D enlargement constraint failed") - analysis.addObject(Flow1d_enlargement1) - - fcc_print('Checking FEM Flow1D outlet constraint...') - Flow1d_outlet = ObjectsFem.makeElementFluid1D(self.active_doc, "ElementFluid1D") - Flow1d_outlet.SectionType = 'Liquid' - Flow1d_outlet.LiquidSectionType = 'PIPE OUTLET' - Flow1d_outlet.OutletPressure = 0.1 - Flow1d_outlet.References = [(line, "Edge13")] - self.assertTrue(Flow1d_outlet, "FemTest of new Flow1D inlet constraint failed") - analysis.addObject(Flow1d_outlet) - - fcc_print('Checking FEM self weight constraint...') - Flow1d_self_weight = ObjectsFem.makeConstraintSelfWeight(self.active_doc, "ConstraintSelfWeight") - Flow1d_self_weight.Gravity_x = 0.0 - Flow1d_self_weight.Gravity_y = 0.0 - Flow1d_self_weight.Gravity_z = -1.0 - self.assertTrue(Flow1d_outlet, "FemTest of new Flow1D self weight constraint failed") - analysis.addObject(Flow1d_self_weight) - - fcc_print('Checking FEM new mesh...') - from .testfiles.ccx.Flow1D_mesh import create_nodes_Flow1D - from .testfiles.ccx.Flow1D_mesh import create_elements_Flow1D - mesh = Fem.FemMesh() - ret = create_nodes_Flow1D(mesh) - self.assertTrue(ret, "Import of mesh nodes failed") - ret = create_elements_Flow1D(mesh) - self.assertTrue(ret, "Import of mesh volumes failed") - mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) - mesh_object.FemMesh = mesh - self.assertTrue(mesh, "FemTest of new mesh failed") - analysis.addObject(mesh_object) - - self.active_doc.recompute() - - fea = ccxtools.FemToolsCcx(analysis, test_mode=True) - fcc_print('Setting up working directory {}'.format(Flow1D_thermomech_analysis_dir)) - fea.setup_working_dir(Flow1D_thermomech_analysis_dir) - self.assertTrue(True if fea.working_dir == Flow1D_thermomech_analysis_dir else False, - "Setting working directory {} failed".format(Flow1D_thermomech_analysis_dir)) - - fcc_print('Checking FEM inp file prerequisites for thermo-mechanical analysis...') - error = fea.check_prerequisites() - self.assertFalse(error, "ccxtools check_prerequisites returned error message: {}".format(error)) - - fcc_print('Checking FEM inp file write...') - - fcc_print('Writing {}/{}.inp for thermomech analysis'.format(Flow1D_thermomech_analysis_dir, mesh_name)) - error = fea.write_inp_file() - self.assertFalse(error, "Writing failed") - - fcc_print('Comparing {} to {}/{}.inp'.format(Flow1D_thermomech_analysis_inp_file, Flow1D_thermomech_analysis_dir, mesh_name)) - ret = compare_inp_files(Flow1D_thermomech_analysis_inp_file, Flow1D_thermomech_analysis_dir + mesh_name + '.inp') - self.assertFalse(ret, "ccxtools 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('Flow1D_thermomech')) - fea.set_base_name(Flow1D_thermomech_base_name) - self.assertTrue(True if fea.base_name == Flow1D_thermomech_base_name else False, - "Setting base name to {} failed".format(Flow1D_thermomech_base_name)) - - fcc_print('Setting inp file name to read test {}.frd file...'.format('Flow1D_thermomech')) - fea.set_inp_file_name() - self.assertTrue(True if fea.inp_file_name == Flow1D_thermomech_analysis_inp_file else False, - "Setting inp file name to {} failed".format(Flow1D_thermomech_analysis_inp_file)) - - fcc_print('Checking FEM frd file read from Flow1D 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 Flow1D thermomech analysis...') - ret = compare_stats(fea, Flow1D_thermomech_expected_values, stat_types, 'CalculiX_thermomech_time_1_0_results') - self.assertFalse(ret, "Invalid results read from .frd file") - - fcc_print('Save FreeCAD file for thermomech analysis to {}...'.format(Flow1D_thermomech_save_fc_file)) - self.active_doc.saveAs(Flow1D_thermomech_save_fc_file) - - fcc_print('--------------- End of FEM tests FLow 1D thermomech analysis ---------------') - - def tearDown(self): - FreeCAD.closeDocument("FemTest") - pass - - -class SolverFrameWorkTest(unittest.TestCase): - - def setUp(self): - try: - FreeCAD.setActiveDocument("FemTest") - except: - FreeCAD.newDocument("FemTest") - finally: - FreeCAD.setActiveDocument("FemTest") - self.active_doc = FreeCAD.ActiveDocument - - def test_solver_framework(self): - fcc_print('--------------- Start of FEM tests solver frame work ---------------') - box = self.active_doc.addObject("Part::Box", "Box") - fcc_print('Checking FEM new analysis...') - analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') - self.assertTrue(analysis, "FemTest of new analysis failed") - - fcc_print('Checking FEM new material...') - material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') - mat = material_object.Material - mat['Name'] = "Steel-Generic" - mat['YoungsModulus'] = "200000 MPa" - mat['PoissonRatio'] = "0.30" - mat['Density'] = "7900 kg/m^3" - material_object.Material = mat - self.assertTrue(material_object, "FemTest of new material failed") - analysis.addObject(material_object) - - fcc_print('Checking FEM new fixed constraint...') - fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") - fixed_constraint.References = [(box, "Face1")] - self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") - analysis.addObject(fixed_constraint) - - fcc_print('Checking FEM new force constraint...') - force_constraint = self.active_doc.addObject("Fem::ConstraintForce", "FemConstraintForce") - force_constraint.References = [(box, "Face6")] - force_constraint.Force = 40000.0 - force_constraint.Direction = (box, ["Edge5"]) - self.active_doc.recompute() - force_constraint.Reversed = True - self.active_doc.recompute() - self.assertTrue(force_constraint, "FemTest of new force constraint failed") - analysis.addObject(force_constraint) - - fcc_print('Checking FEM new pressure constraint...') - pressure_constraint = self.active_doc.addObject("Fem::ConstraintPressure", "FemConstraintPressure") - pressure_constraint.References = [(box, "Face2")] - pressure_constraint.Pressure = 1000.0 - pressure_constraint.Reversed = False - self.assertTrue(pressure_constraint, "FemTest of new pressure constraint failed") - analysis.addObject(pressure_constraint) - - fcc_print('Checking FEM new mesh...') - from .testfiles.ccx.cube_mesh import create_nodes_cube - from .testfiles.ccx.cube_mesh import create_elements_cube - mesh = Fem.FemMesh() - ret = create_nodes_cube(mesh) - self.assertTrue(ret, "Import of mesh nodes failed") - ret = create_elements_cube(mesh) - self.assertTrue(ret, "Import of mesh volumes failed") - mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) - mesh_object.FemMesh = mesh - self.assertTrue(mesh, "FemTest of new mesh failed") - analysis.addObject(mesh_object) - - self.active_doc.recompute() - - # solver frame work ccx solver - fcc_print('Checking FEM solver for solver frame work...') - solver_ccx2_object = ObjectsFem.makeSolverCalculix(self.active_doc, 'SolverCalculiX') - solver_ccx2_object.GeometricalNonlinearity = 'linear' - solver_ccx2_object.ThermoMechSteadyState = False - solver_ccx2_object.MatrixSolverType = 'default' - solver_ccx2_object.IterationsControlParameterTimeUse = False - solver_ccx2_object.EigenmodesCount = 10 - solver_ccx2_object.EigenmodeHighLimit = 1000000.0 - solver_ccx2_object.EigenmodeLowLimit = 0.0 - self.assertTrue(solver_ccx2_object, "FemTest of new ccx solver failed") - analysis.addObject(solver_ccx2_object) - - fcc_print('Checking inpfile writing for solverframework_save_fc_file frame work...') - if not os.path.exists(solverframework_analysis_dir): # solver frameworkd does explicit not create a non existing directory - os.makedirs(solverframework_analysis_dir) - - fcc_print('machine_ccx') - machine_ccx = solver_ccx2_object.Proxy.createMachine(solver_ccx2_object, solverframework_analysis_dir) - fcc_print('Machine testmode: ' + str(machine_ccx.testmode)) - machine_ccx.target = femsolver.run.PREPARE - machine_ccx.start() - machine_ccx.join() # wait for the machine to finish. - fcc_print('Comparing {} to {}/{}.inp'.format(static_analysis_inp_file, solverframework_analysis_dir, mesh_name)) - ret = compare_inp_files(static_analysis_inp_file, solverframework_analysis_dir + mesh_name + '.inp') - self.assertFalse(ret, "ccxtools write_inp_file test failed.\n{}".format(ret)) - - # use solver frame work elmer solver - solver_elmer_object = ObjectsFem.makeSolverElmer(self.active_doc, 'SolverElmer') - self.assertTrue(solver_elmer_object, "FemTest of elmer solver failed") - analysis.addObject(solver_elmer_object) - solver_elmer_eqobj = ObjectsFem.makeEquationElasticity(self.active_doc, solver_elmer_object) - self.assertTrue(solver_elmer_eqobj, "FemTest of elmer elasticity equation failed") - - # set ThermalExpansionCoefficient, current elmer seems to need it even on simple elasticity analysis - mat = material_object.Material - mat['ThermalExpansionCoefficient'] = "0 um/m/K" # FIXME elmer elasticity needs the dictionary key, otherwise it fails - material_object.Material = mat - - mesh_gmsh = ObjectsFem.makeMeshGmsh(self.active_doc) - mesh_gmsh.CharacteristicLengthMin = "9 mm" - mesh_gmsh.FemMesh = mesh_object.FemMesh # elmer needs a GMHS mesh object, FIXME error message on Python solver run - mesh_gmsh.Part = box - analysis.addObject(mesh_gmsh) - self.active_doc.removeObject(mesh_object.Name) - - fcc_print('machine_elmer') - machine_elmer = solver_elmer_object.Proxy.createMachine(solver_elmer_object, solverframework_analysis_dir, True) - fcc_print('Machine testmode: ' + str(machine_elmer.testmode)) - machine_elmer.target = femsolver.run.PREPARE - machine_elmer.start() - machine_elmer.join() # wait for the machine to finish. - - ''' - fcc_print('Test writing STARTINFO file') - fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'ELMERSOLVER_STARTINFO', solverframework_analysis_dir + 'ELMERSOLVER_STARTINFO')) - ret = compare_files(test_file_dir_elmer + 'ELMERSOLVER_STARTINFO', solverframework_analysis_dir + 'ELMERSOLVER_STARTINFO') - self.assertFalse(ret, "STARTINFO write file test failed.\n{}".format(ret)) - - fcc_print('Test writing case file') - fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'case.sif', solverframework_analysis_dir + 'case.sif')) - ret = compare_files(test_file_dir_elmer + 'case.sif', solverframework_analysis_dir + 'case.sif') - self.assertFalse(ret, "case write file test failed.\n{}".format(ret)) - - fcc_print('Test writing GMSH geo file') - fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'group_mesh.geo', solverframework_analysis_dir + 'group_mesh.geo')) - ret = compare_files(test_file_dir_elmer + 'group_mesh.geo', solverframework_analysis_dir + 'group_mesh.geo') - self.assertFalse(ret, "GMSH geo write file test failed.\n{}".format(ret)) - ''' - - fcc_print('Save FreeCAD file for static2 analysis to {}...'.format(solverframework_save_fc_file)) - self.active_doc.saveAs(solverframework_save_fc_file) - fcc_print('--------------- End of FEM tests solver frame work ---------------') - - def tearDown(self): - FreeCAD.closeDocument("FemTest") - pass - - -def create_test_results(): - print("run FEM unit tests") - runTestFem() - - import shutil - import FemGui - - # static and frequency cube - FreeCAD.open(static_save_fc_file) - FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) - fea = ccxtools.FemToolsCcx() - - print("create static result files") - fea.reset_all() - fea.run() - fea.load_results() - stats_static = [] - for s in stat_types: - statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_static_results'), s) - stats_static.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) - 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) - f.close() - 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 = 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) - - print("create frequency result files") - fea.reset_all() - FreeCAD.ActiveDocument.CalculiX.AnalysisType = 'frequency' - fea.solver.EigenmodesCount = 1 # we should only have one result object - fea.run() - fea.load_results() - stats_frequency = [] - for s in stat_types: - statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_frequency_mode_1_results'), s) - stats_frequency.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) - 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 = 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("create thermomech result files") - FreeCAD.open(thermomech_save_fc_file) - FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) - fea = ccxtools.FemToolsCcx() - fea.reset_all() - fea.run() - fea.load_results() - stats_thermomech = [] - for s in stat_types: - statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_thermomech_results'), s) - stats_thermomech.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) - thermomech_expected_values_file = thermomech_analysis_dir + 'spine_thermomech_expected_values' - f = open(thermomech_expected_values_file, 'w') - for s in stats_thermomech: - f.write(s) - f.close() - 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) - - print("create Flow1D result files") - FreeCAD.open(Flow1D_thermomech_save_fc_file) - FemGui.setActiveAnalysis(FreeCAD.ActiveDocument.Analysis) - fea = ccxtools.FemToolsCcx() - fea.reset_all() - fea.run() - fea.load_results() - stats_flow1D = [] - for s in stat_types: - statval = resulttools.get_stats(FreeCAD.ActiveDocument.getObject('CalculiX_thermomech_time_1_0_results'), s) - stats_flow1D.append("{0}: ({1:.14g}, {2:.14g}, {3:.14g})\n".format(s, statval[0], statval[1], statval[2])) - Flow1D_thermomech_expected_values_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech_expected_values' - f = open(Flow1D_thermomech_expected_values_file, 'w') - for s in stats_flow1D: - f.write(s) - f.close() - 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_Flow1D_thermomech_test_result_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech.frd' - dat_Flow1D_thermomech_test_result_file = Flow1D_thermomech_analysis_dir + 'Flow1D_thermomech.dat' - shutil.copyfile(frd_result_file, frd_Flow1D_thermomech_test_result_file) - shutil.copyfile(dat_result_file, dat_Flow1D_thermomech_test_result_file) - print('Flow1D thermomech results copied to the appropriate FEM test dirs in: ' + temp_dir) - - -''' -update the results of FEM unit tests: - -import femtest.testfemcommon -femtest.testfemcommon.create_test_results() - -copy result files from your_temp_directory/FEM_unittests/ test directories into the src directory -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 - -TODO compare the inp file of the helper with the inp file of FEM unit tests -TODO the better way: move the result creation inside the TestFem and add some preference to deactivate this because it needs ccx -''' diff --git a/src/Mod/Fem/femtest/testsolverframework.py b/src/Mod/Fem/femtest/testsolverframework.py new file mode 100644 index 0000000000..0ececa32a1 --- /dev/null +++ b/src/Mod/Fem/femtest/testsolverframework.py @@ -0,0 +1,231 @@ +# Unit test for the FEM module + +# *************************************************************************** +# * Copyright (c) 2015 - FreeCAD Developers * +# * Author: Przemo Firszt * +# * * +# * 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 * +# * * +# ***************************************************************************/ + +import Fem +from femtools import ccxtools +import femresult.resulttools as resulttools +import FreeCAD +import ObjectsFem +import femsolver.run +import tempfile +import unittest +import os +from .testtools import fcc_print +from .testtools import get_defmake_count +from .testtools import compare_inp_files +from .testtools import compare_files +from .testtools import compare_stats +from .testtools import force_unix_line_ends +from .testtools import collect_python_modules + + +mesh_name = 'Mesh' +stat_types = ["U1", "U2", "U3", "Uabs", "Sabs", "MaxPrin", "MidPrin", "MinPrin", "MaxShear", "Peeq", "Temp", "MFlow", "NPress"] + +home_path = FreeCAD.getHomePath() +temp_dir = tempfile.gettempdir() + '/FEM_unittests/' +if not os.path.exists(temp_dir): + os.makedirs(temp_dir) +test_file_dir = home_path + 'Mod/Fem/femtest/testfiles/ccx/' +test_file_dir_elmer = home_path + 'Mod/Fem/femtest/testfiles/elmer/' + +# define some locations fot the analysis tests +# since they are also used in the helper def which create results they should stay global for the module +static_base_name = 'cube_static' +static_analysis_dir = temp_dir + 'FEM_ccx_static/' +static_save_fc_file = static_analysis_dir + static_base_name + '.fcstd' +static_analysis_inp_file = test_file_dir + static_base_name + '.inp' +static_expected_values = test_file_dir + "cube_static_expected_values" + +frequency_base_name = 'cube_frequency' +frequency_analysis_dir = temp_dir + 'FEM_ccx_frequency/' +frequency_save_fc_file = frequency_analysis_dir + frequency_base_name + '.fcstd' +frequency_analysis_inp_file = test_file_dir + frequency_base_name + '.inp' +frequency_expected_values = test_file_dir + "cube_frequency_expected_values" + +thermomech_base_name = 'spine_thermomech' +thermomech_analysis_dir = temp_dir + 'FEM_ccx_thermomech/' +thermomech_save_fc_file = thermomech_analysis_dir + thermomech_base_name + '.fcstd' +thermomech_analysis_inp_file = test_file_dir + thermomech_base_name + '.inp' +thermomech_expected_values = test_file_dir + "spine_thermomech_expected_values" + +Flow1D_thermomech_base_name = 'Flow1D_thermomech' +Flow1D_thermomech_analysis_dir = temp_dir + 'FEM_ccx_Flow1D_thermomech/' +Flow1D_thermomech_save_fc_file = Flow1D_thermomech_analysis_dir + Flow1D_thermomech_base_name + '.fcstd' +Flow1D_thermomech_analysis_inp_file = test_file_dir + Flow1D_thermomech_base_name + '.inp' +Flow1D_thermomech_expected_values = test_file_dir + "Flow1D_thermomech_expected_values" + +solverframework_analysis_dir = temp_dir + 'FEM_solverframework/' +solverframework_save_fc_file = solverframework_analysis_dir + static_base_name + '.fcstd' + + +class SolverFrameWorkTest(unittest.TestCase): + + def setUp(self): + try: + FreeCAD.setActiveDocument("FemTest") + except: + FreeCAD.newDocument("FemTest") + finally: + FreeCAD.setActiveDocument("FemTest") + self.active_doc = FreeCAD.ActiveDocument + + def test_solver_framework(self): + fcc_print('--------------- Start of FEM tests solver frame work ---------------') + box = self.active_doc.addObject("Part::Box", "Box") + fcc_print('Checking FEM new analysis...') + analysis = ObjectsFem.makeAnalysis(self.active_doc, 'Analysis') + self.assertTrue(analysis, "FemTest of new analysis failed") + + fcc_print('Checking FEM new material...') + material_object = ObjectsFem.makeMaterialSolid(self.active_doc, 'MechanicalMaterial') + mat = material_object.Material + mat['Name'] = "Steel-Generic" + mat['YoungsModulus'] = "200000 MPa" + mat['PoissonRatio'] = "0.30" + mat['Density'] = "7900 kg/m^3" + material_object.Material = mat + self.assertTrue(material_object, "FemTest of new material failed") + analysis.addObject(material_object) + + fcc_print('Checking FEM new fixed constraint...') + fixed_constraint = self.active_doc.addObject("Fem::ConstraintFixed", "FemConstraintFixed") + fixed_constraint.References = [(box, "Face1")] + self.assertTrue(fixed_constraint, "FemTest of new fixed constraint failed") + analysis.addObject(fixed_constraint) + + fcc_print('Checking FEM new force constraint...') + force_constraint = self.active_doc.addObject("Fem::ConstraintForce", "FemConstraintForce") + force_constraint.References = [(box, "Face6")] + force_constraint.Force = 40000.0 + force_constraint.Direction = (box, ["Edge5"]) + self.active_doc.recompute() + force_constraint.Reversed = True + self.active_doc.recompute() + self.assertTrue(force_constraint, "FemTest of new force constraint failed") + analysis.addObject(force_constraint) + + fcc_print('Checking FEM new pressure constraint...') + pressure_constraint = self.active_doc.addObject("Fem::ConstraintPressure", "FemConstraintPressure") + pressure_constraint.References = [(box, "Face2")] + pressure_constraint.Pressure = 1000.0 + pressure_constraint.Reversed = False + self.assertTrue(pressure_constraint, "FemTest of new pressure constraint failed") + analysis.addObject(pressure_constraint) + + fcc_print('Checking FEM new mesh...') + from .testfiles.ccx.cube_mesh import create_nodes_cube + from .testfiles.ccx.cube_mesh import create_elements_cube + mesh = Fem.FemMesh() + ret = create_nodes_cube(mesh) + self.assertTrue(ret, "Import of mesh nodes failed") + ret = create_elements_cube(mesh) + self.assertTrue(ret, "Import of mesh volumes failed") + mesh_object = self.active_doc.addObject('Fem::FemMeshObject', mesh_name) + mesh_object.FemMesh = mesh + self.assertTrue(mesh, "FemTest of new mesh failed") + analysis.addObject(mesh_object) + + self.active_doc.recompute() + + # solver frame work ccx solver + fcc_print('Checking FEM solver for solver frame work...') + solver_ccx2_object = ObjectsFem.makeSolverCalculix(self.active_doc, 'SolverCalculiX') + solver_ccx2_object.AnalysisType = 'static' + solver_ccx2_object.GeometricalNonlinearity = 'linear' + solver_ccx2_object.ThermoMechSteadyState = False + solver_ccx2_object.MatrixSolverType = 'default' + solver_ccx2_object.IterationsControlParameterTimeUse = False + solver_ccx2_object.EigenmodesCount = 10 + solver_ccx2_object.EigenmodeHighLimit = 1000000.0 + solver_ccx2_object.EigenmodeLowLimit = 0.0 + self.assertTrue(solver_ccx2_object, "FemTest of new ccx solver failed") + analysis.addObject(solver_ccx2_object) + + fcc_print('Checking inpfile writing for solverframework_save_fc_file frame work...') + if not os.path.exists(solverframework_analysis_dir): # solver frameworkd does explicit not create a non existing directory + os.makedirs(solverframework_analysis_dir) + + fcc_print('machine_ccx') + machine_ccx = solver_ccx2_object.Proxy.createMachine(solver_ccx2_object, solverframework_analysis_dir) + fcc_print('Machine testmode: ' + str(machine_ccx.testmode)) + machine_ccx.target = femsolver.run.PREPARE + machine_ccx.start() + machine_ccx.join() # wait for the machine to finish. + fcc_print('Comparing {} to {}/{}.inp'.format(static_analysis_inp_file, solverframework_analysis_dir, mesh_name)) + ret = compare_inp_files(static_analysis_inp_file, solverframework_analysis_dir + mesh_name + '.inp') + self.assertFalse(ret, "ccxtools write_inp_file test failed.\n{}".format(ret)) + + # use solver frame work elmer solver + solver_elmer_object = ObjectsFem.makeSolverElmer(self.active_doc, 'SolverElmer') + self.assertTrue(solver_elmer_object, "FemTest of elmer solver failed") + analysis.addObject(solver_elmer_object) + solver_elmer_eqobj = ObjectsFem.makeEquationElasticity(self.active_doc, solver_elmer_object) + self.assertTrue(solver_elmer_eqobj, "FemTest of elmer elasticity equation failed") + + # set ThermalExpansionCoefficient, current elmer seems to need it even on simple elasticity analysis + mat = material_object.Material + mat['ThermalExpansionCoefficient'] = "0 um/m/K" # FIXME elmer elasticity needs the dictionary key, otherwise it fails + material_object.Material = mat + + mesh_gmsh = ObjectsFem.makeMeshGmsh(self.active_doc) + mesh_gmsh.CharacteristicLengthMin = "9 mm" + mesh_gmsh.FemMesh = mesh_object.FemMesh # elmer needs a GMHS mesh object, FIXME error message on Python solver run + mesh_gmsh.Part = box + analysis.addObject(mesh_gmsh) + self.active_doc.removeObject(mesh_object.Name) + + fcc_print('machine_elmer') + machine_elmer = solver_elmer_object.Proxy.createMachine(solver_elmer_object, solverframework_analysis_dir, True) + fcc_print('Machine testmode: ' + str(machine_elmer.testmode)) + machine_elmer.target = femsolver.run.PREPARE + machine_elmer.start() + machine_elmer.join() # wait for the machine to finish. + + ''' + fcc_print('Test writing STARTINFO file') + fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'ELMERSOLVER_STARTINFO', solverframework_analysis_dir + 'ELMERSOLVER_STARTINFO')) + ret = compare_files(test_file_dir_elmer + 'ELMERSOLVER_STARTINFO', solverframework_analysis_dir + 'ELMERSOLVER_STARTINFO') + self.assertFalse(ret, "STARTINFO write file test failed.\n{}".format(ret)) + + fcc_print('Test writing case file') + fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'case.sif', solverframework_analysis_dir + 'case.sif')) + ret = compare_files(test_file_dir_elmer + 'case.sif', solverframework_analysis_dir + 'case.sif') + self.assertFalse(ret, "case write file test failed.\n{}".format(ret)) + + fcc_print('Test writing GMSH geo file') + fcc_print('Comparing {} to {}'.format(test_file_dir_elmer + 'group_mesh.geo', solverframework_analysis_dir + 'group_mesh.geo')) + ret = compare_files(test_file_dir_elmer + 'group_mesh.geo', solverframework_analysis_dir + 'group_mesh.geo') + self.assertFalse(ret, "GMSH geo write file test failed.\n{}".format(ret)) + ''' + + fcc_print('Save FreeCAD file for static2 analysis to {}...'.format(solverframework_save_fc_file)) + self.active_doc.saveAs(solverframework_save_fc_file) + fcc_print('--------------- End of FEM tests solver frame work ---------------') + + def tearDown(self): + FreeCAD.closeDocument("FemTest") + pass