Skip to content

Commit

Permalink
Merge pull request #12023 from KratosMultiphysics/feature/linear_to_q…
Browse files Browse the repository at this point in the history
…uadratic_tetrahedra_modeler

[Meshing] Adding linear to quadratic tets modeler
  • Loading branch information
jcotela authored Feb 21, 2024
2 parents 72e377e + af0a38e commit 78955e5
Show file tree
Hide file tree
Showing 12 changed files with 426 additions and 14 deletions.
1 change: 1 addition & 0 deletions applications/MeshingApplication/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ endif(CMAKE_UNITY_BUILD MATCHES ON)

# Add to the KratosMultiphisics Python module
kratos_python_install(${INSTALL_PYTHON_USING_LINKS} ${CMAKE_CURRENT_SOURCE_DIR}/MeshingApplication.py KratosMultiphysics/MeshingApplication/__init__.py )
kratos_python_install(${INSTALL_PYTHON_USING_LINKS} ${CMAKE_CURRENT_SOURCE_DIR}/python_registry_lists.py KratosMultiphysics/MeshingApplication/python_registry_lists.py )

# Install python files
get_filename_component (CURRENT_DIR_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
Expand Down
4 changes: 4 additions & 0 deletions applications/MeshingApplication/MeshingApplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
application_name = "KratosMeshingApplication"

_ImportApplication(application, application_name)

from KratosMultiphysics import python_registry_utilities
from . import python_registry_lists
python_registry_utilities.RegisterAll("KratosMultiphysics.MeshingApplication", python_registry_lists)
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,28 @@
#include "custom_utilities/linear_to_quadratic_tetrahedra_mesh_converter_utility.h"

namespace Kratos {

void LinearToQuadraticTetrahedraMeshConverter::LocalConvertLinearToQuadraticTetrahedraMesh(
bool RefineOnReference,
bool InterpolateInternalVariables)
bool RefineOnReference,
bool InterpolateInternalVariables)
{
//checking all elements to be refined are linear tets
block_for_each(mModelPart.Elements(), [&](Element element) {
if(element.Has(SPLIT_ELEMENT) && element.GetValue(SPLIT_ELEMENT)){
KRATOS_ERROR_IF_NOT(element.GetGeometry().GetGeometryType() == GeometryData::KratosGeometryType::Kratos_Tetrahedra3D4) << "Element #" << element.Id() << " is not a linear tetrahedron" << std::endl;
block_for_each(mModelPart.Elements(), [](const Element& r_element) {
if(r_element.Has(SPLIT_ELEMENT) && r_element.GetValue(SPLIT_ELEMENT)){
KRATOS_ERROR_IF_NOT(r_element.GetGeometry().GetGeometryType() == GeometryData::KratosGeometryType::Kratos_Tetrahedra3D4) << "Element #" << r_element.Id() << " is not a linear tetrahedron" << std::endl;
}
});
block_for_each(mModelPart.Conditions(), [](const Condition& r_condition) {
if(r_condition.Has(SPLIT_ELEMENT) && r_condition.GetValue(SPLIT_ELEMENT)){
KRATOS_ERROR_IF_NOT(r_condition.GetGeometry().GetGeometryType() == GeometryData::KratosGeometryType::Kratos_Triangle3D3) << "Condition #" << r_condition.Id() << " is not a linear tetrahedron" << std::endl;
}
});
LocalRefineMesh(RefineOnReference, InterpolateInternalVariables);
}
}

Tetrahedra3D10<Node> LinearToQuadraticTetrahedraMeshConverter::GenerateTetrahedra(
ModelPart& rThisModelPart,
const std::vector<int>& rNodeIds)
ModelPart& rThisModelPart,
const std::vector<int>& rNodeIds)
{
unsigned int i0 = rNodeIds[0];
unsigned int i1 = rNodeIds[1];
Expand Down Expand Up @@ -59,8 +64,8 @@ namespace Kratos {
}

Triangle3D6<Node> LinearToQuadraticTetrahedraMeshConverter::GenerateTriangle3D6(
ModelPart& rThisModelPart,
const array_1d<int, 6>& rNodeIds)
ModelPart& rThisModelPart,
const array_1d<int, 6>& rNodeIds)
{
unsigned int i0 = rNodeIds[0];
unsigned int i1 = rNodeIds[1];
Expand Down Expand Up @@ -120,7 +125,7 @@ namespace Kratos {
//This method only copies the current information to the new element
InterpolateInteralVariables(0, *it.base(), p_element, r_current_process_info);
}

// Transfer elemental variables to new element
p_element->GetData() = it->GetData();
p_element->GetValue(SPLIT_ELEMENT) = false;
Expand Down Expand Up @@ -168,7 +173,7 @@ namespace Kratos {
// GlobalPointersVector< Element >& children = p_element->GetValue(NEIGHBOUR_ELEMENTS);
auto& children = p_element->GetValue(NEIGHBOUR_ELEMENTS);
p_element = children[0].shared_from_this();
}
}
}

//Recursively for all subModelParts
Expand Down Expand Up @@ -239,7 +244,7 @@ namespace Kratos {
// GlobalPointersVector< Condition >& children = p_cond->GetValue(NEIGHBOUR_CONDITIONS);
auto& children = p_cond->GetValue(NEIGHBOUR_CONDITIONS);
p_cond = children[0].shared_from_this();
}
}
}
for (ModelPart::SubModelPartIterator i_submodelpart = rThisModelPart.SubModelPartsBegin();
i_submodelpart != rThisModelPart.SubModelPartsEnd(); i_submodelpart++)
Expand Down
11 changes: 11 additions & 0 deletions applications/MeshingApplication/python_registry_lists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
python_modelers_to_be_registered = [
"modelers.convert_linear_tetrahedra_to_quadratic_modeler.ConvertLinearTetrahedraToQuadraticModeler",
]

python_operations_to_be_registered = []

python_processes_to_be_registered = []

python_stages_to_be_registered = []

python_orchestrators_to_be_registered = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import KratosMultiphysics
from KratosMultiphysics import MeshingApplication as Meshing

class ConvertLinearTetrahedraToQuadraticModeler(KratosMultiphysics.Modeler):
"""
This class is a modeler in KratosMultiphysics that converts linear tetrahedral (tet) elements to quadratic tet elements within a specified model part.
Attributes:
model (KratosMultiphysics.Model): The Kratos model containing the model part to be modified.
settings (KratosMultiphysics.Parameters): Settings for the conversion process.
Methods:
__init__(model, settings): Constructor for the class.
SetupModelPart(): Performs the conversion from linear to quadratic tet elements.
__GetDefaultSettings(): Provides default settings for the modeler.
__str__(): String representation of the class.
Factory(model, settings): Factory method to create an instance of the class.
"""

def __init__(self, model, settings):
"""
Constructor for the ConvertLinearTetrahedraToQuadraticModeler class.
Args:
model (KratosMultiphysics.Model): The Kratos model containing the model part to be modified.
settings (KratosMultiphysics.Parameters): Configuration settings for the modeler.
The constructor initializes the modeler with the provided model and settings, and validates and assigns default settings.
"""
super().__init__(model, settings)
settings.ValidateAndAssignDefaults(self.__GetDefaultSettings())
self.model = model
self.settings = settings

def SetupModelPart(self):
"""
Converts the specified model part's linear tet elements to quadratic tets.
Raises:
Exception: If the operation is attempted in a distributed (MPI) run or if the input elements are not linear tets (4 nodes).
This method checks the model part for compatibility, sets necessary variables, and calls the utility function for conversion. It also handles the replacement of elements and conditions based on provided settings.
"""
super().SetupModelPart()

if KratosMultiphysics.IsDistributedRun():
raise Exception("ConvertLinearTetrahedraToQuadraticModeler is not MPI-ready")

model_part = self.model[self.settings["model_part_name"].GetString()]
if model_part != model_part.GetRootModelPart():
raise Exception(f"A root ModelPart is required, got SubModelPart {model_part.FullName()}")

KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
KratosMultiphysics.SPLIT_ELEMENT,
True,
model_part.Elements)
KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
KratosMultiphysics.SPLIT_ELEMENT,
True,
model_part.Conditions)

Meshing.LinearToQuadraticTetrahedraMeshConverter(model_part).LocalConvertLinearToQuadraticTetrahedraMesh(False, False)

element_name = self.settings["element_name"].GetString()
condition_name = self.settings["condition_name"].GetString()
if element_name or condition_name:
replace_settings = KratosMultiphysics.Parameters("{}")
replace_settings.AddString("element_name", element_name)
replace_settings.AddString("condition_name", condition_name)
KratosMultiphysics.ReplaceElementsAndConditionsProcess(model_part, replace_settings).Execute()

def __GetDefaultSettings(self):
"""
Provides the default settings for the modeler.
Returns:
KratosMultiphysics.Parameters: The default settings as a Parameters object.
These settings include the name of the model part to be modified and the name of the element to use for replacement, if specified.
"""
return KratosMultiphysics.Parameters('''{
"model_part_name" : "main_model_part",
"element_name" : "",
"condition_name": ""
}''')

def __str__(self):
"""
String representation of the ConvertLinearTetrahedraToQuadraticModeler class.
Returns:
str: A string describing the class.
"""
return "ConvertLinearTetrahedraToQuadraticModeler"
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from test_local_refine_triangle_conditions import TestLocalRefineTriangleMeshConditions as TTestLocalRefineTriangleMeshConditions
from test_local_refine_only_on_boundaries import TestLocalRefineOnlyOnBoundaries as TTestLocalRefineOnlyOnBoundaries
from test_gradual_variable_interpolation_process import TestGradualVariableInterpolationProcess as TTestGradualVariableInterpolationProcess
from test_convert_linear_tetrahedra_to_quadratic_modeler import TestConvertLinearTetrahedraToQuadraticModeler
## NIGHTLY TESTS

## VALIDATION TESTS
Expand All @@ -43,6 +44,8 @@ def AssembleTestSuites():
smallSuite.addTest(TTestLocalRefineTriangleMeshConditions('test_refine_condition_mesh'))
smallSuite.addTest(TTestLocalRefineOnlyOnBoundaries('test_refine_on_boundary_edges'))
smallSuite.addTest(TTestGradualVariableInterpolationProcess('test_gradual_variable_interpolation_process'))
smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([
TestConvertLinearTetrahedraToQuadraticModeler]))
if hasattr(MeshingApplication, "TetrahedraReconnectUtility") :
smallSuite.addTest(TTestRedistance('test_refine_all'))
smallSuite.addTest(TTestRedistance('test_refine_half'))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from importlib import import_module
from pathlib import Path

import KratosMultiphysics as kratos

from KratosMultiphysics import KratosUnittest
from KratosMultiphysics.MeshingApplication.modelers.convert_linear_tetrahedra_to_quadratic_modeler import ConvertLinearTetrahedraToQuadraticModeler


class TestConvertLinearTetrahedraToQuadraticModeler(KratosUnittest.TestCase):

def setUp(self):
self.model = kratos.Model()
model_part = self.model.CreateModelPart("main_model_part")
model_part.ProcessInfo.SetValue(kratos.DOMAIN_SIZE, 3)

work_dir = Path(__file__).parent.absolute()
mdpa_io = kratos.ModelPartIO(work_dir / "cube_with_5_faces")
mdpa_io.ReadModelPart(model_part)


def make_modeler(self, parameters: kratos.Parameters):
registry_data = kratos.Registry[
"Modelers.KratosMultiphysics.MeshingApplication.ConvertLinearTetrahedraToQuadraticModeler"
]
module = import_module(registry_data["ModuleName"])
return getattr(module, registry_data["ClassName"])(self.model, parameters)


def test_creation_from_registry(self):
modeler = self.make_modeler(kratos.Parameters('''{
"model_part_name": "main_model_part"
}'''))

self.assertIsInstance(modeler, ConvertLinearTetrahedraToQuadraticModeler)


def test_quadratic_refinement(self):

model_part = self.model.GetModelPart("main_model_part")

self.assertEqual(model_part.NumberOfNodes(), 64)
self.assertEqual(model_part.NumberOfElements(), 162)
self.assertEqual(model_part.NumberOfConditions(), 90)
self.assertEqual(len(model_part.Elements[1].GetNodes()), 4)
self.assertEqual(len(model_part.Conditions[163].GetNodes()), 3)

modeler = ConvertLinearTetrahedraToQuadraticModeler(
self.model,
kratos.Parameters('''{
"model_part_name": "main_model_part"
}'''))

modeler.SetupModelPart()

self.assertEqual(model_part.NumberOfNodes(), 343)
self.assertEqual(model_part.NumberOfElements(), 162)
self.assertEqual(model_part.NumberOfConditions(), 90)
self.assertEqual(len(model_part.Elements[1].GetNodes()), 10)
self.assertEqual(len(model_part.Conditions[163].GetNodes()), 6)


def test_root_required(self):

modeler = ConvertLinearTetrahedraToQuadraticModeler(
self.model,
kratos.Parameters('''{
"model_part_name": "main_model_part.MainPart.VolumeParts.Body1"
}'''))

msg = "A root ModelPart is required, got SubModelPart main_model_part.MainPart.VolumeParts.Body1"
with self.assertRaisesRegex(Exception, msg):
modeler.SetupModelPart()



if __name__ == "__main__":
KratosUnittest.main()
4 changes: 4 additions & 0 deletions kratos/python/add_geometries_to_python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ void AddGeometriesToPython(pybind11::module& m)
.def("PointsNumber", &GeometryType::PointsNumber)
.def("PointsNumberInDirection", &GeometryType::PointsNumberInDirection)
.def("PolynomialDegree", &GeometryType::PolynomialDegree)
// Geometry data
.def("GetDefaultIntegrationMethod", &GeometryType::GetDefaultIntegrationMethod)
.def("GetGeometryFamily", &GeometryType::GetGeometryFamily)
.def("GetGeometryType", &GeometryType::GetGeometryType)
// Geometry Parts
.def("GetGeometryPart", [](GeometryType& self, IndexType Index)
{ return(self.GetGeometryPart(Index)); })
Expand Down
Loading

0 comments on commit 78955e5

Please sign in to comment.