MMGUtility
Contents |
What is MMG?
Mmg is an open source software for simplicial remeshing. MMG main page[1], and you can download the code in GitHub[2]
- It provides 3 applications and 4 libraries:
- The mmg2d application and the libmmg2d library: adaptation and optimization of a two-dimensional triangulation and generation of a triangulation from a set of points or from given boundary edges
- The mmgs application and the libmmgs library: adaptation and optimization of a surface triangulation and isovalue discretization
- The mmg3d application and the libmmg3d library: adaptation and optimization of a tetrahedral mesh and implicit domain meshing
- The libmmg library gathering the libmmg2d, libmmgs and libmmg3d libraries
- It uses a LGPL[3] license and it has been integrated in Kratos via the mmg_utility.h in the MeshingApplication.
Important: For use it you need to download first (look in the installation section)
- It is used like a process, using the mmg_process.py in the MeshingApplication.
- There are basically two different types of re-meshing strategies (both of them compatibles with an anisotropic re-meshing):
- Level-Set: This re-meshing technique is based in the gradient of the DISTANCE function, and can be used to re-mesh when you are getting closer to the reference geometry.
- Hessian: This re-meshing technique is based in the computation of the Hessian of any variable, in the case of more than one variable or a variable by components is considered them the intersection of the corresponding tensors is computed.
How can I install this library?
The installation of the library is fortunately quite straightforward thanks to the marvels of the configure scripts. The easiest way is the following one, because requires the minimal effort; of course if you have expertise you can find an alternative way to install the library:
- Go to MeshingApplication/custom_external_libraries/
- Here you can see the mmg folder, but it is empty. You have the README.txt, where the installation is explained, and the build folder, where the configure.sh script can be found.
- Rename the folder to anything else and execute (make sure you have installed git first):
git clone https://github.com/MmgTools/mmg.git
- Then copy the content of the build folder from the old mmg folder to the new mmg folder. Go to the build folder and execute:
sh configure.sh
- Once the compilation is done go to the main Kratos folder and go to your cmake_build folder. Here you modify the configure.sh adding the following lines (modify the kartos_dir for your current Kratos installation directory):
-DINCLUDE_MMG=ON \ -DMMG_INCLUDE_DIR="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/include/"\ -DMMG2D_INCLUDE_DIR="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/include/mmg/mmg2d/"\ -DMMG3D_INCLUDE_DIR="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/include/mmg/mmg3d/"\ -DMMGS_INCLUDE_DIR="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/include/mmg/mmgs/"\ -DMMG_LIBRARY="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/lib/libmmg.a" \ -DMMG2D_LIBRARY="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/lib/libmmg2d.a" \ -DMMG3D_LIBRARY="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/lib/libmmg3d.a" \ -DMMGS_LIBRARY="kratos_dir/applications/MeshingApplication/custom_external_libraries/mmg/lib/libmmgs.a" \
- After that recompile Kratos using again:
sh configure.sh
Once it is compiled
Go to the folder tests in the MeshingApplication and run:
python3 test_MeshingApplication.py
You should get an OK, if you don't get an OK there is something wrong:
- Check that your compilation is the correct one
- Follow again all the steps
- Check that the configure.sh it is correctly compiled
- If you get an Unexpected error:
- This problem is because your machine is not compatible with the library, unfortunately this means that you need to wait until the problem is solved
How can I used this library?
Manually
Taking for example the following mesh: File:Remesh sphere.tar.gz, and using the following python script (included in the previous compressed file) it is possible to re-mesh a very coarsed mesh of a sphere into a fine an anisotropic sphere.
# We import the libraies from __future__ import print_function, absolute_import, division #makes KratosMultiphysics backward compatible with python 2.6 and 2.7 import KratosMultiphysics import KratosMultiphysics.MeshingApplication as MeshingApplication # We create the model part main_model_part = KratosMultiphysics.ModelPart("MainModelPart") main_model_part.ProcessInfo.SetValue(KratosMultiphysics.DOMAIN_SIZE, 3) # We add the variables needed main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.DISTANCE) main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.DISTANCE_GRADIENT) main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.NODAL_H) main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.NODAL_AREA) # We import the model main_model_part KratosMultiphysics.ModelPartIO("coarse_sphere").ReadModelPart(main_model_part) # We calculate the gradient of the distance variable local_gradient = KratosMultiphysics.ComputeNodalGradientProcess3D(main_model_part, KratosMultiphysics.DISTANCE, KratosMultiphysics.DISTANCE_GRADIENT, KratosMultiphysics.NODAL_AREA) local_gradient.Execute() # We set to zero the metric ZeroVector = KratosMultiphysics.Vector(6) ZeroVector[0] = 0.0 ZeroVector[1] = 0.0 ZeroVector[2] = 0.0 ZeroVector[3] = 0.0 ZeroVector[4] = 0.0 ZeroVector[5] = 0.0 for node in main_model_part.Nodes: node.SetValue(MeshingApplication.MMG_METRIC, ZeroVector) # We define a metric using the ComputeLevelSetSolMetricProcess metric_process = MeshingApplication.ComputeLevelSetSolMetricProcess3D( main_model_part, 0.1, # minimal_size False, # enforce_current KratosMultiphysics.DISTANCE_GRADIENT, # gradient_variable 0.01, # hmin_over_hmax_anisotropic_ratio 0.5, # boundary_layer_max_distance "Linear" # interpolation ) metric_process.Execute() # We create the remeshing utility MmgUtility = MeshingApplication.MmgUtility3D(main_model_part, "", 0) # We remesh MmgUtility.RemeshModelPart(False, 1000) # Finally we export to GiD from gid_output_process import GiDOutputProcess gid_output = GiDOutputProcess(main_model_part, "gid_output", KratosMultiphysics.Parameters(""" { "result_file_configuration" : { "gidpost_flags": { "GiDPostMode": "GiD_PostBinary", "WriteDeformedMeshFlag": "WriteUndeformed", "WriteConditionsFlag": "WriteConditions", "MultiFileFlag": "SingleFile" }, "nodal_results" : [] } } """) ) gid_output.ExecuteInitialize() gid_output.ExecuteBeforeSolutionLoop() gid_output.ExecuteInitializeSolutionStep() gid_output.PrintOutput() gid_output.ExecuteFinalizeSolutionStep() gid_output.ExecuteFinalize()
The metric can be calculated by hand if you want, for example to get the same result than the previous script:
# We import the libraies from __future__ import print_function, absolute_import, division #makes KratosMultiphysics backward compatible with python 2.6 and 2.7 import KratosMultiphysics import KratosMultiphysics.MeshingApplication as MeshingApplication # We create the model part main_model_part = KratosMultiphysics.ModelPart("MainModelPart") main_model_part.ProcessInfo.SetValue(KratosMultiphysics.DOMAIN_SIZE, 3) # We add the variables needed main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.DISTANCE) main_model_part.AddNodalSolutionStepVariable(KratosMultiphysics.NODAL_H) # We import the model main_model_part KratosMultiphysics.ModelPartIO("coarse_sphere").ReadModelPart(main_model_part) # We know that the gradient is unitary and in X direction UnityVector = KratosMultiphysics.Vector(3) UnityVector[0] = 1.0 UnityVector[1] = 0.0 UnityVector[2] = 0.0 # We set to zero the metric MetricVector = KratosMultiphysics.Vector(6) for node in main_model_part.Nodes: # Calculate the element size distance = node.GetSolutionStepValue(KratosMultiphysics.DISTANCE, 0); nodal_h = node.GetSolutionStepValue(KratosMultiphysics.NODAL_H, 0); element_size = 0.1 if (abs(distance) > 0.5): element_size = nodal_h # Calculate anisotropic ratio ratio = 1.0 if (abs(distance) < 0.5): ratio = 0.01 + (abs(distance)/0.5) * (1.0 - 0.01); # We get the gradient gradient_value = UnityVector # Finally we calculate the metric coeff0 = 1.0/(element_size * element_size); coeff1 = coeff0/(ratio * ratio); v0v0 = gradient_value[0]*gradient_value[0]; v0v1 = gradient_value[0]*gradient_value[1]; v0v2 = gradient_value[0]*gradient_value[2]; v1v1 = gradient_value[1]*gradient_value[1]; v1v2 = gradient_value[1]*gradient_value[2]; v2v2 = gradient_value[2]*gradient_value[2]; MetricVector[0] = coeff0*(1.0 - v0v0) + coeff1*v0v0 MetricVector[1] = coeff0*( - v0v1) + coeff1*v0v1 MetricVector[2] = coeff0*( - v0v2) + coeff1*v0v2 MetricVector[3] = coeff0*(1.0 - v1v1) + coeff1*v1v1 MetricVector[4] = coeff0*( - v1v2) + coeff1*v1v2 MetricVector[5] = coeff0*(1.0 - v2v2) + coeff1*v2v2 node.SetValue(MeshingApplication.MMG_METRIC, MetricVector) # We create the remeshing utility MmgUtility = MeshingApplication.MmgUtility3D(main_model_part, "", 0) # We remesh MmgUtility.RemeshModelPart(False, 1000) # Finally we export to GiD from gid_output_process import GiDOutputProcess gid_output = GiDOutputProcess(main_model_part, "gid_output", KratosMultiphysics.Parameters(""" { "result_file_configuration" : { "gidpost_flags": { "GiDPostMode": "GiD_PostBinary", "WriteDeformedMeshFlag": "WriteUndeformed", "WriteConditionsFlag": "WriteConditions", "MultiFileFlag": "SingleFile" }, "nodal_results" : [] } } """) ) gid_output.ExecuteInitialize() gid_output.ExecuteBeforeSolutionLoop() gid_output.ExecuteInitializeSolutionStep() gid_output.PrintOutput() gid_output.ExecuteFinalizeSolutionStep() gid_output.ExecuteFinalize()
Using the process
As said before, the re-meshing is based in a process structure, in this case the 'MainKratos.py' files must be modified (you can take as reference one present in the next section). The parameters that define this process are the following ones:
## Settings string in json format default_parameters = KratosMultiphysics.Parameters(""" { "output_file_name" : "out", "model_part_name" : "MainModelPart", "strategy" : "LevelSet", "level_set_strategy_parameters" :{ "scalar_variable" : "DISTANCE", "gradient_variable" : "DISTANCE_GRADIENT" }, "hessian_strategy_parameters" :{ "metric_variable" : ["DISTANCE"], "interpolation_error" : 0.04, "mesh_dependent_constant" : 0.0 }, "enforce_current" : true, "initial_step" : 1, "step_frequency" : 0, "automatic_remesh" : true, "automatic_remesh_parameters" :{ "automatic_remesh_type" : "Ratio", "min_size_ratio" : 1.0, "max_size_ratio" : 3.0, "refer_type" : "Mean", "min_size_current_percentage" : 50.0, "max_size_current_percentage" : 98.0 }, "initial_remeshing" : true, "fix_contour_model_parts" : [], "minimal_size" : 0.1, "maximal_size" : 10.0, "anisotropy_remeshing" : true, "anisotropy_parameters":{ "hmin_over_hmax_anisotropic_ratio" : 0.01, "boundary_layer_max_distance" : 1.0, "boundary_layer_min_size_ratio" : 2.0, "interpolation" : "Linear" }, "save_external_files" : false, "max_number_of_searchs" : 1000, "echo_level" : 3 } """)
The meaning of each of the parameters is the following one:
- output_file_name: This is the name of *.sol and *.mesh generated in the case you chose to activate save_external_files.
- model_part_name: This is important, it should correspond with the name of your actual main model part.
- strategy: The type of strategy to chose, or LevelSet or Hessian.
- If you chose the LevelSet strategy:
- scalar_variable:The scalar variable used to calculate the gradient and remesh.
- gradient_variable: The variable where this gradient will be stored.
- If you chose the Hessian strategy:
- metric_variable: The list of variables that can be considered to calculate the metrics of re-meshing.
- interpolation_error: The interpolation error considered in the re-mesh.
- mesh_dependent_constant: This value is automatically calculated if set to 0, but many definitions can be found in the literature.
- enforce_current: If the current size will be enforce as minimum.
- initial_step: The first step to consider to count for the re-meshing.
- step_frequency: The re-mesh will be performed each this number of steps.
- automatic_remesh: If to re-mesh according ratios or manually.
- automatic_remesh_type: If the automatic re-meshed is performed according a ratio or statistically
- min_size_ratio: The proportional ratio of the minimum respect the mean or median NODAL_H
- max_size_ratio: The proportional ratio of the maximum respect the mean or median NODAL_H
- refer_type: This can be chosen between the mean or the median, the mean is the default value.
- min_size_current_percentage: When the minimum size is defined statistically, this is the minimum size percentile
- max_size_current_percentage: When the maximum size is defined statistically, this is the maximum size percentile
- initial_remeshing: If to perform some remeshing in the initialization process
- fix_contour_model_parts: This is a list with the submodelparts of the contour where you desire to fix the nodes.
- minimal_size: When the minimum size is specified manually
- maximal_size: When the maximum size is specified manually
- anisotropy_remeshing: If the anisotropy should be considered in the computation of the remeshing
- hmin_over_hmax_anisotropic_ratio: The minimal anisotropic ratio considered (NOTE: 0 is the maximum value of anisotropy, 1 is not anisotropic at all)
- boundary_layer_max_distance: When the threshold value is specified manually
- boundary_layer_min_size_ratio: When the threshold value is specified using a ratio of reference
- interpolation: The interpolation algorithm used in the anisotropic area. By default is linear, which means that is increasing until the value to the reference is zero.
- save_external_files: This activates the saving of the resulting meshes (in *.mesh and *.sol files)
- max_number_of_searchs: This is the max. number of search that can be done in the value interpolation process (when values are interpolated from the old mesh to the new mesh)
- echo_level: This sets the echo_level, 0 for no output at all, 3 for standard output, 4 for awesome output.
Can you show us a little example? Of course, in the File:Sphere remeshed.gid.tar.gz you can find an example using the process that you can run in your machine. This problem consists in a continuous re-meshing using the Hessian of the velocity as reference.
The resulting output should look something similar to the following[4].
The problems presented in the tests can be used as reference too.