Merge pull request #2549 from berndhahnebach/bhbdev230

FEM: more GSoC stuff
This commit is contained in:
Bernd Hahnebach
2019-09-23 21:17:59 +02:00
committed by GitHub
75 changed files with 786 additions and 497 deletions

View File

@@ -34,15 +34,15 @@ namespace Fem {
* @brief Container of objects relevant to one simulation.
*
* @details
* A Analysis contains all objects nessesary for a complete specification
* A Analysis contains all objects necessary for a complete specification
* of a simulation. After computing it also contains the result of the
* simulation. The Analysis object is just a container. It is not reponsible
* simulation. The Analysis object is just a container. It is not responsible
* for anything else like executing the simulation.
*
* The Analysis class is essentially a App::DocumentObjectGroup. It handles
* all the container stuff. The difference is that the Analysis document
* object uses a different ViewProvider, has a Uid property and does some
* compability handling via handleChangedPropertyName.
* compatibility handling via handleChangedPropertyName.
*
* This implies that it is not checked which objects are put into the
* Analsis object. Every document object of FreeCAD can be part of a
@@ -73,7 +73,7 @@ public:
protected:
/**
* @brief Retain compability with old "Member" property.
* @brief Retain compatibility with old "Member" property.
*
* @details
* In an older version of FreeCAD FemAnalysis handles it's member itself

View File

@@ -40,7 +40,7 @@ namespace Fem {
* used to specify a simulation are children of this class. The base class
* essentially does two things: Most importantely it has a property @ref
* Constraint::References which is a list of all sub objects the constraint
* applys to. Defining it in the base class exposes a common interface to code
* applies to. Defining it in the base class exposes a common interface to code
* using different constraints.
*
* The second purpose of @ref Constraint is to support the redering to the
@@ -146,7 +146,7 @@ public:
* This is just used to make code more understandable. Other versions
* (overloads) of this function do useful calculations based on faces or
* edges. Used by @ref getPoints if no useful shape information is
* avaliable.
* available.
*
* @return always the integer 1
*/
@@ -167,7 +167,7 @@ protected:
* @brief Triggers @ref onChanged to update View Provider.
*
* @note
* This should not be nessesary and is properly a bug in the View Provider
* This should not be necessary and is properly a bug in the View Provider
* of FemConstraint.
*/
virtual void onDocumentRestored();
@@ -203,7 +203,7 @@ protected:
*
* @return
* If the calculation of points, normals and scale was successful it
* returns true. If an error occured and the data couldn't be extracted
* returns true. If an error occurred and the data couldn't be extracted
* properly false is returned.
*/
bool getPoints(
@@ -215,8 +215,8 @@ protected:
* @brief Extract properties of cylindrical face.
*
* @note
* This method is very specific and doesn't requre access to member
* variables. It should be rewritten at a different palce.
* This method is very specific and doesn't require access to member
* variables. It should be rewritten at a different place.
*/
bool getCylinder(
double& radius, double& height,
@@ -226,8 +226,8 @@ protected:
* @brief Calculate point of cylidrical face where to render widget.
*
* @note
* This method is very specific and doesn't requre access to member
* variables. It should be rewritten at a different palce.
* This method is very specific and doesn't require access to member
* variables. It should be rewritten at a different place.
*/
Base::Vector3d getBasePoint(const Base::Vector3d& base, const Base::Vector3d& axis,
const App::PropertyLinkSub &location, const double& dist);
@@ -235,8 +235,8 @@ protected:
* @brief Get normal vector of point calculated by @ref getBasePoint.
*
* @note
* This method is very specific and doesn't requre access to member
* variables. It should be rewritten at a different palce.
* This method is very specific and doesn't require access to member
* variables. It should be rewritten at a different place.
*/
const Base::Vector3d getDirection(const App::PropertyLinkSub &direction);
};

View File

@@ -1179,7 +1179,7 @@ void FemMesh::readAbaqus(const std::string &FileName)
/*
Python command to read Abaqus inp mesh file from test suite:
from feminout.importInpMesh import read as read_inp
femmesh = read_inp(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/testfiles/mesh/tetra10_mesh.inp')
femmesh = read_inp(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/mesh/tetra10_mesh.inp')
*/
PyObject* module = PyImport_ImportModule("feminout.importInpMesh");
@@ -1215,7 +1215,7 @@ void FemMesh::readZ88(const std::string &FileName)
/*
Python command to read Z88 mesh file from test suite:
from feminout.importZ88Mesh import read as read_z88
femmesh = read_z88(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/testfiles/mesh/tetra10_mesh.z88')
femmesh = read_z88(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/mesh/tetra10_mesh.z88')
*/
PyObject* module = PyImport_ImportModule("feminout.importZ88Mesh");

View File

@@ -130,66 +130,70 @@ SET(FemSolverZ88_SRCS
SET(FemTests_SRCS
femtest/__init__.py
femtest/testccxtools.py
femtest/testcommon.py
femtest/testfemimport.py
femtest/testmaterial.py
femtest/testmesh.py
femtest/testobject.py
femtest/testresult.py
femtest/testsolverframework.py
femtest/utilstest.py
)
SET(FemTestsApp_SRCS
femtest/app/__init__.py
femtest/app/support_utils.py
femtest/app/test_ccxtools.py
femtest/app/test_common.py
femtest/app/test_femimport.py
femtest/app/test_material.py
femtest/app/test_mesh.py
femtest/app/test_object.py
femtest/app/test_result.py
femtest/app/test_solverframework.py
)
SET(FemTestsFiles_SRCS
femtest/testfiles/__init__.py
femtest/data/__init__.py
)
SET(FemTestsCcx_SRCS
femtest/testfiles/ccx/__init__.py
femtest/testfiles/ccx/cube_mesh.py
femtest/testfiles/ccx/cube_frequency.inp
femtest/testfiles/ccx/cube_frequency.dat
femtest/testfiles/ccx/cube_frequency.frd
femtest/testfiles/ccx/cube_frequency_expected_values
femtest/testfiles/ccx/cube_frequency.FCStd
femtest/testfiles/ccx/cube_static.inp
femtest/testfiles/ccx/cube_static.dat
femtest/testfiles/ccx/cube_static.frd
femtest/testfiles/ccx/cube_static_expected_values
femtest/testfiles/ccx/cube_static.FCStd
femtest/testfiles/ccx/cube.FCStd
femtest/testfiles/ccx/multimat.inp
femtest/testfiles/ccx/multimat_mesh.py
femtest/testfiles/ccx/spine_mesh.py
femtest/testfiles/ccx/spine_thermomech.inp
femtest/testfiles/ccx/spine_thermomech.dat
femtest/testfiles/ccx/spine_thermomech.frd
femtest/testfiles/ccx/spine_thermomech_expected_values
femtest/testfiles/ccx/spine_thermomech.FCStd
femtest/testfiles/ccx/Flow1D_mesh.py
femtest/testfiles/ccx/Flow1D_thermomech.inp
femtest/testfiles/ccx/Flow1D_thermomech.dat
femtest/testfiles/ccx/Flow1D_thermomech.frd
femtest/testfiles/ccx/Flow1D_thermomech_expected_values
femtest/testfiles/ccx/Flow1D_thermomech_inout_nodes.txt
femtest/testfiles/ccx/Flow1D_thermomech.FCStd
femtest/data/ccx/__init__.py
femtest/data/ccx/cube_mesh.py
femtest/data/ccx/cube_frequency.inp
femtest/data/ccx/cube_frequency.dat
femtest/data/ccx/cube_frequency.frd
femtest/data/ccx/cube_frequency_expected_values
femtest/data/ccx/cube_frequency.FCStd
femtest/data/ccx/cube_static.inp
femtest/data/ccx/cube_static.dat
femtest/data/ccx/cube_static.frd
femtest/data/ccx/cube_static_expected_values
femtest/data/ccx/cube_static.FCStd
femtest/data/ccx/cube.FCStd
femtest/data/ccx/multimat.inp
femtest/data/ccx/multimat_mesh.py
femtest/data/ccx/spine_mesh.py
femtest/data/ccx/spine_thermomech.inp
femtest/data/ccx/spine_thermomech.dat
femtest/data/ccx/spine_thermomech.frd
femtest/data/ccx/spine_thermomech_expected_values
femtest/data/ccx/spine_thermomech.FCStd
femtest/data/ccx/Flow1D_mesh.py
femtest/data/ccx/Flow1D_thermomech.inp
femtest/data/ccx/Flow1D_thermomech.dat
femtest/data/ccx/Flow1D_thermomech.frd
femtest/data/ccx/Flow1D_thermomech_expected_values
femtest/data/ccx/Flow1D_thermomech_inout_nodes.txt
femtest/data/ccx/Flow1D_thermomech.FCStd
)
SET(FemTestsElmer_SRCS
femtest/testfiles/elmer/__init__.py
femtest/testfiles/elmer/case.sif
femtest/testfiles/elmer/group_mesh.geo
femtest/testfiles/elmer/ELMERSOLVER_STARTINFO
femtest/data/elmer/__init__.py
femtest/data/elmer/case.sif
femtest/data/elmer/group_mesh.geo
femtest/data/elmer/ELMERSOLVER_STARTINFO
)
SET(FemTestsMesh_SRCS
femtest/testfiles/mesh/__init__.py
femtest/testfiles/mesh/tetra10_mesh.inp
femtest/testfiles/mesh/tetra10_mesh.unv
femtest/testfiles/mesh/tetra10_mesh.vtk
femtest/testfiles/mesh/tetra10_mesh.yml
femtest/testfiles/mesh/tetra10_mesh.z88
femtest/data/mesh/__init__.py
femtest/data/mesh/tetra10_mesh.inp
femtest/data/mesh/tetra10_mesh.unv
femtest/data/mesh/tetra10_mesh.vtk
femtest/data/mesh/tetra10_mesh.yml
femtest/data/mesh/tetra10_mesh.z88
)
SET(FemTools_SRCS
@@ -237,6 +241,7 @@ SET(FemAllScripts
${FemSolverFenics_SRCS}
${FemSolverZ88_SRCS}
${FemTests_SRCS}
${FemTestsApp_SRCS}
${FemTestsFiles_SRCS}
${FemTestsCcx_SRCS}
${FemTestsElmer_SRCS}
@@ -268,10 +273,11 @@ INSTALL(FILES ${FemSolverElmerEquations_SRCS} DESTINATION Mod/Fem/femsolver/elme
INSTALL(FILES ${FemSolverFenics_SRCS} DESTINATION Mod/Fem/femsolver/fenics)
INSTALL(FILES ${FemSolverZ88_SRCS} DESTINATION Mod/Fem/femsolver/z88)
INSTALL(FILES ${FemTests_SRCS} DESTINATION Mod/Fem/femtest)
INSTALL(FILES ${FemTestsFiles_SRCS} DESTINATION Mod/Fem/femtest/testfiles)
INSTALL(FILES ${FemTestsCcx_SRCS} DESTINATION Mod/Fem/femtest/testfiles/ccx)
INSTALL(FILES ${FemTestsElmer_SRCS} DESTINATION Mod/Fem/femtest/testfiles/elmer)
INSTALL(FILES ${FemTestsMesh_SRCS} DESTINATION Mod/Fem/femtest/testfiles/mesh)
INSTALL(FILES ${FemTestsApp_SRCS} DESTINATION Mod/Fem/femtest/app)
INSTALL(FILES ${FemTestsFiles_SRCS} DESTINATION Mod/Fem/femtest/data)
INSTALL(FILES ${FemTestsCcx_SRCS} DESTINATION Mod/Fem/femtest/data/ccx)
INSTALL(FILES ${FemTestsElmer_SRCS} DESTINATION Mod/Fem/femtest/data/elmer)
INSTALL(FILES ${FemTestsMesh_SRCS} DESTINATION Mod/Fem/femtest/data/mesh)
INSTALL(FILES ${FemTools_SRCS} DESTINATION Mod/Fem/femtools)
INSTALL(FILES ${FemObjectsScripts_SRCS} DESTINATION Mod/Fem/femobjects)

View File

@@ -26,16 +26,16 @@
# Unit test for the FEM module
# to get the right order import as is used
from femtest.testfemimport import TestFemImport as FemTest01
from femtest.testcommon import TestFemCommon as FemTest02
from femtest.testobject import TestObjectCreate as FemTest03
from femtest.testobject import TestObjectType as FemTest04
from femtest.testmaterial import TestMaterialUnits as FemTest05
from femtest.testmesh import TestMeshCommon as FemTest06
from femtest.testmesh import TestMeshEleTetra10 as FemTest07
from femtest.testresult import TestResult as FemTest08
from femtest.testccxtools import TestCcxTools as FemTest09
from femtest.testsolverframework import TestSolverFrameWork as FemTest10
from femtest.app.test_femimport import TestFemImport as FemTest01
from femtest.app.test_common import TestFemCommon as FemTest02
from femtest.app.test_object import TestObjectCreate as FemTest03
from femtest.app.test_object import TestObjectType as FemTest04
from femtest.app.test_material import TestMaterialUnits as FemTest05
from femtest.app.test_mesh import TestMeshCommon as FemTest06
from femtest.app.test_mesh import TestMeshEleTetra10 as FemTest07
from femtest.app.test_result import TestResult as FemTest08
from femtest.app.test_ccxtools import TestCcxTools as FemTest09
from femtest.app.test_solverframework import TestSolverFrameWork as FemTest10
# dummy usage to get flake8 and lgtm quiet
False if FemTest01.__name__ else True
@@ -93,22 +93,22 @@ unittest.TextTestRunner().run(alltest)
./bin/FreeCADCmd --run-test "femtest.testfemimport"
# other module
./bin/FreeCAD --run-test "femtest.testfemimport"
./bin/FreeCAD --run-test "femtest.testccxtools"
./bin/FreeCAD --run-test "femtest.testcommon"
./bin/FreeCAD --run-test "femtest.testmaterial"
./bin/FreeCAD --run-test "femtest.testmesh"
./bin/FreeCAD --run-test "femtest.testobject"
./bin/FreeCAD --run-test "femtest.testresult"
./bin/FreeCAD --run-test "femtest.testsolverframework"
./bin/FreeCADCmd --run-test "femtest.testfemimport"
./bin/FreeCADCmd --run-test "femtest.testccxtools"
./bin/FreeCADCmd --run-test "femtest.testcommon"
./bin/FreeCADCmd --run-test "femtest.testmaterial"
./bin/FreeCADCmd --run-test "femtest.testmesh"
./bin/FreeCADCmd --run-test "femtest.testobject"
./bin/FreeCADCmd --run-test "femtest.testresult"
./bin/FreeCADCmd --run-test "femtest.testsolverframework"
./bin/FreeCAD --run-test "femtest.app.test_femimport"
./bin/FreeCAD --run-test "femtest.app.test_ccxtools"
./bin/FreeCAD --run-test "femtest.app.test_common"
./bin/FreeCAD --run-test "femtest.app.test_material"
./bin/FreeCAD --run-test "femtest.app.test_mesh"
./bin/FreeCAD --run-test "femtest.app.test_object"
./bin/FreeCAD --run-test "femtest.app.test_result"
./bin/FreeCAD --run-test "femtest.app.test_solverframework"
./bin/FreeCADCmd --run-test "femtest.app.test_femimport"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools"
./bin/FreeCADCmd --run-test "femtest.app.test_common"
./bin/FreeCADCmd --run-test "femtest.app.test_material"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh"
./bin/FreeCADCmd --run-test "femtest.app.test_object"
./bin/FreeCADCmd --run-test "femtest.app.test_result"
./bin/FreeCADCmd --run-test "femtest.app.test_solverframework"
# class
./bin/FreeCAD --run-test "femtest.testcommon.TestFemCommon"
@@ -122,38 +122,38 @@ unittest.TextTestRunner().run(alltest)
from femtest.utilstest import get_fem_test_defs as gf
gf()
./bin/FreeCADCmd --run-test "femtest.testfemimport.TestObjectExistance.test_objects_existance"
./bin/FreeCADCmd --run-test "femtest.testccxtools.TestCcxTools.test_1_static_analysis"
./bin/FreeCADCmd --run-test "femtest.testccxtools.TestCcxTools.test_2_static_multiple_material"
./bin/FreeCADCmd --run-test "femtest.testccxtools.TestCcxTools.test_3_freq_analysis"
./bin/FreeCADCmd --run-test "femtest.testccxtools.TestCcxTools.test_4_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.testccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.testcommon.TestFemCommon.test_adding_refshaps"
./bin/FreeCADCmd --run-test "femtest.testcommon.TestFemCommon.test_pyimport_all_FEM_modules"
./bin/FreeCADCmd --run-test "femtest.testmaterial.TestMaterialUnits.test_known_quantity_units"
./bin/FreeCADCmd --run-test "femtest.testmaterial.TestMaterialUnits.test_material_card_quantities"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshCommon.test_mesh_seg2_python"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshCommon.test_mesh_seg3_python"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshCommon.test_unv_save_load"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshCommon.test_writeAbaqus_precision"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_create"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_inp"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_unv"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_vkt"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_yml"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_z88"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectCreate.test_femobjects_make"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectType.test_femobjects_type"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectType.test_femobjects_isoftype"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectType.test_femobjects_derivedfromfem"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectType.test_femobjects_derivedfromstd"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_read_frd_massflow_networkpressure"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_stress_von_mises"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_stress_principal_std"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_stress_principal_reinforced"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_rho"
./bin/FreeCADCmd --run-test "femtest.testresult.TestResult.test_disp_abs"
./bin/FreeCADCmd --run-test "femtest.testsolverframework.TestSolverFrameWork.test_solver_framework"
./bin/FreeCADCmd --run-test "femtest.app.test_femimport.TestObjectExistance.test_objects_existance"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_1_static_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_2_static_multiple_material"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_3_freq_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_4_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_common.TestFemCommon.test_adding_refshaps"
./bin/FreeCADCmd --run-test "femtest.app.test_common.TestFemCommon.test_pyimport_all_FEM_modules"
./bin/FreeCADCmd --run-test "femtest.app.test_material.TestMaterialUnits.test_known_quantity_units"
./bin/FreeCADCmd --run-test "femtest.app.test_material.TestMaterialUnits.test_material_card_quantities"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshCommon.test_mesh_seg2_python"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshCommon.test_mesh_seg3_python"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshCommon.test_unv_save_load"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshCommon.test_writeAbaqus_precision"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_create"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_inp"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_unv"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_vkt"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_yml"
./bin/FreeCADCmd --run-test "femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_z88"
./bin/FreeCADCmd --run-test "femtest.app.test_object.TestObjectCreate.test_femobjects_make"
./bin/FreeCADCmd --run-test "femtest.app.test_object.TestObjectType.test_femobjects_type"
./bin/FreeCADCmd --run-test "femtest.app.test_object.TestObjectType.test_femobjects_isoftype"
./bin/FreeCADCmd --run-test "femtest.app.test_object.TestObjectType.test_femobjects_derivedfromfem"
./bin/FreeCADCmd --run-test "femtest.app.test_object.TestObjectType.test_femobjects_derivedfromstd"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_read_frd_massflow_networkpressure"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_stress_von_mises"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_stress_principal_std"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_stress_principal_reinforced"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_rho"
./bin/FreeCADCmd --run-test "femtest.app.test_result.TestResult.test_disp_abs"
./bin/FreeCADCmd --run-test "femtest.app.test_solverframework.TestSolverFrameWork.test_solver_framework"
# to get all command to start FreeCAD from build dir on Linux
@@ -162,109 +162,108 @@ from femtest.utilstest import get_fem_test_defs as gf
gf("in")
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testccxtools.TestCcxTools.test_1_static_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_1_static_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testccxtools.TestCcxTools.test_2_static_multiple_material"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_2_static_multiple_material"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testccxtools.TestCcxTools.test_3_freq_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_3_freq_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testccxtools.TestCcxTools.test_4_thermomech_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_4_thermomech_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testcommon.TestFemCommon.test_adding_refshaps"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_common.TestFemCommon.test_adding_refshaps"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testcommon.TestFemCommon.test_pyimport_all_FEM_modules"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_common.TestFemCommon.test_pyimport_all_FEM_modules"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmaterial.TestMaterialUnits.test_known_quantity_units"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_material.TestMaterialUnits.test_known_quantity_units"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmaterial.TestMaterialUnits.test_material_card_quantities"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_material.TestMaterialUnits.test_material_card_quantities"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshCommon.test_mesh_seg2_python"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshCommon.test_mesh_seg2_python"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshCommon.test_mesh_seg3_python"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshCommon.test_mesh_seg3_python"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshCommon.test_unv_save_load"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshCommon.test_unv_save_load"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshCommon.test_writeAbaqus_precision"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshCommon.test_writeAbaqus_precision"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_create"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_create"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_inp"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_inp"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_unv"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_unv"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_vkt"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_vkt"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_yml"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_yml"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_z88"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_mesh.TestMeshEleTetra10.test_tetra10_z88"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testobject.TestObjectCreate.test_femobjects_make"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_object.TestObjectCreate.test_femobjects_make"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testobject.TestObjectType.test_femobjects_type"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_object.TestObjectType.test_femobjects_type"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testobject.TestObjectType.test_femobjects_isoftype"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_object.TestObjectType.test_femobjects_isoftype"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testobject.TestObjectType.test_femobjects_derivedfromfem"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_object.TestObjectType.test_femobjects_derivedfromfem"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testobject.TestObjectType.test_femobjects_derivedfromstd"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_object.TestObjectType.test_femobjects_derivedfromstd"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_read_frd_massflow_networkpressure"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_read_frd_massflow_networkpressure"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_stress_von_mises"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_stress_von_mises"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_stress_principal_std"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_stress_principal_std"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_stress_principal_reinforced"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_stress_principal_reinforced"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_rho"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_rho"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testresult.TestResult.test_disp_abs"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_result.TestResult.test_disp_abs"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testsolverframework.TestSolverFrameWork.test_solver_framework"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_solverframework.TestSolverFrameWork.test_solver_framework"))
# open files from FEM test suite source code
# be careful on updating these files, they contain the original results!
# TODO update files, because some of them have non-existing FEM object classes
app_home = FreeCAD.ConfigGet("AppHomePath")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/cube.FCStd")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/cube_frequency.FCStd")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/cube_static.FCStd")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/Flow1D_thermomech.FCStd")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/multimat.FCStd")
doc = FreeCAD.open(app_home + "Mod/Fem/femtest/testfiles/ccx/spine_thermomech.FCStd")
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/cube.FCStd')
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/cube_frequency.FCStd')
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/cube_static.FCStd')
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/Flow1D_thermomech.FCStd')
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/multimat.FCStd')
doc = FreeCAD.open(FreeCAD.ConfigGet("AppHomePath") + 'Mod/Fem/femtest/data/ccx/spine_thermomech.FCStd')
# open files generated from test suite
import femtest.utilstest as ut

View File

@@ -32,18 +32,23 @@ __url__ = "http://www.freecadweb.org"
# Make mesh of pn junction in TetGen format
import FreeCAD
from FreeCAD import Console
import Mesh
App = FreeCAD # shortcut
if FreeCAD.GuiUp:
import FreeCADGui
Gui = FreeCADGui # shortcut
## \addtogroup FEM
# @{
def exportMeshToTetGenPoly(meshToExport, filePath, beVerbose=1):
"""Export mesh to TetGen *.poly file format"""
# ********** Part 1 - write node list to output file
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\nExport of mesh to TetGen file ...")
Console.PrintMessage("\nExport of mesh to TetGen file ...")
(allVertices, allFacets) = meshToExport.Topology
f = open(filePath, "w")
f.write("# This file was generated from FreeCAD geometry\n")
@@ -94,7 +99,7 @@ def exportMeshToTetGenPoly(meshToExport, filePath, beVerbose=1):
EdgeKeys = EdgeFacets.keys()
# disconnectedEdges = len(EdgeKeys)
if beVerbose == 1:
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"\nBoundaryMarker:" + repr(BoundaryMarker) + " " + repr(len(EdgeFacets))
)
searchForPair = 1
@@ -146,7 +151,7 @@ def exportMeshToTetGenPoly(meshToExport, filePath, beVerbose=1):
searchForPair = 0
# End of main loop
if beVerbose == 1:
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"\nNew BoundaryMarker:" + repr(BoundaryMarker) + " " + repr(len(EdgeFacets))
)
@@ -185,7 +190,7 @@ def createMesh():
# ======================== Script beginning... ========================
beVerbose = 1
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\n\n\n\n\n\n\n\nScript starts...")
Console.PrintMessage("\n\n\n\n\n\n\n\nScript starts...")
# Geometry definition
# Define objects names
PyDocumentName = "pnJunction"
@@ -199,7 +204,7 @@ def createMesh():
# Init objects
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\nInit Objects...")
Console.PrintMessage("\nInit Objects...")
# closeDocument after restart of macro. Needs any ActiveDocument.
# App.closeDocument(App.ActiveDocument.Label)
AppPyDoc = App.newDocument(PyDocumentName)
@@ -235,13 +240,13 @@ def createMesh():
]
if beVerbose == 1:
if len(BoxList) != len(BoxMeshList):
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"\n ERROR! Input len() of BoxList and BoxMeshList is not the same! "
)
# Set sizes in nanometers
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\nSet sizes...")
Console.PrintMessage("\nSet sizes...")
tessellationTollerance = 0.05
ModelWidth = 300
BulkHeight = 300
@@ -303,7 +308,7 @@ def createMesh():
# Unite
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\nFuse objects...")
Console.PrintMessage("\nFuse objects...")
fuseShape = BoxList[0].Shape
for index in range(1, len(BoxList), 1):
fuseShape = fuseShape.fuse(BoxList[index].Shape)
@@ -342,6 +347,6 @@ def createMesh():
Gui.SendMsgToActiveView("ViewFit")
if beVerbose == 1:
FreeCAD.Console.PrintMessage("\nScript finished without errors.")
Console.PrintMessage("\nScript finished without errors.")
## @}

View File

@@ -29,6 +29,7 @@ __url__ = "http://www.freecadweb.org"
# \brief FreeCAD Calculix DAT reader for FEM workbench
import FreeCAD
from FreeCAD import Console
import os
@@ -71,7 +72,6 @@ def import_dat(
Analysis=None
):
r = readResult(filename)
# print("Results {}".format(r))
return r
@@ -79,7 +79,7 @@ def import_dat(
def readResult(
dat_input
):
FreeCAD.Console.PrintMessage("Read ccx results from dat file: {}\n".format(dat_input))
Console.PrintMessage("Read ccx results from dat file: {}\n".format(dat_input))
dat_file = pyopen(dat_input, "r")
eigenvalue_output_section_found = False
mode_reading = False

View File

@@ -31,6 +31,7 @@ __url__ = "http://www.freecadweb.org"
# \brief FreeCAD Calculix FRD Reader for FEM workbench
import FreeCAD
from FreeCAD import Console
import os
@@ -88,7 +89,7 @@ def importFrd(
nodenumbers_for_compacted_mesh = []
number_of_increments = len(m["Results"])
FreeCAD.Console.PrintLog(
Console.PrintLog(
"Increments: " + str(number_of_increments) + "\n"
)
if len(m["Results"]) > 0:
@@ -175,7 +176,7 @@ def importFrd(
"or if CalculiX returned no results because "
"of nonpositive jacobian determinant in at least one element.\n"
)
FreeCAD.Console.PrintMessage(error_message)
Console.PrintMessage(error_message)
if analysis:
analysis_object.addObject(result_mesh_object)
@@ -186,7 +187,7 @@ def importFrd(
FreeCAD.ActiveDocument.recompute()
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Problem on frd file import. No nodes found in frd file.\n"
)
return res_obj
@@ -197,14 +198,14 @@ def importFrd(
def read_frd_result(
frd_input
):
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Read ccx results from frd file: {}\n"
.format(frd_input)
)
inout_nodes = []
inout_nodes_file = frd_input.rsplit(".", 1)[0] + "_inout_nodes.txt"
if os.path.exists(inout_nodes_file):
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Read special 1DFlow nodes data form: {}\n".format(inout_nodes_file)
)
f = pyopen(inout_nodes_file, "r")
@@ -213,7 +214,7 @@ def read_frd_result(
a = line.split(",")
inout_nodes.append(a)
f.close()
FreeCAD.Console.PrintMessage("{}\n".format(inout_nodes))
Console.PrintMessage("{}\n".format(inout_nodes))
frd_file = pyopen(frd_input, "r")
nodes = {}
elements_hexa8 = {}
@@ -370,7 +371,6 @@ def read_frd_result(
nd8, nd5, nd6, nd7, nd4, nd1, nd2, nd3, nd20, nd17,
nd18, nd19, nd12, nd9, nd10, nd11, nd16, nd13, nd14, nd15
)
# print(elements_hexa20[elem])
elif elemType == 5 and input_continues is False:
# first line
# C3D15 Calculix --> penta15 FreeCAD
@@ -719,11 +719,11 @@ def read_frd_result(
if not inout_nodes:
if results:
if "mflow" in results[0] or "npressure" in results[0]:
FreeCAD.Console.PrintError(
Console.PrintError(
"We have mflow or npressure, but no inout_nodes file.\n"
)
if not nodes:
FreeCAD.Console.PrintError("FEM: No nodes found in Frd file.\n")
Console.PrintError("FEM: No nodes found in Frd file.\n")
return {
"Nodes": nodes,

View File

@@ -31,6 +31,7 @@ __url__ = "http://www.freecadweb.org"
import os
import FreeCAD
from FreeCAD import Console
from . import importToolsFem
from . import readFenicsXML
from . import writeFenicsXML
@@ -122,7 +123,7 @@ if FreeCAD.GuiUp:
default_value = int(self.form.tableGroups.item(r, 3).text())
marked_value = int(self.form.tableGroups.item(r, 4).text())
except ValueError:
FreeCAD.Console.PrintError(
Console.PrintError(
"ERROR: value conversion failed "
"in table to dict: assuming 0 for default, "
"1 for marked.\n"
@@ -165,22 +166,22 @@ def export(objectslist, fileString, group_values_dict_nogui=None):
of (marked_value (default=1), default_value (default=0))
"""
if len(objectslist) != 1:
FreeCAD.Console.PrintError(
Console.PrintError(
"This exporter can only export one object.\n")
return
obj = objectslist[0]
if not obj.isDerivedFrom("Fem::FemMeshObject"):
FreeCAD.Console.PrintError("No FEM mesh object selected.\n")
Console.PrintError("No FEM mesh object selected.\n")
return
if fileString != "":
fileName, fileExtension = os.path.splitext(fileString)
if fileExtension.lower() == ".xml":
FreeCAD.Console.PrintWarning(
Console.PrintWarning(
"XML is not designed to save higher order elements.\n")
FreeCAD.Console.PrintWarning(
Console.PrintWarning(
"Reducing order for second order mesh.\n")
FreeCAD.Console.PrintWarning("Tri6 -> Tri3, Tet10 -> Tet4, etc.\n")
Console.PrintWarning("Tri6 -> Tri3, Tet10 -> Tet4, etc.\n")
writeFenicsXML.write_fenics_mesh_xml(obj, fileString)
elif fileExtension.lower() == ".xdmf":
mesh_groups = importToolsFem.get_FemMeshObjectMeshGroups(obj)

View File

@@ -30,6 +30,7 @@ __date__ = "04/08/2016"
# \brief FreeCAD INP file reader for FEM workbench
import FreeCAD
from FreeCAD import Console
import os
@@ -211,7 +212,7 @@ def read_inp(file_name):
elif line[:5].upper() == "*STEP":
model_definition = False
if error_seg3 is True: # to print "not supported"
FreeCAD.Console.PrintError("Error: seg3 (3-node beam element type) not supported, yet.\n")
Console.PrintError("Error: seg3 (3-node beam element type) not supported, yet.\n")
f.close()
# switch from the CalculiX node numbering to the FreeCAD node numbering

View File

@@ -29,6 +29,7 @@ __url__ = "http://www.freecadweb.org"
# \brief FreeCAD FEM import tools
import FreeCAD
from FreeCAD import Console
def get_FemMeshObjectMeshGroups(
@@ -69,7 +70,7 @@ def get_FemMeshObjectOrder(
else:
presumable_order = [el - 1 for el in edges_length_set]
else:
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Found no edges in mesh: Element order determination does not work without them.\n"
)
@@ -212,7 +213,7 @@ def make_femmesh(
for i in elms_seg3:
e = elms_seg3[i]
mesh.addEdge([e[0], e[1], e[2]], i)
FreeCAD.Console.PrintLog(
Console.PrintLog(
"imported mesh: {} nodes, {} HEXA8, {} PENTA6, {} TETRA4, {} TETRA10, {} PENTA15"
.format(
len(nds),
@@ -223,7 +224,7 @@ def make_femmesh(
len(elms_penta15)
)
)
FreeCAD.Console.PrintLog(
Console.PrintLog(
"imported mesh: {} HEXA20, {} TRIA3, {} TRIA6, {} QUAD4, {} QUAD8, {} SEG2, {} SEG3"
.format(
len(elms_hexa20),
@@ -236,9 +237,9 @@ def make_femmesh(
)
)
else:
FreeCAD.Console.PrintError("No Elements found!\n")
Console.PrintError("No Elements found!\n")
else:
FreeCAD.Console.PrintError("No Nodes found!\n")
Console.PrintError("No Nodes found!\n")
return mesh
@@ -412,7 +413,7 @@ def fill_femresult_mechanical(
if len(Peeq) > 0:
if len(Peeq.values()) != len(disp.values()):
# how is this possible? An example is needed!
FreeCAD.Console.PrintError("PEEQ seams to have exptra nodes.\n")
Console.PrintError("PEEQ seams to have exptra nodes.\n")
Pe = []
Pe_extra_nodes = list(Peeq.values())
nodes = len(disp.values())
@@ -439,7 +440,7 @@ def fill_femresult_mechanical(
nodes = len(disp.values())
for i in range(nodes):
# how is this possible? An example is needed!
FreeCAD.Console.PrintError("Temperature seams to have exptra nodes.\n")
Console.PrintError("Temperature seams to have exptra nodes.\n")
Temp_value = Temp_extra_nodes[i]
Temp.append(Temp_value)
res_obj.Temperature = list(map((lambda x: x), Temp))

View File

@@ -32,6 +32,7 @@ __url__ = "http://www.freecadweb.org"
import os
import FreeCAD
from FreeCAD import Console
import Fem
@@ -71,26 +72,26 @@ def export(
):
"called when freecad exports an object to vtk"
if len(objectslist) > 1: # the case of no selected obj is caught by FreeCAD already
FreeCAD.Console.PrintError(
Console.PrintError(
"This exporter can only export one object at once\n"
)
return
obj = objectslist[0]
if obj.isDerivedFrom("Fem::FemPostPipeline"):
FreeCAD.Console.PrintError(
"Export of a VTK post object to vtk is not yet implemented !\n"
Console.PrintError(
"Export of a VTK post object to vtk is not yet implemented!\n"
)
return
elif obj.isDerivedFrom("Fem::FemMeshObject"):
FreeCAD.Console.PrintError(
Console.PrintError(
"Use export to FEM mesh formats to export a FEM mesh object to vtk!\n"
)
return
elif obj.isDerivedFrom("Fem::FemResultObject"):
Fem.writeResult(filename, obj)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Selected object is not supported by export to VTK.\n"
)
return
@@ -119,7 +120,7 @@ def importVtk(
# FreeCAD result object
importVtkFCResult(filename, object_name)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Error, wrong parameter in VTK import pref: {}\n"
.format(object_type)
)

View File

@@ -32,13 +32,14 @@ import json
import os
import FreeCAD
from FreeCAD import Console
from . import importToolsFem
has_yaml = True
try:
import yaml
except ImportError:
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"No YAML available (import yaml failure), "
"yaml import/export won't work\n"
)
@@ -88,13 +89,13 @@ def insert(
def export(objectslist, fileString):
"called when freecad exports a file"
if len(objectslist) != 1:
FreeCAD.Console.PrintError(
Console.PrintError(
"This exporter can only "
"export one object.\n")
return
obj = objectslist[0]
if not obj.isDerivedFrom("Fem::FemMeshObject"):
FreeCAD.Console.PrintError("No FEM mesh object selected.\n")
Console.PrintError("No FEM mesh object selected.\n")
return
write(fileString, obj.FemMesh)
@@ -162,13 +163,13 @@ def read(
raw_mesh_data = yaml.load(fp)
fp.close()
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Unknown extension, "
"please select other importer.\n")
FreeCAD.Console.PrintMessage("Converting indices to integer numbers ...")
Console.PrintMessage("Converting indices to integer numbers ...")
mesh_data = convert_raw_data_to_mesh_data(raw_mesh_data)
FreeCAD.Console.PrintMessage("OK\n")
Console.PrintMessage("OK\n")
return importToolsFem.make_femmesh(mesh_data)

View File

@@ -31,6 +31,7 @@ __url__ = "http://www.freecadweb.org"
import os
import FreeCAD
from FreeCAD import Console
# ************************************************************************************************
# ********* generic FreeCAD import and export methods ********************************************
@@ -78,11 +79,11 @@ def export(
):
"called when freecad exports a file"
if len(objectslist) != 1:
FreeCAD.Console.PrintError("This exporter can only export one object.\n")
Console.PrintError("This exporter can only export one object.\n")
return
obj = objectslist[0]
if not obj.isDerivedFrom("Fem::FemMeshObject"):
FreeCAD.Console.PrintError("No FEM mesh object selected.\n")
Console.PrintError("No FEM mesh object selected.\n")
return
femnodes_mesh = obj.FemMesh.Nodes
import femmesh.meshtools as FemMeshTools
@@ -179,7 +180,7 @@ def read_z88_mesh(
kflag = int(mesh_info[4])
# for non rotational elements ist --> kflag = 0 --> cartesian, kflag = 1 polar coordinates
if kflag:
FreeCAD.Console.PrintError(
Console.PrintError(
"KFLAG = 1, Rotational coordinates not supported at the moment\n"
)
return {}
@@ -188,15 +189,15 @@ def read_z88_mesh(
elemts_first_line = nodes_last_line + 1
elements_last_line = elemts_first_line - 1 + elements_count * 2
FreeCAD.Console.PrintLog(nodes_count)
Console.PrintLog(nodes_count)
Console.PrintLog("\n")
Console.PrintLog(elements_count)
FreeCAD.Console.PrintLog("\n")
FreeCAD.Console.PrintLog(elements_count)
FreeCAD.Console.PrintLog("\n")
FreeCAD.Console.PrintLog(nodes_last_line)
FreeCAD.Console.PrintLog("\n")
FreeCAD.Console.PrintLog(elemts_first_line)
FreeCAD.Console.PrintLog("\n")
FreeCAD.Console.PrintLog(elements_last_line)
Console.PrintLog(nodes_last_line)
Console.PrintLog("\n")
Console.PrintLog(elemts_first_line)
Console.PrintLog("\n")
Console.PrintLog(elements_last_line)
z88_mesh_file.seek(0) # go back to the beginning of the file
for no, line in enumerate(z88_mesh_file):
@@ -226,55 +227,55 @@ def read_z88_mesh(
# not supported elements
if z88_element_type == 8:
# torus8
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 8, torus8\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Rotational elements are not supported at the moment\n"
)
return {}
elif z88_element_type == 12:
# torus12
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 12, torus12\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Rotational elements are not supported at the moment\n"
)
return {}
elif z88_element_type == 15:
# torus6
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 15, torus6\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Rotational elements are not supported at the moment\n"
)
return {}
elif z88_element_type == 19:
# platte16
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 19, platte16\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Not supported at the moment\n"
)
return {}
elif z88_element_type == 21:
# schale16, mixture made from hexa8 and hexa20 (thickness is linear)
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 21, schale16\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Not supported at the moment\n"
)
return {}
elif z88_element_type == 22:
# schale12, mixtrue made from prism6 and prism15 (thickness is linear)
FreeCAD.Console.PrintError(
Console.PrintError(
"Z88 Element No. 22, schale12\n"
)
FreeCAD.Console.PrintError(
Console.PrintError(
"Not supported at the moment\n"
)
return {}
@@ -392,13 +393,13 @@ def read_z88_mesh(
# unknown elements
# some examples have -1 for some teaching reasons to show some other stuff
else:
FreeCAD.Console.PrintError("Unknown element\n")
Console.PrintError("Unknown element\n")
return {}
for n in nodes:
FreeCAD.Console.PrintLog(str(n) + " " + str(nodes[n]) + "\n")
Console.PrintLog(str(n) + " " + str(nodes[n]) + "\n")
for e in elements_tria6:
FreeCAD.Console.PrintLog(str(e) + " " + str(elements_tria6[e]) + "\n")
Console.PrintLog(str(e) + " " + str(elements_tria6[e]) + "\n")
FreeCAD.Console.PrintLog("\n")
z88_mesh_file.close()
@@ -429,7 +430,7 @@ def write(
fem_mesh: a FemMesh"""
if not fem_mesh.isDerivedFrom("Fem::FemMesh"):
FreeCAD.Console.PrintError("Not a FemMesh was given as parameter.\n")
Console.PrintError("Not a FemMesh was given as parameter.\n")
return
femnodes_mesh = fem_mesh.Nodes
import femmesh.meshtools as FemMeshTools
@@ -461,7 +462,7 @@ def write_z88_mesh_to_file(
):
node_dof = 6 # schalenelemente
else:
FreeCAD.Console.PrintError("Error: wrong z88_element_type.\n")
Console.PrintError("Error: wrong z88_element_type.\n")
return
node_count = len(femnodes_mesh)
element_count = len(femelement_table)
@@ -545,7 +546,7 @@ def write_z88_mesh_to_file(
)
)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Writing of Z88 elementtype {0} not supported.\n".format(z88_element_type)
)
# TODO support schale12 (made from prism15) and schale16 (made from hexa20)
@@ -559,14 +560,14 @@ def get_z88_element_type(
):
import femmesh.meshtools as FemMeshTools
if not femmesh:
FreeCAD.Console.PrintMessage("Error: No femmesh!\n")
Console.PrintError("Error: No femmesh!")
if not femelement_table:
FreeCAD.Console.PrintMessage("We need to get the femelement_table first!\n")
Console.PrintError("We need to get the femelement_table first!")
femelement_table = FemMeshTools.get_femelement_table(femmesh)
# in some cases lowest key in femelement_table is not [1]
for elem in sorted(femelement_table):
elem_length = len(femelement_table[elem])
FreeCAD.Console.PrintLog("node count of first element: " + str(elem_length) + "\n")
Console.PrintLog("node count of first element: " + str(elem_length) + "\n")
break # break after the first elem
if FemMeshTools.is_solid_femmesh(femmesh):
if femmesh.TetraCount == femmesh.VolumeCount:
@@ -575,43 +576,43 @@ def get_z88_element_type(
elif elem_length == 10:
return 16
else:
FreeCAD.Console.PrintMessage("Tetra with neither 4 nor 10 nodes.\n")
Console.PrintMessage("Tetra with neither 4 nor 10 nodes.\n")
elif femmesh.HexaCount == femmesh.VolumeCount:
if elem_length == 8:
return 1
elif elem_length == 20:
return 10
else:
FreeCAD.Console.PrintMessage("Hexa with neither 8 nor 20 nodes.\n")
Console.PrintError("Hexa with neither 8 nor 20 nodes.\n")
return 0
else:
FreeCAD.Console.PrintMessage("no tetra, no hexa or Mixed Volume Elements.\n")
Console.PrintError("no tetra, no hexa or Mixed Volume Elements.\n")
elif FemMeshTools.is_face_femmesh(femmesh):
if femmesh.TriangleCount == femmesh.FaceCount:
if elem_length == 3:
FreeCAD.Console.PrintMessage("tria3mesh, not supported by Z88.\n")
Console.PrintError("tria3mesh, not supported by Z88.\n")
return 0
elif elem_length == 6:
return 24
else:
FreeCAD.Console.PrintMessage("Tria with neither 3 nor 6 nodes.\n")
Console.PrintError("Tria with neither 3 nor 6 nodes.\n")
return 0
elif femmesh.QuadrangleCount == femmesh.FaceCount:
if elem_length == 4:
FreeCAD.Console.PrintMessage("quad4mesh, not supported by Z88.\n")
Console.PrintError("quad4mesh, not supported by Z88.\n")
return 0
elif elem_length == 8:
return 23
else:
FreeCAD.Console.PrintMessage("Quad with neither 4 nor 8 nodes.\n")
Console.PrintError("Quad with neither 4 nor 8 nodes.\n")
return 0
else:
FreeCAD.Console.PrintMessage("no tria, no quad\n")
Console.PrintError("no tria, no quad\n")
return 0
elif FemMeshTools.is_edge_femmesh(femmesh):
FreeCAD.Console.PrintMessage("Edge femmesh will be exported as 3D truss element nr 4.\n")
Console.PrintMessage("Edge femmesh will be exported as 3D truss element nr 4.\n")
return 4
else:
FreeCAD.Console.PrintMessage("Neither edge nor face nor solid femmesh.\n")
Console.PrintError("Neither edge nor face nor solid femmesh.\n")
return 0
return 0

View File

@@ -29,6 +29,7 @@ __url__ = "http://www.freecadweb.org"
# \brief FreeCAD Z88 Disp Reader for FEM workbench
import FreeCAD
from FreeCAD import Console
import os
@@ -99,7 +100,7 @@ def import_z88_disp(
)
result_mesh_object.FemMesh = femmesh
else:
FreeCAD.Console.PrintError("Z88 mesh file z88i1.txt not found!")
Console.PrintError("Z88 mesh file z88i1.txt not found!")
# create result obj
for result_set in disp_read["Results"]:
@@ -118,7 +119,7 @@ def import_z88_disp(
FreeCAD.ActiveDocument.recompute()
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Problem on Z88 result file import. No nodes found in Z88 result file.\n"
)
return res_obj
@@ -145,7 +146,6 @@ def read_z88_disp(
if lno >= 6:
# disp line
# print(linelist)
node_no = int(linelist[0])
mode_disp_x = float(linelist[1])
mode_disp_y = float(linelist[2])
@@ -160,7 +160,7 @@ def read_z88_disp(
results.append(mode_results)
for r in results[0]["disp"]:
FreeCAD.Console.PrintLog("{} --> {}\n".format(r, results[0]["disp"][r]))
Console.PrintLog("{} --> {}\n".format(r, results[0]["disp"][r]))
z88_disp_file.close()
return {"Nodes": nodes, "Results": results}

View File

@@ -28,12 +28,12 @@ __url__ = "http://www.freecadweb.org"
# \ingroup FEM
# \brief FreeCAD Fenics Mesh XDMF reader for FEM workbench
import FreeCAD
from FreeCAD import Console
def read_fenics_mesh_xdmf(xdmffilename):
FreeCAD.Console.PrintMessage("Not operational, yet\n")
Console.PrintMessage("Not operational, yet\n")
return {
"Nodes": {},

View File

@@ -19,7 +19,6 @@
# * USA *
# * *
# ***************************************************************************
from __future__ import print_function
__title__ = "FreeCAD Fenics XML mesh reader"
__author__ = "Johannes Hartung"
@@ -31,6 +30,7 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FreeCAD import Console
from xml.etree import ElementTree as ET
import itertools
@@ -58,8 +58,8 @@ def read_fenics_mesh_xml(xmlfilename):
vertex_size = 0
print("Mesh dimension: %d" % (dim,))
print("Mesh cell type: %s" % (cell_type,))
Console.PrintLog("Mesh dimension: %d\n" % (dim,))
Console.PrintLog("Mesh cell type: %s\n" % (cell_type,))
# every cell type contains a dict with key=dimension and value=number
@@ -77,10 +77,10 @@ def read_fenics_mesh_xml(xmlfilename):
cell_dict = {}
if find_vertices is None:
print("No vertices found!")
Console.PrintWarning("No vertices found!\n")
else:
vertex_size = int(find_vertices.attrib.get("size"))
print("Reading %d vertices" % (vertex_size,))
Console.PrintLog("Reading %d vertices\n" % (vertex_size,))
for vertex in find_vertices:
ind = int(vertex.get("index"))
@@ -94,18 +94,18 @@ def read_fenics_mesh_xml(xmlfilename):
# increase node index by one, since fenics starts at 0, FreeCAD at 1
# print("%d %f %f %f" % (ind, node_x, node_y, node_z))
else:
print("found strange vertex tag: %s" % (vertex.tag,))
Console.PrintWarning("found strange vertex tag: %s\n" % (vertex.tag,))
if find_cells is None:
print("No cells found!")
Console.PrintWarning("No cells found!\n")
else:
print("Reading %d cells" % (int(find_cells.attrib.get("size")),))
Console.PrintLog("Reading %d cells\n" % (int(find_cells.attrib.get("size")),))
for cell in find_cells:
ind = int(cell.get("index"))
if cell.tag.lower() != cell_type.lower():
print(
"Strange mismatch between cell type {} and cell tag {}"
Console.PrintWarning(
"Strange mismatch between cell type {} and cell tag {}\n"
.format(cell_type, cell.tag.lower())
)
num_vertices = cells_parts_dim[cell_type][0]
@@ -232,23 +232,23 @@ def read_fenics_mesh_xml(xmlfilename):
root = tree.getroot()
if root.tag.lower() != "dolfin":
print("Strange root tag, should be dolfin!")
Console.PrintWarning("Strange root tag, should be dolfin!\n")
find_mesh = root.find("mesh")
if find_mesh is not None: # these are consistency checks of the XML structure
print("Mesh found")
Console.PrintMessage("Mesh found\n")
(nodes, cells_dict, cell_type, dim) = read_mesh_block(find_mesh)
element_dict = generate_lower_dimensional_structures(nodes, cells_dict, cell_type, dim)
print("Show min max element dict")
Console.PrintMessage("Show min max element dict")
for (elm, numbers) in list(element_dict.items()):
lst = sorted(list(numbers.items()), key=lambda x: x[0])
if lst != []:
print(elm, " min: ", lst[0], " max: ", lst[-1])
Console.PrintWarning(elm, " min: ", lst[0], " max: ", lst[-1], "\n")
else:
print("No mesh found")
Console.PrintError("No mesh found")
if root.find("data") is not None:
print("Internal mesh data found")
Console.PrintLog("Internal mesh data found\n")
return {
"Nodes": nodes,

View File

@@ -28,6 +28,7 @@ __url__ = "http://www.freecadweb.org"
# \ingroup FEM
# \brief FreeCAD Fenics Mesh XDMF writer for FEM workbench
from FreeCAD import Console
from .importToolsFem import \
get_FemMeshObjectDimension,\
get_FemMeshObjectElementTypes,\
@@ -168,7 +169,10 @@ def write_fenics_mesh_codim_xdmf(
fc_topo = fem_mesh_obj.FemMesh.Nodes
else:
fc_topo = []
print("Dimension of mesh incompatible with export XDMF function: %d" % (dim_topo,))
Console.PrintError(
"Dimension of mesh incompatible with export XDMF function: %d\n"
% (dim_topo,)
)
nodeindices = [(
nodes_dict[ind] for ind in fem_mesh_obj.FemMesh.getElementNodes(fc_topo_ind)
@@ -271,16 +275,16 @@ def write_fenics_mesh_xdmf(
"Prism": "unknown", "Pyramid": "unknown",
}
print("Converting " + fem_mesh_obj.Label + " to fenics XDMF File")
print("Dimension of mesh: %d" % (get_FemMeshObjectDimension(fem_mesh_obj),))
Console.PrintMessage("Converting " + fem_mesh_obj.Label + " to fenics XDMF File\n")
Console.PrintMessage("Dimension of mesh: %d\n" % (get_FemMeshObjectDimension(fem_mesh_obj),))
elements_in_mesh = get_FemMeshObjectElementTypes(fem_mesh_obj)
print("Elements appearing in mesh: %s" % (str(elements_in_mesh),))
Console.PrintMessage("Elements appearing in mesh: %s\n" % (str(elements_in_mesh),))
celltype_in_mesh = get_MaxDimElementFromList(elements_in_mesh)
(num_cells, cellname_fc, dim_cell) = celltype_in_mesh
cellname_fenics = FreeCAD_to_Fenics_dict[cellname_fc]
print(
"Celltype in mesh -> {} and its Fenics dolfin name: {}"
Console.PrintMessage(
"Celltype in mesh -> {} and its Fenics dolfin name: {}\n"
.format(celltype_in_mesh, cellname_fenics)
)
@@ -313,15 +317,17 @@ def write_fenics_mesh_xdmf(
gmshgroups = get_FemMeshObjectMeshGroups(fem_mesh_obj)
if gmshgroups is not ():
print("found mesh groups")
Console.PrintMessage("found mesh groups\n")
for g in gmshgroups:
mesh_function_type = fem_mesh.getGroupElementType(g)
mesh_function_codim = dim_cell - FreeCAD_Group_Dimensions[mesh_function_type]
mesh_function_name = fem_mesh.getGroupName(g)
print("group id: %d (label: %s) with element type %s and codim %d"
% (g, mesh_function_name, mesh_function_type, mesh_function_codim))
Console.PrintMessage(
"group id: %d (label: %s) with element type %s and codim %d\n"
% (g, mesh_function_name, mesh_function_type, mesh_function_codim)
)
mesh_function_grid = ET.SubElement(
domain, "Grid",

View File

@@ -19,7 +19,6 @@
# * USA *
# * *
# ***************************************************************************
from __future__ import print_function
__title__ = "FreeCAD Fenics XML mesh writer"
__author__ = "Johannes Hartung"
@@ -30,6 +29,7 @@ __url__ = "http://www.freecadweb.org"
# \brief FreeCAD Fenics Mesh XML writer for FEM workbench
from FreeCAD import Console
from .importToolsFem import get_FemMeshObjectDimension
from .importToolsFem import get_FemMeshObjectElementTypes
from .importToolsFem import get_MaxDimElementFromList
@@ -68,17 +68,18 @@ def write_fenics_mesh_xml(fem_mesh_obj, outputfile):
"hexahedron": 8
}
print("Converting " + fem_mesh_obj.Label + " to fenics XML File")
print("Dimension of mesh: %d" % (get_FemMeshObjectDimension(fem_mesh_obj),))
Console.Message("Converting " + fem_mesh_obj.Label + " to fenics XML File\n")
Console.Message("Dimension of mesh: %d\n" % (get_FemMeshObjectDimension(fem_mesh_obj),))
elements_in_mesh = get_FemMeshObjectElementTypes(fem_mesh_obj)
print("Elements appearing in mesh: %s" % (str(elements_in_mesh),))
Console.Message("Elements appearing in mesh: %s" % (str(elements_in_mesh),))
celltype_in_mesh = get_MaxDimElementFromList(elements_in_mesh)
(num_cells, cellname_fc, dim_cell) = celltype_in_mesh
cellname_fenics = FreeCAD_to_Fenics_dict[cellname_fc]
num_verts_cell = XML_Number_of_Nodes_dict[cellname_fenics]
print(
"Celltype in mesh -> %s and its Fenics name: %s" % (str(celltype_in_mesh), cellname_fenics)
Console.Message(
"Celltype in mesh -> %s and its Fenics name: %s\n"
% (str(celltype_in_mesh), cellname_fenics)
)
root = ET.Element("dolfin", dolfin="http://fenicsproject.org")

View File

@@ -31,6 +31,7 @@ import sys
import subprocess
import FreeCAD
from FreeCAD import Console
import Fem
from FreeCAD import Units
from . import meshtools
@@ -73,7 +74,7 @@ class GmshTools():
elif self.order == "2nd":
self.order = "2"
else:
print("Error in order")
Console.PrintError("Error in order\n")
# dimension
self.dimension = self.mesh_obj.ElementDimension
@@ -160,15 +161,15 @@ class GmshTools():
return error
def start_logs(self):
print("\nGmsh FEM mesh run is being started.")
print(" Part to mesh: Name --> {}, Label --> {}, ShapeType --> {}".format(
Console.PrintLog("\nGmsh FEM mesh run is being started.\n")
Console.PrintLog(" Part to mesh: Name --> {}, Label --> {}, ShapeType --> {}\n".format(
self.part_obj.Name,
self.part_obj.Label,
self.part_obj.Shape.ShapeType
))
print(" CharacteristicLengthMax: {}".format(self.clmax))
print(" CharacteristicLengthMin: {}".format(self.clmin))
print(" ElementOrder: {}".format(self.order))
Console.PrintLog(" CharacteristicLengthMax: {}\n".format(self.clmax))
Console.PrintLog(" CharacteristicLengthMin: {}\n".format(self.clmin))
Console.PrintLog(" ElementOrder: {}\n".format(self.order))
def get_dimension(self):
# Dimension
@@ -188,18 +189,18 @@ class GmshTools():
self.dimension = "1"
elif shty == "Vertex":
# print("Found: " + shty)
FreeCAD.Console.PrintError("You can not mesh a Vertex.\n")
Console.PrintError("You can not mesh a Vertex.\n")
self.dimension = "0"
elif shty == "Compound":
# print(" Found a " + shty)
FreeCAD.Console.PrintLog(
Console.PrintLog(
" Found a Compound. Since it could contain"
"any kind of shape dimension 3 is used.\n"
)
self.dimension = "3" # dimension 3 works for 2D and 1d shapes as well
else:
self.dimension = "0"
FreeCAD.Console.PrintError(
Console.PrintError(
"Could not retrieve Dimension from shape type. Please choose dimension."
)
elif self.dimension == "3D":
@@ -209,8 +210,8 @@ class GmshTools():
elif self.dimension == "1D":
self.dimension = "1"
else:
print("Error in dimension")
print(" ElementDimension: " + self.dimension)
Console.PrintError("Error in dimension\n")
Console.PrintMessage(" ElementDimension: " + self.dimension + "\n")
def get_tmp_file_paths(self, param_working_dir=None, create=False):
self.working_dir = ""
@@ -219,7 +220,7 @@ class GmshTools():
self.working_dir = param_working_dir
if femutils.check_working_dir(self.working_dir) is not True:
if create is True:
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Dir given as parameter \'{}\' doesn't exist, "
"but parameter to create it is set to True. "
"Dir will be created.\n".format(self.working_dir)
@@ -227,13 +228,13 @@ class GmshTools():
from os import mkdir
mkdir(param_working_dir)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"Dir given as parameter \'{}\' doesn't exist "
"and create parameter is set to False.\n"
.format(self.working_dir)
)
self.working_dir = femutils.get_pref_working_dir(self.mesh_obj)
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Dir \'{}\' will be used instead.\n"
.format(self.working_dir)
)
@@ -242,12 +243,12 @@ class GmshTools():
# check working_dir exist, if not use a tmp dir and inform the user
if femutils.check_working_dir(self.working_dir) is not True:
FreeCAD.Console.PrintError(
Console.PrintError(
"Dir \'{}\' doesn't exist or cannot be created.\n"
.format(self.working_dir)
)
self.working_dir = femutils.get_temp_dir(self.mesh_obj)
FreeCAD.Console.PrintMessage(
Console.PrintMessage(
"Dir \'{}\' will be used instead.\n"
.format(self.working_dir)
)
@@ -259,9 +260,9 @@ class GmshTools():
self.temp_file_geometry = join(self.working_dir, _geometry_name + ".brep") # geometry file
self.temp_file_mesh = join(self.working_dir, self.mesh_name + ".unv") # mesh file
self.temp_file_geo = join(self.working_dir, "shape2mesh.geo") # Gmsh input file
print(" " + self.temp_file_geometry)
print(" " + self.temp_file_mesh)
print(" " + self.temp_file_geo)
Console.PrintMessage(" " + self.temp_file_geometry + "\n")
Console.PrintMessage(" " + self.temp_file_mesh + "\n")
Console.PrintMessage(" " + self.temp_file_geo + "\n")
def get_gmsh_command(self):
from platform import system
@@ -288,7 +289,7 @@ class GmshTools():
"Please install Gmsh or set path to binary "
"in FEM preferences tab Gmsh.\n"
)
FreeCAD.Console.PrintError(error_message)
Console.PrintError(error_message)
raise Exception(error_message)
self.gmsh_bin = gmsh_path
else:
@@ -296,7 +297,7 @@ class GmshTools():
"No standard location implemented for your operating system. "
"Set GMHS binary path in FEM preferences.\n"
)
FreeCAD.Console.PrintError(error_message)
Console.PrintError(error_message)
raise Exception(error_message)
else:
if not self.gmsh_bin:
@@ -310,7 +311,7 @@ class GmshTools():
self.gmsh_bin = FreeCAD.getHomePath() + "bin/gmsh.exe"
else:
self.gmsh_bin = "gmsh"
print(" " + self.gmsh_bin)
Console.PrintMessage(" " + self.gmsh_bin + "\n")
def get_group_data(self):
# TODO: solids, faces, edges and vertexes don't seem to work together in one group,
@@ -321,21 +322,21 @@ class GmshTools():
# print(" No mesh group objects.")
pass
else:
print(" Mesh group objects, we need to get the elements.")
Console.PrintMessage(" Mesh group objects, we need to get the elements.\n")
for mg in self.mesh_obj.MeshGroupList:
new_group_elements = meshtools.get_mesh_group_elements(mg, self.part_obj)
for ge in new_group_elements:
if ge not in self.group_elements:
self.group_elements[ge] = new_group_elements[ge]
else:
FreeCAD.Console.PrintError(" A group with this name exists already.\n")
Console.PrintError(" A group with this name exists already.\n")
# group meshing for analysis
analysis_group_meshing = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/Fem/General"
).GetBool("AnalysisGroupMeshing", False)
if self.analysis and analysis_group_meshing:
print(" Group meshing for analysis.")
Console.PrintMessage(" Group meshing for analysis.\n")
self.group_nodes_export = True
new_group_elements = meshtools.get_analysis_group_elements(
self.analysis,
@@ -345,12 +346,12 @@ class GmshTools():
if ge not in self.group_elements:
self.group_elements[ge] = new_group_elements[ge]
else:
FreeCAD.Console.PrintError(" A group with this name exists already.\n")
Console.PrintError(" A group with this name exists already.\n")
else:
print(" No Group meshing for analysis.")
Console.PrintMessage(" No Group meshing for analysis.\n")
if self.group_elements:
print(" {}".format(self.group_elements))
Console.PrintMessage(" {}\n".format(self.group_elements))
def get_region_data(self):
# mesh regions
@@ -358,7 +359,7 @@ class GmshTools():
# print(" No mesh regions.")
pass
else:
print(" Mesh regions, we need to get the elements.")
Console.PrintMessage(' Mesh regions, we need to get the elements.\n')
# by the use of MeshRegion object and a BooleanSplitCompound
# there could be problems with node numbers see
# http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467
@@ -377,7 +378,7 @@ class GmshTools():
"It is strongly recommended to extract the shape to mesh "
"from the Compound and use this one."
)
FreeCAD.Console.PrintError(error_message + "\n")
Console.PrintError(error_message + "\n")
# TODO: no gui popup because FreeCAD will be in a endless output loop
# as long as the pop up is on --> maybe find a better solution for
# either of both --> thus the pop up is in task panel
@@ -394,7 +395,7 @@ class GmshTools():
# if not try to find the element in the shape to mesh
search_ele_in_shape_to_mesh = False
if not self.part_obj.Shape.isSame(sub[0].Shape):
FreeCAD.Console.PrintLog(
Console.PrintLog(
" One element of the meshregion {} is "
"not an element of the Part to mesh.\n"
"But we are going to try to find it in "
@@ -416,7 +417,7 @@ class GmshTools():
if found_element:
elems = found_element
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"One element of the meshregion {} could not be found "
"in the Part to mesh. It will be ignored.\n"
.format(mr_obj.Name)
@@ -427,19 +428,19 @@ class GmshTools():
mr_obj.CharacteristicLength
).Value
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The element {} of the meshregion {} has "
"been added to another mesh region.\n"
.format(elems, mr_obj.Name)
)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The meshregion: {} is not used to create the mesh "
"because the reference list is empty.\n"
.format(mr_obj.Name)
)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The meshregion: {} is not used to create the "
"mesh because the CharacteristicLength is 0.0 mm.\n"
.format(mr_obj.Name)
@@ -449,8 +450,8 @@ class GmshTools():
ele_shape = meshtools.get_element(self.part_obj, eleml)
ele_vertexes = meshtools.get_vertexes_by_element(self.part_obj.Shape, ele_shape)
self.ele_node_map[eleml] = ele_vertexes
print(" {}".format(self.ele_length_map))
print(" {}".format(self.ele_node_map))
Console.PrintMessage(" {}\n".format(self.ele_length_map))
Console.PrintMessage(" {}\n".format(self.ele_node_map))
def get_boundary_layer_data(self):
# mesh boundary layer
@@ -462,7 +463,7 @@ class GmshTools():
# print(" No mesh boundary layer setting document object.")
pass
else:
print(" Mesh boundary layers, we need to get the elements.")
Console.PrintMessage(" Mesh boundary layers, we need to get the elements.\n")
if self.part_obj.Shape.ShapeType == "Compound":
# see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and
# http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
@@ -471,7 +472,7 @@ class GmshTools():
"It is strongly recommended to extract the shape to mesh "
"from the Compound and use this one."
)
FreeCAD.Console.PrintError(err + "\n")
Console.PrintError(err + "\n")
for mr_obj in self.mesh_obj.MeshBoundaryLayerList:
if mr_obj.MinimumThickness and Units.Quantity(mr_obj.MinimumThickness).Value > 0:
if mr_obj.References:
@@ -483,7 +484,7 @@ class GmshTools():
# if not try to find the element in the shape to mesh
search_ele_in_shape_to_mesh = False
if not self.part_obj.Shape.isSame(sub[0].Shape):
FreeCAD.Console.PrintLog(
Console.PrintLog(
" One element of the mesh boundary layer {} is "
"not an element of the Part to mesh.\n"
"But we are going to try to find it in "
@@ -505,7 +506,7 @@ class GmshTools():
if found_element: # also
elems = found_element
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"One element of the mesh boundary layer {} could "
"not be found in the Part to mesh. "
"It will be ignored.\n"
@@ -518,7 +519,7 @@ class GmshTools():
belem_list.append(elems)
self.bl_boundary_list.append(elems)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The element {} of the mesh boundary "
"layer {} has been added "
"to another mesh boundary layer.\n"
@@ -550,23 +551,23 @@ class GmshTools():
elif self.dimension == "3":
setting["FacesList"] = belem_list
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"boundary layer is only supported for 2D and 3D mesh"
)
self.bl_setting_list.append(setting)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The mesh boundary layer: {} is not used to create "
"the mesh because the reference list is empty.\n"
.format(mr_obj.Name)
)
else:
FreeCAD.Console.PrintError(
Console.PrintError(
"The mesh boundary layer: {} is not used to create "
"the mesh because the min thickness is 0.0 mm.\n"
.format(mr_obj.Name)
)
print(" {}".format(self.bl_setting_list))
Console.PrintMessage(" {}\n".format(self.bl_setting_list))
def write_groups(self, geo):
if self.group_elements:
@@ -612,7 +613,7 @@ class GmshTools():
# currently single body is supported
if len(self.bl_setting_list):
geo.write("// boundary layer setting\n")
print(" Start to write boundary layer setup")
Console.PrintMessage(" Start to write boundary layer setup\n")
field_number = 1
for item in self.bl_setting_list:
prefix = "Field[" + str(field_number) + "]"
@@ -629,13 +630,13 @@ class GmshTools():
else:
line = prefix + "." + str(k) + " = " + str(v) + ";\n"
geo.write(line)
print(line)
Console.PrintMessage("{}\n".format(line))
geo.write("BoundaryLayer Field = " + str(field_number) + ";\n")
geo.write("// end of this boundary layer setup \n")
field_number += 1
geo.write("\n")
geo.flush()
print(" finished in boundary layer setup")
Console.PrintMessage(" finished in boundary layer setup\n")
else:
# print(" no boundary layer setup is found for this mesh")
geo.write("// no boundary layer settings for this mesh\n")
@@ -811,7 +812,7 @@ class GmshTools():
# print(error)
except:
error = "Error executing: {}\n".format(" ".join(comandlist))
FreeCAD.Console.PrintError(error)
Console.PrintError(error)
self.error = True
return error
@@ -819,9 +820,9 @@ class GmshTools():
if not self.error:
fem_mesh = Fem.read(self.temp_file_mesh)
self.mesh_obj.FemMesh = fem_mesh
FreeCAD.Console.PrintMessage(" The Part should have a pretty new FEM mesh!\n")
Console.PrintMessage(" The Part should have a pretty new FEM mesh!\n")
else:
FreeCAD.Console.PrintError("No mesh was created.\n")
Console.PrintError("No mesh was created.\n")
## @}

View File

@@ -31,8 +31,8 @@ import os.path
import subprocess
import tempfile
import FreeCAD
from FreeCAD import Units
from FreeCAD import Console
import Fem
import femtools.femutils as femutils
import femmesh.gmshtools as gmshtools
@@ -125,7 +125,7 @@ class Writer(object):
groups.extend(self._builder.getBoundaryNames())
self._exportToUnv(groups, mesh, unvPath)
if self.testmode:
FreeCAD.Console.PrintMessage("We are in testmode ElmerGrid may not be installed.\n")
Console.PrintMessage("We are in testmode ElmerGrid may not be installed.\n")
else:
binary = settings.get_binary("ElmerGrid")
if binary is None:
@@ -135,7 +135,7 @@ class Writer(object):
_ELMERGRID_OFORMAT,
unvPath,
"-out", self.directory]
subprocess.call(args)
subprocess.call(args, stdout=subprocess.DEVNULL)
def _writeStartinfo(self):
path = os.path.join(self.directory, _STARTINFO_NAME)
@@ -165,7 +165,7 @@ class Writer(object):
tools.write_part_file()
tools.write_geo()
if self.testmode:
FreeCAD.Console.PrintMessage("We are in testmode, Gmsh may not be installed.\n")
Console.PrintMessage("We are in testmode, Gmsh may not be installed.\n")
import shutil
shutil.copyfile(geoPath, os.path.join(self.directory, "group_mesh.geo"))
else:

View File

@@ -18,14 +18,21 @@
# * USA *
# * *
# ***************************************************************************
""" Execute Solver and obtain Reports and Results.
Integral part of the Solver Framework which contains components responsible for
executing the solver in the background. Also provides an asynchronous
communication system with the solver running in the background. The purpose of
this module is to be as generic as possible. It can execute every solver
supported by the fem workbench. The threading and communication support is
mainly implemented by the :mod:`femsolver.task` and :mod:`femsolver.signal`
modules.
"""
__title__ = "FreeCAD FEM solver run"
__author__ = "Markus Hovorka"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import os
import os.path
import threading
@@ -54,6 +61,35 @@ _dirTypes = {}
def run_fem_solver(solver, working_dir=None):
""" Execute *solver* of the solver framwork.
Uses :meth:`getMachine <femsolver.solverbase.Proxy.getMachine>` to obtain a
:class:`Machine` instance of the solver. It than executes the Machine with
using the ``RESULTS`` target (see :class:`Machine` for infos about
different targets). This method is blocking, it waits for the solver to
finished before returning. Be aware of :class:`Machine` caching when using
the function.
:param solver:
A document object which must be a famework complient solver. This means
that it should be derived from the document object provided by
:mod:`femsolver.solverbase` and implement all required methods
correctely. Of particular importance is :meth:`getMachine
<femsolver.solverbase.Proxy.getMachine>` as it is used by this method
the get the :class:`Machine` used to execute the solver.
:param working_dir:
If specified it overwrites the automatic and user configurable working
directory management of the Solver framework. Should always be a
absolute path because the location of the binary is not consistent
among platforms. If ``None`` the automatic working directory management
is used.
:note:
There is some legacy code to execute the old Calculix solver
(pre-framework) which behaives differently because it doesn't use a
:class:`Machine`.
"""
if solver.Proxy.Type == "Fem::FemSolverCalculixCcxTools":
App.Console.PrintMessage("CalxuliX ccx tools solver!\n")
@@ -112,6 +148,19 @@ def run_fem_solver(solver, working_dir=None):
def getMachine(solver, path=None):
""" Get or create :class:`Machine` using caching mechanism.
:param solver:
A document object which must be a famework complient solver. This means
that it should be derived from the document object provided by
:mod:`femsolver.solverbase` and implement all required methods
correctely. Of particular importance is :meth:`getMachine
<femsolver.solverbase.Proxy.getMachine>` as it is used by this method
to create a new :class:`Machine` on cache miss.
:param path:
A valid filesystem path which shall be associetad with the machine.
"""
_DocObserver.attach()
m = _machines.get(solver)
if m is None or not _isPathValid(m, path):
@@ -124,15 +173,15 @@ def _isPathValid(m, path):
setting = settings.get_dir_setting()
if path is not None:
return t is None and m.directory == path
if setting == settings.BESIDE:
if t == settings.BESIDE:
if setting == settings.DirSetting.BESIDE:
if t == settings.DirSetting.BESIDE:
base = os.path.split(m.directory.rstrip("/"))[0]
return base == femutils.get_beside_base(m.solver)
return False
if setting == settings.TEMPORARY:
return t == settings.TEMPORARY
if setting == settings.CUSTOM:
if t == settings.CUSTOM:
if setting == settings.DirSetting.TEMPORARY:
return t == settings.DirSetting.TEMPORARY
if setting == settings.DirSetting.CUSTOM:
if t == settings.DirSetting.CUSTOM:
firstBase = os.path.split(m.directory.rstrip("/"))[0]
customBase = os.path.split(firstBase)[0]
return customBase == femutils.get_custom_base(m.solver)
@@ -393,17 +442,11 @@ class _DocObserver(object):
def _deleteMachine(self, obj):
m = _machines[obj]
t = _dirTypes[m.directory]
def delegate():
m.join()
if t == settings.TEMPORARY:
shutil.rmtree(m.directory)
del _dirTypes[m.directory]
del _machines[obj]
m.abort()
thread = threading.Thread(target=delegate)
thread.daemon = False
thread.start()
if t == settings.DirSetting.TEMPORARY:
shutil.rmtree(m.directory)
del _machines[obj]
del _dirTypes[m.directory]
def _checkEquation(self, obj):
for o in obj.Document.Objects:
@@ -456,5 +499,3 @@ class _DocObserver(object):
return True
return False
## @}

View File

@@ -19,28 +19,58 @@
# * USA *
# * *
# ***************************************************************************
""" Query FEM specific settings including solver settings.
Query settings from the hierarchically organized settings/parameter system of
FreeCAD related to the FEM module. The collection of independed functions use
the settings system as a backend and expose a easy to use interface for other
modules of the FEM module.
Functions quering solver specific settings always take a solver name as a
string to identify the solver in question. At the moment the following solvers
are supported:
- Calculix
- ElmerSolver
- Z88
To query settings about those solver the solver name must be given exactely in
the form written in the list above. To make the solver recognize settings for a
new solver have a look at :class:`_SolverDlg`.
"""
__title__ = "FreeCAD FEM solver settings"
__author__ = "Markus Hovorka, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
"""
parameter in FreeCAD can be edited in two ways, either in the
Preferences: menu Edit --> Preferences
or
Parameter editor: menu Tools --> Edit parameter
"""
import FreeCAD
# working directory: possible choices
TEMPORARY = "temporary"
BESIDE = "beside"
CUSTOM = "custom"
class DirSetting:
""" Enum of possible directory setting values.
Strings used to indicate the solver directory setting set in FreeCADs
setting system. Returned by :func:`get_dir_setting` for that purpose. There
are three different possible values:
:cvar TEMPORARY:
Let FreeCAD manage (create, delete) the working directories for all
solver. Use temporary directories.
:cvar BESIDE:
Create a directory in the same folder in which the FCStd file of the
document is located. Use Subfolder for each solver (e.g. for a file
./mydoc.FCStd and a solver with the label Elmer002 use
./mydoc/Elmer002).
:cvar CUSTOM:
Use directory set below. Create own subdirectory for every solver. Name
directory after the solver label prefixed with the document name.
"""
TEMPORARY = "temporary"
BESIDE = "beside"
CUSTOM = "custom"
# FEM parameter location path
@@ -48,26 +78,117 @@ _PARAM_PATH = "User parameter:BaseApp/Preferences/Mod/Fem/"
_GENERAL_PARAM = _PARAM_PATH + "General"
# ******** binary parameter **********************************************************************
def get_binary(name):
""" Find binary of solver *name* honoring user settings.
Return the specific path set by the user in FreeCADs settings/parameter
system if set or the default binary name if no specific path is set. If no
path was found because the solver *name* isn't supported ``None`` is
returned. This method does not check whether the binary actually exists
and is callable.
:param name: solver id as a ``str`` (see :mod:`femsolver.settings`)
"""
if name in _SOLVER_PARAM:
binary = _SOLVER_PARAM[name].get_binary()
FreeCAD.Console.PrintMessage('Solver binary path: {} \n'.format(binary))
return binary
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
.format(name)
)
return None
def get_write_comments(name):
""" Check whether "write_comments" is set for solver.
Returns ``True`` if the "write_comments" setting/parameter is set for the
solver with the id *name*. Returns ``False`` otherwise. If the solver isn't
supported ``None`` is returned.
:param name: solver id as a ``str`` (see :mod:`femsolver.settings`)
"""
if name in _SOLVER_PARAM:
return _SOLVER_PARAM[name].get_write_comments()
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
.format(name)
)
return None
def get_custom_dir():
""" Get value for :term:`General/CustomDirectoryPath` parameter. """
param_group = FreeCAD.ParamGet(_GENERAL_PARAM)
return param_group.GetString("CustomDirectoryPath")
def get_dir_setting():
""" Return directory setting set by the user.
Return one of the three possible values of the :class:`DirSetting` enum
depending on the setting set in FreeCAD parameter system. Result dependes
on the values of :term:`General/UseTempDirectory`,
:term:`General/UseBesideDirectory` and :term:`General/UseCustomDirectory`.
"""
param_group = FreeCAD.ParamGet(_GENERAL_PARAM)
if param_group.GetBool("UseBesideDirectory"):
return DirSetting.BESIDE
elif param_group.GetBool("UseCustomDirectory"):
return DirSetting.CUSTOM
return DirSetting.TEMPORARY
class _SolverDlg(object):
""" Internal query logic for solver specific settings.
Each instance queries settings for one specific solver (e.g. Elmer) common
among all solvers. To clearify: There are a few settings that are useful
for every solver (e.g. where to find the solver binary) but the value and
the FreeCAD parameter path is different for each one. A instance of this
class contains all the solver specific paths needed. The settings can be
queried via the methods which use those path members to query the value for
the specific solver.
:ivar default:
Default binary name as a string preferably without a prefix path to
make it more generic (e.g. "ccx"). This only works if the binary can be
found via the PATH environment variable on linux or similar mechanisms
on other operating systems. Used if nothing else is specified by the
user.
:ivar param_path:
Parent param path (FreeCADs settings/parameter system) that contains
all settings for the specific solver.
:ivar use_default:
Param path identifying the "use_default" setting. Only specifie the
last part as the *param_path* is prepended to this value.
:ivar custom_path:
Param path identifying the "custom_path" setting. Only specifie the
last part as the *param_path* is prepended to this value.
"""
WRITE_COMMENTS_PARAM = "writeCommentsToInputFile"
def __init__(self, default, param_path, use_default, custom_path):
# set the parameter identifier
self.default = default
self.param_path = param_path
self.use_default = use_default
self.custom_path = custom_path
self.write_comments = "writeCommentsToInputFile"
# get the parameter object where the paramete are saved in
self.param_group = FreeCAD.ParamGet(self.param_path)
def get_binary(self):
# set the binary path to the FreeCAD defaults
# ATM pure unix shell commands without path names are used
# TODO see todo on use_default later in this module
binary = self.default
FreeCAD.Console.PrintLog("Solver binary path: {} \n".format(binary))
@@ -82,24 +203,9 @@ class _SolverDlg(object):
return find_bin(binary)
def get_write_comments(self):
return self.param_group.GetBool(self.write_comments, True)
return self.param_group.GetBool(self.WRITE_COMMENTS_PARAM, True)
"""
default:
default command to run the binary
this one is taken if the UseStandardXXXLocationis not given or set to True
param:
path where these settings are saved, in FEM normally one path in one Tab in Preferences GUI
use_default:
the UseStandardXXXLocation parameter identifier
if this parameter is set to True FreeCAD standards
for the binary are usedor FreeCAD tries to find the binary
TODO: see method setup_ccx in ccx tools module, which sets up ccx binary for various os
custom_path:
the xxxBinaryPath parameter identifier
binary path given by the user
"""
_SOLVER_PARAM = {
"Calculix": _SolverDlg(
default="ccx",
@@ -122,48 +228,3 @@ _SOLVER_PARAM = {
use_default="UseStandardZ88Location",
custom_path="z88BinaryPath"),
}
def get_binary(name):
if name in _SOLVER_PARAM:
binary = _SOLVER_PARAM[name].get_binary()
FreeCAD.Console.PrintMessage("Solver binary path: {} \n".format(binary))
return binary
else:
FreeCAD.Console.PrintError(
"Settings solver name: {} not found in "
"solver settings modules _SOLVER_PARAM dirctionary.\n"
.format(name)
)
return None
def get_write_comments(name):
if name in _SOLVER_PARAM:
return _SOLVER_PARAM[name].get_write_comments()
else:
FreeCAD.Console.PrintError(
"Settings solver name: {} not found in "
"solver settings modules _SOLVER_PARAM dirctionary.\n"
.format(name)
)
return None
# ******** working directory parameter ***********************************************************
def get_custom_dir():
param_group = FreeCAD.ParamGet(_GENERAL_PARAM)
return param_group.GetString("CustomDirectoryPath")
def get_dir_setting():
param_group = FreeCAD.ParamGet(_GENERAL_PARAM)
if param_group.GetBool("UseTempDirectory"):
return TEMPORARY
elif param_group.GetBool("UseBesideDirectory"):
return BESIDE
elif param_group.GetBool("UseCustomDirectory"):
return CUSTOM
## @}

View File

@@ -36,7 +36,7 @@ from os.path import join
def get_fem_test_home_dir(
):
return join(FreeCAD.getHomePath(), "Mod", "Fem", "femtest", "testfiles")
return join(FreeCAD.getHomePath(), "Mod", "Fem", "femtest", "data")
def get_fem_test_tmp_dir(

View File

@@ -28,8 +28,8 @@ from femtools import ccxtools
import FreeCAD
import ObjectsFem
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
from os.path import join
@@ -167,8 +167,8 @@ class TestCcxTools(unittest.TestCase):
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
from ..data.ccx.cube_mesh import create_nodes_cube
from ..data.ccx.cube_mesh import create_elements_cube
mesh = Fem.FemMesh()
ret = create_nodes_cube(mesh)
self.assertTrue(
@@ -380,7 +380,7 @@ class TestCcxTools(unittest.TestCase):
analysis.addObject(pressure_constraint)
mesh = Fem.FemMesh()
import femtest.testfiles.ccx.multimat_mesh as multimatmesh
import femtest.data.ccx.multimat_mesh as multimatmesh
multimatmesh.create_nodes(mesh)
multimatmesh.create_elements(mesh)
mesh_object = self.active_doc.addObject("Fem::FemMeshObject", self.mesh_name)
@@ -481,8 +481,8 @@ class TestCcxTools(unittest.TestCase):
analysis.addObject(material_object)
fcc_print("Checking FEM new mesh...")
from .testfiles.ccx.cube_mesh import create_nodes_cube
from .testfiles.ccx.cube_mesh import create_elements_cube
from ..data.ccx.cube_mesh import create_nodes_cube
from ..data.ccx.cube_mesh import create_elements_cube
mesh = Fem.FemMesh()
ret = create_nodes_cube(mesh)
self.assertTrue(ret, "Import of mesh nodes failed")
@@ -704,8 +704,8 @@ class TestCcxTools(unittest.TestCase):
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
from ..data.ccx.spine_mesh import create_nodes_spine
from ..data.ccx.spine_mesh import create_elements_spine
mesh = Fem.FemMesh()
ret = create_nodes_spine(mesh)
self.assertTrue(
@@ -1106,8 +1106,8 @@ class TestCcxTools(unittest.TestCase):
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
from ..data.ccx.Flow1D_mesh import create_nodes_Flow1D
from ..data.ccx.Flow1D_mesh import create_elements_Flow1D
mesh = Fem.FemMesh()
ret = create_nodes_Flow1D(mesh)
self.assertTrue(ret, "Import of mesh nodes failed")

View File

@@ -26,8 +26,8 @@
import FreeCAD
import ObjectsFem
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
class TestFemCommon(unittest.TestCase):

View File

@@ -26,7 +26,7 @@
import unittest
import FreeCAD
from femtest.utilstest import fcc_print
from .support_utils import fcc_print
class TestFemImport(unittest.TestCase):

View File

@@ -25,7 +25,7 @@
import FreeCAD
import unittest
from .utilstest import fcc_print
from .support_utils import fcc_print
from os.path import join

View File

@@ -26,8 +26,8 @@
import Fem
import FreeCAD
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
from os.path import join

View File

@@ -26,8 +26,8 @@
import FreeCAD
import ObjectsFem
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
class TestObjectCreate(unittest.TestCase):

View File

@@ -25,8 +25,8 @@
import FreeCAD
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
from os.path import join

View File

@@ -27,8 +27,8 @@ import FreeCAD
import ObjectsFem
import femsolver.run
import unittest
from . import utilstest as testtools
from .utilstest import fcc_print
from . import support_utils as testtools
from .support_utils import fcc_print
from os.path import join
@@ -127,8 +127,8 @@ class TestSolverFrameWork(unittest.TestCase):
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
from ..data.ccx.cube_mesh import create_nodes_cube
from ..data.ccx.cube_mesh import create_elements_cube
mesh = Fem.FemMesh()
ret = create_nodes_cube(mesh)
self.assertTrue(ret, "Import of mesh nodes failed")

View File

@@ -20,6 +20,13 @@
# * USA *
# * *
# ***************************************************************************
""" Collection of functions for the Fem module.
This module contains function for managing a analysis and all the different
types of objects it contains, helper for executing a simulation, function for
extracting relevant parts of geometry and a few unrelated function useful at
various places in the Fem module.
"""
__title__ = "FEM Utilities"
@@ -38,16 +45,39 @@ if FreeCAD.GuiUp:
from PySide import QtGui
# analysis and its members
def createObject(doc, name, proxy, viewProxy):
def createObject(doc, name, proxy, viewProxy=None):
""" Add python object to document using python type string.
Add a document object suitable for the *proxy* and the *viewProxy* to *doc*
and attach it to the *proxy* and the *viewProxy*. This function can only be
used with python proxies that specify their C++ type via the BaseType class
member (e.g. Cube.BaseType). If there already exists a object with *name* a
suitable unique name is generated. To auto generate a name pass ``""``.
:param doc: document object to which the object is added
:param name: string of the name of new object in *doc*, use
``""`` to generate a name
:param proxy: python proxy for new object
:param viewProxy: view proxy for new object
:returns: reference to new object
"""
obj = doc.addObject(proxy.BaseType, name)
proxy(obj)
if FreeCAD.GuiUp:
if FreeCAD.GuiUp and viewProxy is not None:
viewProxy(obj.ViewObject)
return obj
def findAnalysisOfMember(member):
""" Find Analysis the *member* belongs to.
:param member: a document object
:returns:
If a analysis that contains *member* can be found a reference is returned.
If no such object exists in the document of *member*, ``None`` is returned.
"""
if member is None:
raise ValueError("Member must not be None")
for obj in member.Document.Objects:
@@ -69,6 +99,22 @@ def _searchGroups(member, objs):
def get_member(analysis, t):
""" Return list of all members of *analysis* of type *t*.
Search *analysis* for members of type *t*. This method checks the custom
python typesytem (BaseType class property) used by the Fem module if
possible. If the object does not use the python typesystem the usual
isDerivedFrom from the C++ dynamic type system is used.
:param analysis: only objects part of this analysis are considered
:param t: only objects of this type are returned
:note:
Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the
type is just checked for equality. If the type doesn't match
``obj.isDerivedFrom`` is called as usual. See
https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
"""
if analysis is None:
raise ValueError("Analysis must not be None")
matching = []
@@ -81,12 +127,58 @@ def get_member(analysis, t):
def get_single_member(analysis, t):
""" Return one object of type *t* and part of *analysis*.
Search *analysis* for members of type *t* and return the first one that's
found. This method checks the custom python typesytem (BaseType class
property) used by the Fem module if possible. If the object doesn't use the
python typesystem the usual isDerivedFrom from the C++ dynamic type system
is used.
:param analysis: only objects part of this analysis are considered
:param t: only a object of this type is returned
:note:
Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the
type is just checked for equality. If the type doesn't match
``obj.isDerivedFrom`` is called as usual. See
https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
"""
objs = get_member(analysis, t)
return objs[0] if objs else None
# collect analysis members used in CalculiX and Z88
def get_several_member(analysis, t):
""" Get members and pack them for Calculix/Z88.
Collect members by calling :py:func:`get_member` and pack them into a
data structure that can be consumed by calculix and Z88 solver modules.
:param analysis: see :py:func:`get_member`
:param t: see :py:func:`get_member`
:returns:
A list containing one dict per member. Each dict has two entries:
``"Object"`` and ``"RefShapeType"``. ``dict["Object"]`` contains the
member document object. ``dict["RefShapeType"]`` contains the shape type
of the *References* property of the member (used by constraints) as a
string ("Vertex", "Edge", "Face" or "Solid"). If the member doesn't have a
*References* property ``dict["RefShapeType"]`` is the empty string ``""``.
:note:
Undefined behaviour if one of the members has a *References* property
which is empty.
:note:
Undefined behaviour if the type of the references of one object are not
all the same.
:note:
Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the
type is just checked for equality. If the type doesn't match
``obj.isDerivedFrom`` is called as usual. See
https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
"""
# if no member is found, an empty list is returned
objs = get_member(analysis, t)
members = []
@@ -99,6 +191,14 @@ def get_several_member(analysis, t):
def get_mesh_to_solve(analysis):
""" Find one and only mesh object of *analysis*.
:returns:
A tuple ``(object, message)``. If and only if the analysis contains
exactely one mesh object the first value of the tuple is the mesh document
object. Otherwise the first value is ``None`` and the second value is a
error message indicating what went wrong.
"""
mesh_to_solve = None
for m in analysis.Group:
if m.isDerivedFrom("Fem::FemMeshObject") and not is_of_type(m, "Fem::FemMeshResult"):
@@ -114,27 +214,46 @@ def get_mesh_to_solve(analysis):
# typeID and object type defs
def type_of_obj(obj):
"""returns objects TypeId (C++ objects) or Proxy.Type (Python objects)"""
""" Return type of *obj* honoring the special typesystem of Fem.
Python objects of the Fem workbench define their type via a class member
``<Class>.Type``. Return this type if the property exists. If not return
the conventional ``TypeId`` value.
:para obj: a document object
"""
if hasattr(obj, "Proxy") and hasattr(obj.Proxy, "Type"):
return obj.Proxy.Type
return obj.TypeId
def is_of_type(obj, ty):
"""returns True if an object is of
a given TypeId (C++ objects) or Proxy.Type (Python Features)"""
# only returns true if the exact TypeId is given.
# For FeaturPythons the Proxy.Type has to be given.
# Keep in mind the TypeId for them is the TypeId from the C++ father class
""" Compare type of *obj* with *ty* honoring Fems typesystem.
See :py:func:`type_of_obj` for more info about the special typesystem of
the Fem module.
:returns:
``True`` if *obj* is of type *ty*, ``False`` otherwise. Type must match
exactely: Derived objects are not considered to be of type of one of their
super classes.
"""
return type_of_obj(obj) == ty
def is_derived_from(obj, t):
"""returns True if an object or its inheritance chain is of a
given TypeId (C++ objects) or Proxy.Type (Python objects)"""
# returns true for all FEM objects if given t == "App::DocumentObject"
# since this is a father of the given object
# see https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
""" Check if *obj* is derived from *t* honoring Fems typesytem.
Essentially just call ``obj.isDerivedFrom(t)`` and return it's value. For
objects using Fems typesystem (see :py:func:`type_of_obj`) return always
True if the Fem type is equal to *t*.
:note:
Inheritance of Fem types is not checked. If *obj* uses Fems typesystem the
type is just checked for equality. If the type doesn't match
``obj.isDerivedFrom`` is called as usual. See
https://forum.freecadweb.org/viewtopic.php?f=10&t=32625
"""
if (hasattr(obj, "Proxy") and hasattr(obj.Proxy, "Type") and obj.Proxy.Type == t):
return True
return obj.isDerivedFrom(t)
@@ -143,8 +262,16 @@ def is_derived_from(obj, t):
# ************************************************************************************************
# working dir
def get_pref_working_dir(solver_obj):
# _dirTypes from run are not used
# be aware beside could get an error if the document has not been saved
""" Return working directory for solver honoring user settings.
:throws femsolver.run.MustSaveError:
If user setting is set to BESIDE and the document isn't saved.
:note:
Not working correctely for most cases because this circumvents directory
caching of the solver framework. For solver use getMachine from run.py
instead.
"""
dir_setting = settings.get_dir_setting()
if dir_setting == settings.TEMPORARY:
setting_working_dir = get_temp_dir(solver_obj)
@@ -255,6 +382,13 @@ def get_part_to_mesh(mesh_obj):
def getBoundBoxOfAllDocumentShapes(doc):
""" Calculate bounding box containing all objects inside *doc*.
:returns:
A bounding box containing all objects that have a *Shape* attribute (all
Part and PartDesign objects). If the document contains no such objects or
no objects at all return ``None``.
"""
overalboundbox = None
for o in doc.Objects:
# netgen mesh obj has an attribute Shape which is an Document obj, which has no BB
@@ -271,6 +405,16 @@ def getBoundBoxOfAllDocumentShapes(doc):
def getSelectedFace(selectionex):
""" Return selected face if exactly one face is selected.
:returns:
The selected face as a ``Part::TopoShape`` if exactly one face is selected.
Otherwise return ``None``.
:param selectionex:
A list of selection object like the one Gui.Selection.getSelectionEx()
returns.
"""
aFace = None
# print(selectionex)
if len(selectionex) != 1:
@@ -290,14 +434,27 @@ def getSelectedFace(selectionex):
def get_refshape_type(fem_doc_object):
# returns the reference shape type
# for force object:
# in GUI defined frc_obj all frc_obj have at least one ref_shape
# and ref_shape have all the same shape type
# for material object:
# in GUI defined material_obj could have no RefShape and RefShapes could be different type
# we're going to need the RefShapes to be the same type inside one fem_doc_object
# TODO: check if all RefShapes inside the object really have the same type
""" Return shape type the constraints references.
Determine single shape type of references of *fem_doc_object* which must be
a constraint (=have a *References* property). All references must be of the
same type which is than returned as a string. A type can be "Vertex",
"Edge", "Face" or "Solid".
:param fem_doc_object:
A constraint object with a *References* property.
:returns:
A string representing the shape type ("Vertex", "Edge", "Face" or
"Solid"). If *fem_doc_object* isn't a constraint ``""`` is returned.
:note:
Undefined behaviour if the type of the references of one object are
not all the same.
:note:
Undefined behaviour if constraint contains no references (empty list).
"""
import femmesh.meshtools as FemMeshTools
if hasattr(fem_doc_object, "References") and fem_doc_object.References:
first_ref_obj = fem_doc_object.References[0]
@@ -315,6 +472,12 @@ def get_refshape_type(fem_doc_object):
def pydecode(bytestring):
""" Return *bytestring* as a unicode string for python 2 and 3.
For python 2 *bytestring* is converted to a string of type ``unicode``. For
python 3 it is returned as is because it uses unicode for it's ``str`` type
already.
"""
if sys.version_info.major < 3:
return bytestring
else: