From 5f44622d6234cde3b01b79cf61cbf6a21e76698c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 16:04:32 +0200 Subject: [PATCH 01/50] Refactor CartesianMeshGeneratorModeler class for improved clarity and functionality - Updated class documentation to provide detailed descriptions of methods and parameters. - Replaced traditional include guards with #pragma once for better compatibility. - Simplified type definitions using 'using' instead of 'typedef'. - Enhanced constructor definitions and added default constructor for better usability. - Refactored GenerateMesh method and related calculations for clarity and maintainability. - Improved naming conventions and code organization for better readability. - Removed unused code and comments to streamline the implementation. --- .../cartesian_mesh_generator_modeler.cpp | 531 ++++++++++++ .../cartesian_mesh_generator_modeler.h | 787 ++++++------------ 2 files changed, 770 insertions(+), 548 deletions(-) create mode 100644 kratos/modeler/cartesian_mesh_generator_modeler.cpp diff --git a/kratos/modeler/cartesian_mesh_generator_modeler.cpp b/kratos/modeler/cartesian_mesh_generator_modeler.cpp new file mode 100644 index 000000000000..a05e3a0a8d79 --- /dev/null +++ b/kratos/modeler/cartesian_mesh_generator_modeler.cpp @@ -0,0 +1,531 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Jordi Cotela Dalmau +// + +// System includes + +// External includes + +// Project includes +#include "utilities/timer.h" +#include "modeler/cartesian_mesh_generator_modeler.h" + +namespace Kratos +{ + +CartesianMeshGeneratorModeler::CartesianMeshGeneratorModeler() + : Modeler() + , mpModel(nullptr) + , mpSourceModelPart(nullptr) + , mElementSize(0.0) +{ +} + +/***********************************************************************************/ +/***********************************************************************************/ + +CartesianMeshGeneratorModeler::CartesianMeshGeneratorModeler( + Model& rModel, + Parameters ModelerParameters + ) + : Modeler(rModel, ModelerParameters) + , mpModel(&rModel) + , mpSourceModelPart(nullptr) +{ + mParameters.ValidateAndAssignDefaults(GetDefaultParameters()); + mElementSize = mParameters["element_size"].GetDouble(); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +const Parameters CartesianMeshGeneratorModeler::GetDefaultParameters() const +{ + return Parameters(R"({ + "input_model_part_name" : "", + "output_model_part_name" : "", + "element_name" : "Element3D4N", + "element_size" : 1.0 + })"); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::SetupModelPart() +{ + KRATOS_TRY + + KRATOS_ERROR_IF(mpModel == nullptr) + << "CartesianMeshGeneratorModeler::SetupModelPart called without a Model." << std::endl; + + const std::string input_name = mParameters["input_model_part_name"].GetString(); + const std::string output_name = mParameters["output_model_part_name"].GetString(); + const std::string element_name = mParameters["element_name"].GetString(); + + KRATOS_ERROR_IF(input_name.empty()) + << "CartesianMeshGeneratorModeler: \"input_model_part_name\" must not be empty." << std::endl; + KRATOS_ERROR_IF(output_name.empty()) + << "CartesianMeshGeneratorModeler: \"output_model_part_name\" must not be empty." << std::endl; + + mpSourceModelPart = &mpModel->GetModelPart(input_name); + + ModelPart& r_output = mpModel->HasModelPart(output_name) + ? mpModel->GetModelPart(output_name) + : mpModel->CreateModelPart(output_name); + + if (!r_output.RecursivelyHasProperties(0)) + r_output.CreateNewProperties(0); + + const Element& r_ref_element = KratosComponents::Get(element_name); + GenerateMesh(r_output, r_ref_element); + + KRATOS_CATCH("") +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::GenerateMesh( + ModelPart& rModelPart, + Element const& rReferenceElement + ) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(mpSourceModelPart == nullptr) + << "CartesianMeshGeneratorModeler: source model part is not set." << std::endl; + + const unsigned int dimension = rReferenceElement.GetGeometry().WorkingSpaceDimension(); + + KRATOS_INFO("CartesianMeshGeneratorModeler") << "Generating mesh for dimension: " << dimension << std::endl; + + Timer::Start("Generating Mesh"); + + CalculateBoundingBox(*mpSourceModelPart, mMinPoint, mMaxPoint); + CalculateDivisionNumbers(); + + unsigned int start_node_id = mpSourceModelPart->NumberOfNodes() + 1; + unsigned int start_element_id = 1; + + if (dimension == 3) { + // 3D Cartesian tetrahedral mesh using Freudenthal decomposition (6 tets per hex cell) + Timer::Start("Generating Nodes"); + + const double x0 = mMinPoint.X(); + const double y0 = mMinPoint.Y(); + const double z0 = mMinPoint.Z(); + const unsigned int nx = mDivisionsNumber[0]; + const unsigned int ny = mDivisionsNumber[1]; + const unsigned int nz = mDivisionsNumber[2]; + + // 3D index with correct strides (nx, nx*ny) + auto NodeIdx3D = [&](unsigned int i, unsigned int j, unsigned int k) -> unsigned int { + return i + nx * j + nx * ny * k; + }; + + const unsigned int total_nodes = nx * ny * nz; + std::vector node_ptrs(total_nodes); + ModelPart::NodesContainerType::ContainerType& r_nodes_array = rModelPart.NodesArray(); + r_nodes_array.resize(total_nodes); + + for (unsigned int k = 0; k < nz; k++) { + for (unsigned int j = 0; j < ny; j++) { + for (unsigned int i = 0; i < nx; i++) { + auto p_node = Node::Pointer(new Node( + start_node_id++, + x0 + i * mElementSize, + y0 + j * mElementSize, + z0 + k * mElementSize)); + node_ptrs[NodeIdx3D(i,j,k)] = p_node; + r_nodes_array[NodeIdx3D(i,j,k)] = p_node; + } + } + } + + Timer::Stop("Generating Nodes"); + Timer::Start("Generating Elements"); + + const unsigned int sx = mSegmentsNumber[0]; + const unsigned int sy = mSegmentsNumber[1]; + const unsigned int sz = mSegmentsNumber[2]; + ModelPart::ElementsContainerType::ContainerType& r_elements_array = rModelPart.ElementsArray(); + r_elements_array.resize(6 * sx * sy * sz); + + Element::NodesArrayType tet_nodes(4); + unsigned int elem_counter = 0; + + for (unsigned int k = 0; k < sz; k++) { + for (unsigned int j = 0; j < sy; j++) { + for (unsigned int i = 0; i < sx; i++) { + auto c000 = node_ptrs[NodeIdx3D(i, j, k )]; + auto c100 = node_ptrs[NodeIdx3D(i+1, j, k )]; + auto c010 = node_ptrs[NodeIdx3D(i, j+1, k )]; + auto c110 = node_ptrs[NodeIdx3D(i+1, j+1, k )]; + auto c001 = node_ptrs[NodeIdx3D(i, j, k+1)]; + auto c101 = node_ptrs[NodeIdx3D(i+1, j, k+1)]; + auto c011 = node_ptrs[NodeIdx3D(i, j+1, k+1)]; + auto c111 = node_ptrs[NodeIdx3D(i+1, j+1, k+1)]; + + // Freudenthal decomposition: 6 tets all sharing the c000-c111 body diagonal + tet_nodes(0)=c000; tet_nodes(1)=c100; tet_nodes(2)=c110; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + + tet_nodes(0)=c000; tet_nodes(1)=c100; tet_nodes(2)=c101; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + + tet_nodes(0)=c000; tet_nodes(1)=c010; tet_nodes(2)=c110; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + + tet_nodes(0)=c000; tet_nodes(1)=c010; tet_nodes(2)=c011; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + + tet_nodes(0)=c000; tet_nodes(1)=c001; tet_nodes(2)=c101; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + + tet_nodes(0)=c000; tet_nodes(1)=c001; tet_nodes(2)=c011; tet_nodes(3)=c111; + r_elements_array[elem_counter++] = rReferenceElement.Create(start_element_id++, tet_nodes, rReferenceElement.pGetProperties()); + } + } + } + + Timer::Stop("Generating Elements"); + Timer::Stop("Generating Mesh"); + return; + } + + KRATOS_ERROR_IF(dimension != 2) << "Only 2D and 3D meshes are supported!" << std::endl; + + // 2D path: quadrilateral elements with inside-test via ray casting + const unsigned int number_of_nodes = mDivisionsNumber[0] * mDivisionsNumber[1] * mDivisionsNumber[2]; + const unsigned int number_of_elements = mSegmentsNumber[0] * mSegmentsNumber[1] * mSegmentsNumber[2]; + + KRATOS_INFO("CartesianMeshGeneratorModeler") << "Number of nodes: " << number_of_nodes << std::endl; + KRATOS_INFO("CartesianMeshGeneratorModeler") << "Number of elements: " << number_of_elements << std::endl; + + CalculateBoundaryIntersections(*mpSourceModelPart); + CalculateIsInside(*mpSourceModelPart); + CalculateNormals(); + + Timer::Start("Generating Nodes"); + + const double x0 = mMinPoint.X(); + const double y0 = mMinPoint.Y(); + const double z0 = mMinPoint.Z(); + + ModelPart::NodesContainerType::ContainerType& r_nodes_array = rModelPart.NodesArray(); + ModelPart::NodesContainerType::ContainerType temp_nodes_array(number_of_nodes); + + ModelPart::ElementsContainerType::ContainerType& r_elements_array = rModelPart.ElementsArray(); + + for (unsigned int k = 0; k < mDivisionsNumber[2]; k++) + for (unsigned int j = 0; j < mDivisionsNumber[1]; j++) + for (unsigned int i = 0; i < mDivisionsNumber[0]; i++) + temp_nodes_array[NodeIndex(i,j,k)] = Node::Pointer(new Node( + start_node_id++, + x0 + i * mElementSize, + y0 + j * mElementSize, + z0 + k * mElementSize)); + + unsigned int number_of_active_nodes = 0; + for (unsigned int i = 0; i < number_of_nodes; i++) + if (mIsInside[i]) + number_of_active_nodes++; + + r_nodes_array.resize(number_of_active_nodes); + + unsigned int index = 0; + for (unsigned int i = 0; i < number_of_nodes; i++) + if (mIsInside[i]) + r_nodes_array[index++] = temp_nodes_array[i]; + + Timer::Stop("Generating Nodes"); + Timer::Start("Generating Elements"); + + Element::NodesArrayType element_nodes(4); + + unsigned int number_of_active_elements = 0; + for (unsigned int j = 0; j < mSegmentsNumber[1]; j++) + for (unsigned int i = 0; i < mSegmentsNumber[0]; i++) + if (mIsInside[NodeIndex(i,j,0)] & mIsInside[NodeIndex(i+1,j,0)] & + mIsInside[NodeIndex(i+1,j+1,0)] & mIsInside[NodeIndex(i,j+1,0)]) + number_of_active_elements++; + + r_elements_array.resize(number_of_active_elements); + + unsigned int counter = 0; + for (unsigned int j = 0; j < mSegmentsNumber[1]; j++) { + for (unsigned int i = 0; i < mSegmentsNumber[0]; i++) { + if (mIsInside[NodeIndex(i,j,0)] & mIsInside[NodeIndex(i+1,j,0)] & + mIsInside[NodeIndex(i+1,j+1,0)] & mIsInside[NodeIndex(i,j+1,0)]) { + element_nodes(0) = temp_nodes_array[NodeIndex(i, j, 0)]; + element_nodes(1) = temp_nodes_array[NodeIndex(i+1, j, 0)]; + element_nodes(2) = temp_nodes_array[NodeIndex(i+1, j+1, 0)]; + element_nodes(3) = temp_nodes_array[NodeIndex(i, j+1, 0)]; + r_elements_array[counter++] = rReferenceElement.Create(start_element_id++, element_nodes, rReferenceElement.pGetProperties()); + } + } + } + + for (auto& r_elem : mpSourceModelPart->Elements()) { + auto& r_geometry = r_elem.GetGeometry(); + array_1d coords1, coords2; + noalias(coords1) = r_geometry[0].Coordinates() + mNormals[r_geometry[0].Id()-1]; + noalias(coords2) = r_geometry[1].Coordinates() + mNormals[r_geometry[1].Id()-1]; + Point point1(coords1[0], coords1[1], coords1[2]); + Point point2(coords2[0], coords2[1], coords2[2]); + unsigned int index1 = FindNearestNodeIndex(point1, mNormals[r_geometry[0].Id()-1]); + unsigned int index2 = FindNearestNodeIndex(point2, mNormals[r_geometry[1].Id()-1]); + element_nodes(0) = r_geometry(0); + element_nodes(1) = r_geometry(1); + element_nodes(2) = temp_nodes_array[index2]; + element_nodes(3) = temp_nodes_array[index1]; + r_elements_array.push_back(rReferenceElement.Create(start_element_id++, element_nodes, rReferenceElement.pGetProperties())); + } + + Timer::Stop("Generating Elements"); + Timer::Stop("Generating Mesh"); + + KRATOS_CATCH("") +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::CalculateNormals() +{ + const array_1d zero = ZeroVector(3); + + if (mNormals.size() != mpSourceModelPart->NumberOfNodes()) + mNormals.resize(mpSourceModelPart->NumberOfNodes(), zero); + else + std::fill(mNormals.begin(), mNormals.end(), zero); + + const double coefficient = mElementSize / 2.0; + + for (auto& r_elem : mpSourceModelPart->Elements()) { + auto& r_geometry = r_elem.GetGeometry(); + array_1d normal; + normal[0] = r_geometry[1].Y() - r_geometry[0].Y(); + normal[1] = -(r_geometry[1].X() - r_geometry[0].X()); + normal[2] = 0.0; + normal *= coefficient / r_geometry.Length(); + mNormals[r_geometry[0].Id()-1] += normal; + mNormals[r_geometry[1].Id()-1] += normal; + } + + for (auto& r_node : mpSourceModelPart->Nodes()) + noalias(r_node.FastGetSolutionStepValue(NORMAL)) = mNormals[r_node.Id()-1]; +} + +/***********************************************************************************/ +/***********************************************************************************/ + +unsigned int CartesianMeshGeneratorModeler::FindNearestNodeIndex( + Point& rThisPoint, + array_1d& rNormal + ) +{ + const double x = (rThisPoint.X() - mMinPoint.X()) / mElementSize; + const double y = (rThisPoint.Y() - mMinPoint.Y()) / mElementSize; + + unsigned int i = static_cast(x); + unsigned int j = static_cast(y); + + if (mIsInside[NodeIndex(i,j,0)]) + return NodeIndex(i,j,0); + + if (rNormal[0] >= 0.0) { + if (rNormal[1] >= 0.0) { + if (rNormal[0] > rNormal[1]) i++; + else j++; + } else { + if (rNormal[0] > -rNormal[1]) i++; + else j--; + } + } else { + if (rNormal[1] >= 0.0) { + if (-rNormal[0] > rNormal[1]) i--; + else j++; + } else { + if (-rNormal[0] > -rNormal[1]) i--; + else j--; + } + } + + return NodeIndex(i,j,0); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::CalculateIsInside(ModelPart& rModelPart) +{ + const unsigned int number_of_nodes = mDivisionsNumber[0] * mDivisionsNumber[1] * mDivisionsNumber[2]; + + if (mIsInside.size() != number_of_nodes) + mIsInside.resize(number_of_nodes, 0); + else + std::fill(mIsInside.begin(), mIsInside.end(), 0); + + const int size = static_cast(mSegmentsNumber[1]) + 1; + + for (int j = 0; j < size; j++) { + std::vector& r_j_intersections = mIntersections[j]; + + for (auto j_x = r_j_intersections.begin(); j_x != r_j_intersections.end(); j_x++) { + const auto start = j_x++; + const unsigned int i_start = static_cast(*start / mElementSize); + const unsigned int i_end = static_cast(*j_x / mElementSize); + for (unsigned int i = i_start + 1; i < i_end; i++) + mIsInside[NodeIndex(i, j, 0)] = true; + } + } +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::CalculateBoundaryIntersections(ModelPart& rModelPart) +{ + if (mIntersections.size() != mSegmentsNumber[1] + 1) + mIntersections.resize(mSegmentsNumber[1] + 1); + + for (auto& r_elem : rModelPart.Elements()) { + const auto& r_geometry = r_elem.GetGeometry(); + + double x1, x2, y1, y2; + if (r_geometry[0].Y() < r_geometry[1].Y()) { + x1 = r_geometry[0].X() - mMinPoint.X(); + x2 = r_geometry[1].X() - mMinPoint.X(); + y1 = r_geometry[0].Y() - mMinPoint.Y(); + y2 = r_geometry[1].Y() - mMinPoint.Y(); + } else { + x1 = r_geometry[1].X() - mMinPoint.X(); + x2 = r_geometry[0].X() - mMinPoint.X(); + y1 = r_geometry[1].Y() - mMinPoint.Y(); + y2 = r_geometry[0].Y() - mMinPoint.Y(); + } + + unsigned int i_start = static_cast(y1 / mElementSize); + const unsigned int i_end = static_cast(y2 / mElementSize); + + if (i_start * mElementSize < y1) + i_start++; + + const double m = (y1 != y2) ? (x2 - x1) / (y2 - y1) : 0.0; + const double delta_x = m * mElementSize; + double x = x1 + (i_start * mElementSize - y1) * m; + + for (unsigned int i = i_start; i <= i_end; i++) { + mIntersections[i].push_back(x); + x += delta_x; + } + } + + for (auto& r_row : mIntersections) + std::sort(r_row.begin(), r_row.end()); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::CalculateBoundingBox( + ModelPart& rModelPart, + Point& rMinPoint, + Point& rMaxPoint + ) +{ + if (rModelPart.NumberOfElements() == 0 && rModelPart.NumberOfNodes() == 0) { + rMinPoint = Point(); + rMaxPoint = Point(); + return; + } + + // Fall back to node-based BB when no elements are present (e.g. condition-only model parts from STL) + if (rModelPart.NumberOfElements() == 0) { + rMinPoint = *rModelPart.NodesBegin(); + rMaxPoint = rMinPoint; + for (const auto& r_node : rModelPart.Nodes()) { + for (unsigned int i = 0; i < 3; i++) { + if (rMinPoint[i] > r_node[i]) rMinPoint[i] = r_node[i]; + if (rMaxPoint[i] < r_node[i]) rMaxPoint[i] = r_node[i]; + } + } + return; + } + + if (rModelPart.ElementsBegin()->GetGeometry().empty()) { + rMinPoint = Point(); + rMaxPoint = Point(); + return; + } + + rMinPoint = rModelPart.ElementsBegin()->GetGeometry()[0]; + rMaxPoint = rMinPoint; + + for (const auto& r_elem : rModelPart.Elements()) { + for (const auto& r_point : r_elem.GetGeometry()) { + for (unsigned int i = 0; i < Point::Dimension(); i++) { + if (rMinPoint[i] > r_point[i]) rMinPoint[i] = r_point[i]; + if (rMaxPoint[i] < r_point[i]) rMaxPoint[i] = r_point[i]; + } + } + } +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::CalculateDivisionNumbers() +{ + if (mElementSize == 0.0) + return; + + for (unsigned int i = 0; i < Point::Dimension(); i++) { + const double delta = mMaxPoint[i] - mMinPoint[i]; + int segments_number = static_cast(delta / mElementSize); + + if ((segments_number * mElementSize) < delta) + segments_number++; + + mSegmentsNumber[i] = segments_number; + mDivisionsNumber[i] = segments_number + 1; + + if (mSegmentsNumber[i] == 0) + mSegmentsNumber[i]++; + } +} + +/***********************************************************************************/ +/***********************************************************************************/ + +std::string CartesianMeshGeneratorModeler::Info() const +{ + return "CartesianMeshGeneratorModeler"; +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::PrintInfo(std::ostream& rOStream) const +{ + rOStream << Info(); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void CartesianMeshGeneratorModeler::PrintData(std::ostream& rOStream) const +{ +} + +} // namespace Kratos diff --git a/kratos/modeler/cartesian_mesh_generator_modeler.h b/kratos/modeler/cartesian_mesh_generator_modeler.h index 55a9b48cbb71..63e95e057a57 100644 --- a/kratos/modeler/cartesian_mesh_generator_modeler.h +++ b/kratos/modeler/cartesian_mesh_generator_modeler.h @@ -2,54 +2,54 @@ // ' / __| _` | __| _ \ __| // . \ | ( | | ( |\__ ` // _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics +// Multi-Physics // -// License: BSD License -// Kratos default license: kratos/license.txt +// License: BSD License +// Kratos default license: kratos/license.txt // // Main authors: Jordi Cotela Dalmau -// // -#if !defined(KRATOS_CARTESIAN_MESH_GENERATOR_H_INCLUDED ) -#define KRATOS_CARTESIAN_MESH_GENERATOR_H_INCLUDED +#pragma once // System includes -#include -#include // External includes // Project includes -#include "includes/define.h" +#include "containers/model.h" +#include "geometries/geometry.h" +#include "containers/pointer_vector.h" #include "modeler/modeler.h" -#include "spatial_containers/spatial_containers.h" namespace Kratos { -///@name Kratos Globals +///@addtogroup KratosCore ///@{ -///@} -///@name Type Definitions -///@{ - -///@} -///@name Enum's -///@{ - -///@} -///@name Functions -///@{ - -///@} ///@name Kratos Classes ///@{ -/// Short class definition. -/** Detail class definition. -*/ -class CartesianMeshGeneratorModeler : public Modeler +/** + * @class CartesianMeshGeneratorModeler + * @ingroup KratosCore + * @brief Generates a structured Cartesian mesh filling the bounding box of a + * source model part. + * @details For 3D problems each axis-aligned hexahedral cell is split into + * 6 tetrahedra using the Freudenthal (Kuhn) decomposition so that + * the resulting tetrahedral mesh is conforming across cell boundaries. + * For 2D problems quadrilateral elements are generated using a + * ray-casting inside test derived from the source boundary elements. + * + * The class is constructed with a reference source model part + * (from which the bounding box and boundary are taken) and a uniform + * element size. The generated nodes and elements are placed in the + * destination model part passed to GenerateMesh(). + * + * @author Jordi Cotela Dalmau + */ +class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler + : public Modeler { public: ///@name Type Definitions @@ -58,562 +58,270 @@ class CartesianMeshGeneratorModeler : public Modeler /// Pointer definition of CartesianMeshGeneratorModeler KRATOS_CLASS_POINTER_DEFINITION(CartesianMeshGeneratorModeler); - typedef Modeler BaseType; - - typedef Point PointType; - - typedef Node NodeType; + /// The base class type + using BaseType = Modeler; - typedef Geometry GeometryType; + /// The geometry type definition + using GeometryType = Geometry; - typedef PointerVector NodesVectorType; + /// The nodes vector type definition + using NodesVectorType = PointerVector; - typedef std::size_t SizeType; + /// The size type definition + using SizeType = std::size_t; ///@} ///@name Life Cycle ///@{ - /// constructor. - CartesianMeshGeneratorModeler(ModelPart& rSourceModelPart, double ElementSize) : - mrModelPart(rSourceModelPart), mElementSize(ElementSize) - { - } + /** + * @brief Default constructor (required for registry). + * @note Do not call GenerateMesh() on a default-constructed instance. + */ + CartesianMeshGeneratorModeler(); + + /** + * @brief Constructor for use via the modeler factory / registry. + * @details Reads the input model part name, output model part name, + * element name and element size from @p ModelerParameters. + * The default parameters are: + * @code + * { + * "input_model_part_name" : "", + * "output_model_part_name" : "", + * "element_name" : "Element3D4N", + * "element_size" : 1.0 + * } + * @endcode + * SetupModelPart() performs the actual mesh generation. + * @param rModel Model that owns both the input and output model parts. + * @param ModelerParameters Parameters block (see default values above). + */ + CartesianMeshGeneratorModeler(Model& rModel, Parameters ModelerParameters = Parameters()); + + /** + * @brief Legacy direct constructor. + * @param rSourceModelPart Model part whose geometry defines the bounding + * box (and, for 2D, the boundary) used during mesh generation. + * @param ElementSize Uniform edge length of each voxel cell. The actual + * number of cells per direction is computed as + * ceil(bounding_box_extent / ElementSize). + */ + CartesianMeshGeneratorModeler(ModelPart& rSourceModelPart, double ElementSize) + : Modeler() + , mpModel(nullptr) + , mpSourceModelPart(&rSourceModelPart) + , mElementSize(ElementSize) {} /// Destructor. - virtual ~CartesianMeshGeneratorModeler() {} - - - ///@} - ///@name Operators - ///@{ - + ~CartesianMeshGeneratorModeler() override = default; ///@} ///@name Operations ///@{ - void GenerateMesh(ModelPart& rThisModelPart, Element const& rReferenceElement) - { - const unsigned int dimension = rReferenceElement.GetGeometry().Dimension(); - - KRATOS_WATCH(dimension); - - Timer::Start("Generating Mesh"); - - CalculateBoundingBox(mrModelPart, mMinPoint, mMaxPoint); - CalculateDivisionNumbers(); - - unsigned int start_node_id = mrModelPart.NumberOfNodes() + 1; - unsigned int start_element_id = 1; - //unsigned int segment_number_1 = mSegmentsNumber[0] + 1; - //unsigned int segment_number_2 = mSegmentsNumber[1] + 1; - //unsigned int segment_number_3 = mSegmentsNumber[2] + 1; - - - - const unsigned int number_of_nodes = mDivisionsNumber[0] * mDivisionsNumber[1] * mDivisionsNumber[2]; - //const unsigned int number_of_nodes = segment_number_1 * segment_number_2 * segment_number_3; - - const unsigned int number_of_elements = mSegmentsNumber[0] * mSegmentsNumber[1] * mSegmentsNumber[2]; - - KRATOS_WATCH(number_of_nodes); - - KRATOS_WATCH(number_of_elements); - - CalculateBoundaryIntersections(mrModelPart); - - CalculateIsInside(mrModelPart); - - CalculateNormals(); - - Timer::Start("Generating Nodes"); - - double x0 = mMinPoint.X(); - double y0 = mMinPoint.Y(); - double z0 = mMinPoint.Z(); - - ModelPart::NodesContainerType::ContainerType& nodes_array = rThisModelPart.NodesArray(); - ModelPart::NodesContainerType::ContainerType temp_nodes_array(number_of_nodes); - - ModelPart::ElementsContainerType::ContainerType& elements_array = rThisModelPart.ElementsArray(); - ModelPart::ElementsContainerType::ContainerType temp_elements_array(number_of_elements); - - for(unsigned int k = 0 ; k < mDivisionsNumber[2] ; k++) - for(unsigned int j = 0 ; j < mDivisionsNumber[1] ; j++) - for(unsigned int i = 0 ; i < mDivisionsNumber[0] ; i++) - temp_nodes_array[NodeIndex(i,j,k)] = NodeType::Pointer(new NodeType(start_node_id++, x0 + i * mElementSize, y0 + j * mElementSize, z0 + k * mElementSize)); - - unsigned int number_of_active_nodes = 0; - - for(unsigned int i = 0 ; i < number_of_nodes ; i++) - if(mIsInside[i]) - number_of_active_nodes++; - - nodes_array.resize(number_of_active_nodes); - - unsigned int index = 0; - - for(unsigned int i = 0 ; i < number_of_nodes ; i++) - if(mIsInside[i]) - nodes_array[index++]=temp_nodes_array[i]; - - Timer::Stop("Generating Nodes"); - - Timer::Start("Generating Elements"); - - Element::NodesArrayType element_nodes(4); - - if(dimension == 2) - { - unsigned int number_of_active_elements = 0; - for(unsigned int j = 0 ; j < mSegmentsNumber[1] ; j++) - for(unsigned int i = 0 ; i < mSegmentsNumber[0] ; i++) - { - if(mIsInside[NodeIndex(i,j,0)] & mIsInside[NodeIndex(i+1,j,0)] & mIsInside[NodeIndex(i+1,j+1,0)] & mIsInside[NodeIndex(i,j+1,0)]) - number_of_active_elements++; - } - - elements_array.resize(number_of_active_elements); - - unsigned int counter = 0; - - for(unsigned int j = 0 ; j < mSegmentsNumber[1] ; j++) - for(unsigned int i = 0 ; i < mSegmentsNumber[0] ; i++) - { - if(mIsInside[NodeIndex(i,j,0)] & mIsInside[NodeIndex(i+1,j,0)] & mIsInside[NodeIndex(i+1,j+1,0)] & mIsInside[NodeIndex(i,j+1,0)]) - { - element_nodes(0) = temp_nodes_array[NodeIndex(i,j,0)]; - element_nodes(1) = temp_nodes_array[NodeIndex(i+1,j,0)]; - element_nodes(2) = temp_nodes_array[NodeIndex(i+1,j+1,0)]; - element_nodes(3) = temp_nodes_array[NodeIndex(i,j+1,0)]; - - elements_array[counter++] = rReferenceElement.Create(start_element_id++, element_nodes, rReferenceElement.pGetProperties()); - //elements_array[ElementIndex(i,j,0)] = rReferenceElement.Create(start_element_id++, element_nodes, rReferenceElement.pGetProperties()); - } - } - for(ModelPart::ElementIterator i_element = mrModelPart.ElementsBegin() ; i_element != mrModelPart.ElementsEnd() ; i_element++) - { - Element::GeometryType& r_geometry = i_element->GetGeometry(); - - PointType point1 = r_geometry[0] + mNormals[r_geometry[0].Id()-1]; - PointType point2 = r_geometry[1] + mNormals[r_geometry[1].Id()-1]; - - unsigned int index1 = FindNearestNodeIndex(point1,mNormals[r_geometry[0].Id()-1]); - unsigned int index2 = FindNearestNodeIndex(point2,mNormals[r_geometry[1].Id()-1]); - - element_nodes(0) = r_geometry(0); - element_nodes(1) = r_geometry(1); - element_nodes(2) = temp_nodes_array[index2]; - element_nodes(3) = temp_nodes_array[index1]; - - elements_array.push_back(rReferenceElement.Create(start_element_id++, element_nodes, rReferenceElement.pGetProperties())); - } - } - - // TODO: assigning nodes and elements to the modelpart - // TODO: adding source boundary mesh nods to modelpart - - Timer::Stop("Generating Elements"); - - - - Timer::Stop("Generating Mesh"); - } - - - void CalculateNormals() - { - array_1d zero = ZeroVector(3); - - if(mNormals.size() != mrModelPart.NumberOfNodes()) - mNormals.resize(mrModelPart.NumberOfNodes(), zero); - else - std::fill(mNormals.begin(), mNormals.end(), zero); - - double coefficient = mElementSize / 2.00; - - for(ModelPart::ElementIterator i_element = mrModelPart.ElementsBegin() ; i_element != mrModelPart.ElementsEnd() ; i_element++) - { - Element::GeometryType& r_geometry = i_element->GetGeometry(); - array_1d normal; - - normal[0] = r_geometry[1].Y() - r_geometry[0].Y(); - normal[1] = - (r_geometry[1].X() - r_geometry[0].X()); - - normal *= coefficient / r_geometry.Length(); - - - mNormals[r_geometry[0].Id()-1] += normal ; - mNormals[r_geometry[1].Id()-1] += normal ; - } - for(ModelPart::NodeIterator i_node = mrModelPart.NodesBegin() ; i_node != mrModelPart.NodesEnd() ; i_node++) - noalias(i_node->FastGetSolutionStepValue(NORMAL)) = mNormals[i_node->Id()-1] ; - } - - unsigned int FindNearestNodeIndex(PointType& rThisPoint, array_1d& rNormal) - { - double x = (rThisPoint.X() - mMinPoint.X()) / mElementSize; - double y = (rThisPoint.Y() - mMinPoint.Y()) / mElementSize; - - unsigned int i = static_cast(x); - unsigned int j = static_cast(y); - - if(mIsInside[NodeIndex(i,j,0)]) - return NodeIndex(i,j,0); - - - if(rNormal[0] >= 0.00) - { - if(rNormal[1] >= 0.00) - { - if(rNormal[0] > rNormal[1]) - i++; - else - j++; - } - else - { - if(rNormal[0] > -rNormal[1]) - i++; - else - j--; - } - } - else - { - if(rNormal[1] >= 0.00) - { - if(-rNormal[0] > rNormal[1]) - i--; - else - j++; - } - else - { - if(-rNormal[0] > -rNormal[1]) - i--; - else - j--; - } - } - - - return NodeIndex(i,j,0); - - } - - void CalculateIsInside(ModelPart& rThisModelPart) - { - const unsigned int number_of_nodes = mDivisionsNumber[0] * mDivisionsNumber[1] * mDivisionsNumber[2]; - - if(mIsInside.size() != number_of_nodes) - { - mIsInside.resize(number_of_nodes, 0); - } - else - std::fill(mIsInside.begin(),mIsInside.end(), 0); - - int size = mSegmentsNumber[1] + 1; - - for(int j = 0 ; j < size ; j++) - { -// bool is_inside = false; - std::vector& j_intersections = mIntersections[j]; - - for(std::vector::iterator j_x = j_intersections.begin() ; j_x != j_intersections.end() ; j_x++) - { - std::vector::iterator start = j_x++; - - unsigned int i_start = static_cast(*start / mElementSize); - unsigned int i_end = static_cast(*j_x / mElementSize); - - for(unsigned int i = i_start + 1 ; i < i_end ; i++) - mIsInside[NodeIndex(i,j,0)]=true; - } - } - } - - void CalculateBoundaryIntersections(ModelPart& rThisModelPart) - { - std::vector number_of_intersections(mSegmentsNumber[1] + 1, 0); // number of intersections per row for mSegmentsNumber[1] + 1 rows in x direction - if(mIntersections.size() != mSegmentsNumber[1] + 1) - mIntersections.resize(mSegmentsNumber[1] + 1); // intersection points x coordinate per row for mSegmentsNumber[1] + 1 rows - - for(ModelPart::ElementIterator i_element = rThisModelPart.ElementsBegin() ; i_element != rThisModelPart.ElementsEnd() ; i_element++) - { - Element::GeometryType& r_geometry = i_element->GetGeometry(); - - double x1; - double x2; - double y1; - double y2; - if(r_geometry[0].Y() < r_geometry[1].Y()) - { - x1 = (r_geometry[0].X() - mMinPoint.X()); - x2 = (r_geometry[1].X() - mMinPoint.X()); - y1 = (r_geometry[0].Y() - mMinPoint.Y()); - y2 = (r_geometry[1].Y() - mMinPoint.Y()); - } - else - { - x1 = (r_geometry[1].X() - mMinPoint.X()); - x2 = (r_geometry[0].X() - mMinPoint.X()); - y1 = (r_geometry[1].Y() - mMinPoint.Y()); - y2 = (r_geometry[0].Y() - mMinPoint.Y()); - } - - unsigned int i_start = static_cast(y1 / mElementSize); - unsigned int i_end = static_cast(y2 / mElementSize); - - if (i_start*mElementSize < y1) - i_start++; - - double m = 0.00; - if(y1 != y2) - m = (x2 - x1) / (y2 - y1); - - double delta_x = m*mElementSize; - double x = x1 + (i_start * mElementSize - y1) * m ; - for(unsigned int i = i_start ; i <= i_end ; i++) - { - number_of_intersections[i]++; - mIntersections[i].push_back(x); - x += delta_x; - } - } - - for(int i = 0 ; i < mIntersections.size() ; i++) - std::sort(mIntersections[i].begin(), mIntersections[i].end()); - } - - void CalculateBoundingBox(ModelPart& rThisModelPart, Point& rMinPoint, Point& rMaxPoint) - { - if(rThisModelPart.NumberOfElements() == 0) - { - rMinPoint = PointType(); - rMaxPoint = PointType(); - return; - } - - if(rThisModelPart.ElementsBegin()->GetGeometry().empty()) - { - rMinPoint = PointType(); - rMaxPoint = PointType(); - return; - } - - - rMinPoint = rThisModelPart.ElementsBegin()->GetGeometry()[0]; - rMaxPoint = rMinPoint; - - for(ModelPart::ElementIterator i_element = rThisModelPart.ElementsBegin() ; - i_element != rThisModelPart.ElementsEnd() ; i_element++) - for(Element::GeometryType::iterator i_point = i_element->GetGeometry().begin() ; i_point != i_element->GetGeometry().end() ; i_point++) - for(unsigned int i = 0 ; i < PointType::Dimension() ; i++) - { - if(rMinPoint[i] > (*i_point)[i]) - rMinPoint[i] = (*i_point)[i]; - - if(rMaxPoint[i] < (*i_point)[i]) - rMaxPoint[i] = (*i_point)[i]; - } - } - - - void CalculateDivisionNumbers() - { - if(mElementSize == 0.00) - return; - - for(unsigned int i = 0 ; i < PointType::Dimension() ; i++) - { - double delta = mMaxPoint[i] - mMinPoint[i]; - int segments_number = static_cast(delta / mElementSize); - - if (((segments_number * mElementSize) < delta)) - segments_number++; - - mSegmentsNumber[i] = segments_number; - KRATOS_WATCH(mSegmentsNumber[i]); - - mDivisionsNumber[i] = segments_number + 1; - - if(mSegmentsNumber[i] == 0) - mSegmentsNumber[i]++; - } - - } - - virtual void GenerateNodes(ModelPart& ThisModelPart) + /** + * @brief Creates a new instance via the modeler factory. + * @param rModel Owning model. + * @param ModelParameters Configuration parameters. + * @return Shared pointer to the new modeler. + */ + Modeler::Pointer Create(Model& rModel, const Parameters ModelParameters) const override { - //std::vector + return Kratos::make_shared(rModel, ModelParameters); } - + /** + * @brief Returns the default parameters accepted by the Model constructor. + * @return A Parameters object with default values. + */ + const Parameters GetDefaultParameters() const override; + + /** + * @brief Runs mesh generation when the modeler is used through the factory. + * @details Reads the input/output model part names and element name from + * the stored parameters and delegates to GenerateMesh(). + */ + void SetupModelPart() override; + + /** + * @brief Generates a Cartesian mesh in the destination model part. + * @details The element type (and therefore the dimension) is determined + * by @p rReferenceElement. For 3D elements six tetrahedra are + * created per hex cell (Freudenthal decomposition). For 2D + * elements one quadrilateral is created per active cell. + * @param rThisModelPart Destination model part that will receive the + * generated nodes and elements. + * @param rReferenceElement Prototype element whose geometry dimension + * selects the 2D or 3D code path and whose properties are + * reused for every created element. + */ + void GenerateMesh(ModelPart& rThisModelPart, Element const& rReferenceElement); + + /** + * @brief Computes outward-pointing normals at every boundary node of + * the source model part (2D only). + * @details The normals are scaled to half the element size and + * accumulated over all boundary elements sharing each node. + * The result is stored in the NORMAL solution-step variable + * and in the internal @c mNormals cache used by + * FindNearestNodeIndex(). + */ + void CalculateNormals(); + + /** + * @brief Returns the flat index of the grid node closest to @p rThisPoint + * in the direction given by @p rNormal (2D only). + * @details Starting from the cell that contains the point the method + * steps one cell in the dominant normal direction until it + * finds a node that is marked as inside. + * @param rThisPoint Query point in world coordinates. + * @param rNormal Outward boundary normal at the query point; used to + * determine which neighbouring cell to prefer. + * @return Flat index into the internal node array of the nearest inside + * node. + */ + unsigned int FindNearestNodeIndex(Point& rThisPoint, array_1d& rNormal); + + /** + * @brief Marks each grid node as inside or outside the 2D boundary. + * @details Uses the precomputed horizontal ray–edge intersection table + * (populated by CalculateBoundaryIntersections()) to flood-fill + * the grid cells between pairs of intersections on each + * horizontal scan line. + * @param rThisModelPart The source model part providing the boundary. + */ + void CalculateIsInside(ModelPart& rThisModelPart); + + /** + * @brief Builds the horizontal ray–edge intersection table (2D only). + * @details For every boundary element in @p rThisModelPart the method + * computes the x-coordinates at which the element edge crosses + * each horizontal grid line and stores them in @c mIntersections. + * Each row of the table is sorted in ascending order after all + * edges have been processed. + * @param rThisModelPart The source model part providing the boundary edges. + */ + void CalculateBoundaryIntersections(ModelPart& rThisModelPart); + + /** + * @brief Computes the axis-aligned bounding box of @p rThisModelPart. + * @details When the model part contains elements the bounding box is + * computed from element vertices. When it contains only nodes + * (e.g. a condition-only mesh read from an STL file) the bounding + * box is computed directly from the node coordinates. An empty + * model part yields the origin for both corners. + * @param rThisModelPart The model part to bound. + * @param rMinPoint Output: minimum corner of the bounding box. + * @param rMaxPoint Output: maximum corner of the bounding box. + */ + void CalculateBoundingBox(ModelPart& rThisModelPart, Point& rMinPoint, Point& rMaxPoint); + + /** + * @brief Computes the number of grid cells and node layers per direction. + * @details Sets @c mSegmentsNumber[i] = ceil(extent_i / mElementSize) + * and @c mDivisionsNumber[i] = mSegmentsNumber[i] + 1. + * Directions with zero extent are given one segment so that the + * degenerate case does not crash. + */ + void CalculateDivisionNumbers(); + + /** + * @brief Returns the flat element index for cell (i, j, k). + * @param i Cell index along X. + * @param j Cell index along Y. + * @param k Cell index along Z. + * @return Flat index = i + nx*j + nx*ny*k, where nx = mDivisionsNumber[0] + * and ny = mDivisionsNumber[1]. + */ unsigned int ElementIndex(unsigned int i, unsigned int j, unsigned int k) { return i + mDivisionsNumber[0] * j + mDivisionsNumber[0] * mDivisionsNumber[1] * k; } + /** + * @brief Returns the flat node index for grid point (i, j, k). + * @param i Node index along X. + * @param j Node index along Y. + * @param k Node index along Z. + * @return Flat index = i + sx*j + sx*sy*k, where sx = mSegmentsNumber[0] + * and sy = mSegmentsNumber[1]. + */ unsigned int NodeIndex(unsigned int i, unsigned int j, unsigned int k) { return i + mSegmentsNumber[0] * j + mSegmentsNumber[0] * mSegmentsNumber[1] * k; } - - - - - ///@} - ///@name Access - ///@{ - - - ///@} - ///@name Inquiry - ///@{ - - ///@} ///@name Input and output ///@{ - /// Turn back information as a string. - virtual std::string Info() const - { - return "CartesianMeshGeneratorModeler"; - } - - /// Print information about this object. - virtual void PrintInfo(std::ostream& rOStream) const - { - rOStream << Info(); - } - - /// Print object's data. - virtual void PrintData(std::ostream& rOStream) const - { - } - - - ///@} - ///@name Friends - ///@{ - - - ///@} - -protected: - ///@name Protected static Member Variables - ///@{ - - - ///@} - ///@name Protected member Variables - ///@{ - - - ///@} - ///@name Protected Operators - ///@{ - + /// @brief Returns the class name as a string. + std::string Info() const override; - ///@} - ///@name Protected Operations - ///@{ - - - ///@} - ///@name Protected Access - ///@{ - - - ///@} - ///@name Protected Inquiry - ///@{ - - - ///@} - ///@name Protected LifeCycle - ///@{ + /// @brief Prints the class name to @p rOStream. + void PrintInfo(std::ostream& rOStream) const override; + /// @brief Prints object data to @p rOStream (currently empty). + void PrintData(std::ostream& rOStream) const override; ///@} private: - ///@name Static Member Variables - ///@{ - - - ///@} ///@name Member Variables ///@{ - ModelPart& mrModelPart; + /// Owning model (only set when using the Model constructor). + Model* mpModel = nullptr; - double mElementSize; - PointType mMinPoint; - PointType mMaxPoint; + /// Source model part whose geometry defines the domain to mesh (nullptr only for the default-constructed prototype). + ModelPart* mpSourceModelPart; - unsigned int mSegmentsNumber[3]; + /// Uniform voxel cell edge length. + double mElementSize = 0.0; - unsigned int mDivisionsNumber[3]; + /// Minimum corner of the bounding box of the source model part. + Point mMinPoint; - std::vector > mIntersections; - std::vector mIsInside; + /// Maximum corner of the bounding box of the source model part. + Point mMaxPoint; - std::vector > mNormals; + /// Number of voxel cells per direction (X=0, Y=1, Z=2). + unsigned int mSegmentsNumber[3] = {0, 0, 0}; - ///@} - ///@name Private Operators - ///@{ + /// Number of node layers per direction: mSegmentsNumber[i] + 1. + unsigned int mDivisionsNumber[3] = {0, 0, 0}; + /// Sorted x-coordinates of edge–scanline intersections per row (2D only). + std::vector> mIntersections; - ///@} - ///@name Private Operations - ///@{ - - - void GenerateNodes(ModelPart& ThisModelPart, GeometryType& rGeometry, SizeType NumberOfSegments, SizeType StartNodeId) - { - double x1 = rGeometry[0][0]; - double y1 = rGeometry[0][1]; - double z1 = rGeometry[0][2]; - double x2 = rGeometry[1][0]; - double y2 = rGeometry[1][1]; - double z2 = rGeometry[1][2]; - - double dx = (x2 - x1) / NumberOfSegments; - double dy = (y2 - y1) / NumberOfSegments; - double dz = (z2 - z1) / NumberOfSegments; - - for(SizeType i = 1 ; i < NumberOfSegments - 1 ; i++) - { - ThisModelPart.CreateNewNode(StartNodeId++, x1 + i * dx, y1 + i * dy, z1 + i * dz); - } - } - - ///@} - ///@name Private Access - ///@{ + /// Per-node inside flag populated by CalculateIsInside() (2D only). + std::vector mIsInside; + /// Accumulated boundary normals at each source-model-part node (2D only). + std::vector> mNormals; ///@} - ///@name Private Inquiry + ///@name Private Operations ///@{ + /** + * @brief Creates equally-spaced intermediate nodes along a geometry edge. + * @param rThisModelPart Model part in which to create the nodes. + * @param rGeometry Two-node edge geometry. + * @param NumberOfSegments Number of segments to divide the edge into; + * (NumberOfSegments - 1) new nodes are created (endpoints excluded). + * @param StartNodeId First node ID to assign; incremented for each new node. + */ + void GenerateNodes(ModelPart& rThisModelPart, GeometryType& rGeometry, + SizeType NumberOfSegments, SizeType StartNodeId); ///@} - ///@name Un accessible methods + ///@name Inaccessible methods ///@{ - /// Assignment operator. - CartesianMeshGeneratorModeler& operator=(CartesianMeshGeneratorModeler const& rOther); - - /// Copy constructor. - CartesianMeshGeneratorModeler(CartesianMeshGeneratorModeler const& rOther); - + CartesianMeshGeneratorModeler& operator=(CartesianMeshGeneratorModeler const& rOther) = delete; + CartesianMeshGeneratorModeler(CartesianMeshGeneratorModeler const& rOther) = delete; ///@} @@ -621,34 +329,17 @@ class CartesianMeshGeneratorModeler : public Modeler ///@} -///@name Type Definitions -///@{ +/// @brief Input stream operator (no-op). +inline std::istream& operator>>(std::istream& rIStream, CartesianMeshGeneratorModeler& rThis) { return rIStream; } - -///@} -///@name Input and output -///@{ - - -/// input stream function -inline std::istream& operator >> (std::istream& rIStream, - CartesianMeshGeneratorModeler& rThis); - -/// output stream function -inline std::ostream& operator << (std::ostream& rOStream, - const CartesianMeshGeneratorModeler& rThis) +/// @brief Output stream operator — prints Info() followed by PrintData(). +inline std::ostream& operator<<(std::ostream& rOStream, const CartesianMeshGeneratorModeler& rThis) { rThis.PrintInfo(rOStream); rOStream << std::endl; rThis.PrintData(rOStream); - return rOStream; } -///@} - - -} // namespace Kratos. - -#endif // KRATOS_CARTESIAN_MESH_GENERATOR_H_INCLUDED defined +} // namespace Kratos From 7bebcabfa82a064b9feec853dc6c7060f6f8668b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 16:04:38 +0200 Subject: [PATCH 02/50] [Python] Add CartesianMeshGeneratorModeler to Python bindings --- kratos/python/add_modeler_to_python.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kratos/python/add_modeler_to_python.cpp b/kratos/python/add_modeler_to_python.cpp index 45e0f56f86b2..919ed4705cf4 100644 --- a/kratos/python/add_modeler_to_python.cpp +++ b/kratos/python/add_modeler_to_python.cpp @@ -28,6 +28,7 @@ #include "modeler/combine_model_part_modeler.h" #include "modeler/voxel_mesh_generator_modeler.h" #include "modeler/clean_up_problematic_triangles_modeler.h" +#include "modeler/cartesian_mesh_generator_modeler.h" namespace Kratos::Python { @@ -122,6 +123,14 @@ void AddModelerToPython(pybind11::module& m) py::class_(m, "CleanUpProblematicTrianglesModeler") .def(py::init()) ; + + py::class_(m, "CartesianMeshGeneratorModeler") + .def(py::init()) + .def(py::init()) + .def("GenerateMesh", [](CartesianMeshGeneratorModeler& self, ModelPart& rModelPart, const std::string& rElementName) { + self.GenerateMesh(rModelPart, KratosComponents::Get(rElementName)); + }) + ; } } // namespace Kratos::Python. \ No newline at end of file From 7b46d3b9775f23af25a0dbf7c0607927bcd052f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 16:04:47 +0200 Subject: [PATCH 03/50] Add CartesianMeshGeneratorModeler to KratosApplication --- kratos/includes/kratos_application.h | 2 ++ kratos/sources/kratos_application.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/kratos/includes/kratos_application.h b/kratos/includes/kratos_application.h index f3ffa3c50243..5bad37c27933 100644 --- a/kratos/includes/kratos_application.h +++ b/kratos/includes/kratos_application.h @@ -81,6 +81,7 @@ #include "modeler/combine_model_part_modeler.h" #include "modeler/connectivity_preserve_modeler.h" #include "modeler/voxel_mesh_generator_modeler.h" +#include "modeler/cartesian_mesh_generator_modeler.h" #include "modeler/clean_up_problematic_triangles_modeler.h" namespace Kratos { @@ -571,6 +572,7 @@ class KRATOS_API(KRATOS_CORE) KratosApplication { const CombineModelPartModeler mCombineModelPartModeler; const ConnectivityPreserveModeler mConnectivityPreserveModeler; const VoxelMeshGeneratorModeler mVoxelMeshGeneratorModeler; + const CartesianMeshGeneratorModeler mCartesianMeshGeneratorModeler; const CleanUpProblematicTrianglesModeler mCleanUpProblematicTrianglesModeler; // Base constitutive law definition diff --git a/kratos/sources/kratos_application.cpp b/kratos/sources/kratos_application.cpp index 1cd550418682..afa802ea5b1a 100644 --- a/kratos/sources/kratos_application.cpp +++ b/kratos/sources/kratos_application.cpp @@ -272,6 +272,7 @@ void KratosApplication::RegisterKratosCore() { KRATOS_REGISTER_MODELER("CombineModelPartModeler", mCombineModelPartModeler); KRATOS_REGISTER_MODELER("ConnectivityPreserveModeler", mConnectivityPreserveModeler); KRATOS_REGISTER_MODELER("VoxelMeshGeneratorModeler", mVoxelMeshGeneratorModeler); + KRATOS_REGISTER_MODELER("CartesianMeshGeneratorModeler", mCartesianMeshGeneratorModeler); KRATOS_REGISTER_MODELER("CleanUpProblematicTrianglesModeler", mCleanUpProblematicTrianglesModeler); // Register general geometries: From 8b5d462b947754d0c1566ac758f992ad244055c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 16:04:54 +0200 Subject: [PATCH 04/50] Add unit tests for CartesianMeshGeneratorModeler functionality --- .../test_cartesian_mesh_generator_modeler.cpp | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp diff --git a/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp b/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp new file mode 100644 index 000000000000..7f0984ff25cd --- /dev/null +++ b/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp @@ -0,0 +1,192 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Jordi Cotela Dalmau +// + +// System includes + +// External includes + +// Project includes +#include "testing/testing.h" +#include "containers/model.h" +#include "includes/element.h" +#include "includes/kratos_components.h" +#include "modeler/cartesian_mesh_generator_modeler.h" + +namespace Kratos::Testing +{ + +namespace { + +/// Build a square 2x2 bounding-box model part with 8 corner nodes only (no elements), +/// so the node-based BB fallback is exercised. +ModelPart& CreateBoxSourceModelPart(Model& rModel, const std::string& rName, + double xMin, double yMin, double zMin, + double xMax, double yMax, double zMax) +{ + auto& r_mp = rModel.CreateModelPart(rName); + r_mp.CreateNewNode(1, xMin, yMin, zMin); + r_mp.CreateNewNode(2, xMax, yMin, zMin); + r_mp.CreateNewNode(3, xMax, yMax, zMin); + r_mp.CreateNewNode(4, xMin, yMax, zMin); + r_mp.CreateNewNode(5, xMin, yMin, zMax); + r_mp.CreateNewNode(6, xMax, yMin, zMax); + r_mp.CreateNewNode(7, xMax, yMax, zMax); + r_mp.CreateNewNode(8, xMin, yMax, zMax); + return r_mp; +} + +} // anonymous namespace + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test that GenerateMesh (direct API) fills a 3D model part with the correct +/// node and element counts for a unit-cube source with a given element size. +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DNodeCount, KratosCoreFastSuite) +{ + Model model; + // 1x1x1 box, element size 0.5 → 2 segments per direction → 3^3=27 nodes, 2^3*6=48 tets + auto& r_source = CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + auto& r_output = model.CreateModelPart("output"); + r_output.CreateNewProperties(0); + + CartesianMeshGeneratorModeler modeler(r_source, 0.5); + modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + + // 3 nodes per direction → 27 total + KRATOS_EXPECT_EQ(r_output.NumberOfNodes(), 27u); + // 2 cells per direction → 8 hex cells × 6 tets = 48 tetrahedra + KRATOS_EXPECT_EQ(r_output.NumberOfElements(), 48u); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test that every generated node lies inside (or on the boundary of) the source BB. +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DNodesInsideBB, KratosCoreFastSuite) +{ + Model model; + auto& r_source = CreateBoxSourceModelPart(model, "source", -1.0, -1.0, -1.0, 1.0, 1.0, 1.0); + auto& r_output = model.CreateModelPart("output"); + r_output.CreateNewProperties(0); + + CartesianMeshGeneratorModeler modeler(r_source, 0.5); + modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + + for (const auto& r_node : r_output.Nodes()) { + KRATOS_EXPECT_GE(r_node.X(), -1.0 - 1e-12); + KRATOS_EXPECT_LE(r_node.X(), 1.0 + 1e-12); + KRATOS_EXPECT_GE(r_node.Y(), -1.0 - 1e-12); + KRATOS_EXPECT_LE(r_node.Y(), 1.0 + 1e-12); + KRATOS_EXPECT_GE(r_node.Z(), -1.0 - 1e-12); + KRATOS_EXPECT_LE(r_node.Z(), 1.0 + 1e-12); + } +} + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test that each element has exactly 4 nodes (tetrahedron) and that all node IDs +/// reference nodes that are present in the output model part. +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DElementConnectivity, KratosCoreFastSuite) +{ + Model model; + auto& r_source = CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + auto& r_output = model.CreateModelPart("output"); + r_output.CreateNewProperties(0); + + CartesianMeshGeneratorModeler modeler(r_source, 1.0); + modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + + // 1 cell per direction, 6 tets + KRATOS_EXPECT_EQ(r_output.NumberOfElements(), 6u); + + for (const auto& r_elem : r_output.Elements()) { + KRATOS_EXPECT_EQ(r_elem.GetGeometry().size(), 4u); + for (unsigned int n = 0; n < 4; ++n) { + const auto node_id = r_elem.GetGeometry()[n].Id(); + KRATOS_EXPECT_TRUE(r_output.HasNode(node_id)); + } + } +} + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test the factory / registry constructor (Model + Parameters) via SetupModelPart(). +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModelerSetupModelPart, KratosCoreFastSuite) +{ + Model model; + CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 2.0, 2.0, 2.0); + + Parameters params(R"({ + "input_model_part_name" : "source", + "output_model_part_name" : "output", + "element_name" : "Element3D4N", + "element_size" : 1.0 + })"); + + CartesianMeshGeneratorModeler modeler(model, params); + modeler.SetupModelPart(); + + const auto& r_output = model.GetModelPart("output"); + // 2x2x2 box, element size 1 → 3^3=27 nodes, 2^3*6=48 tets + KRATOS_EXPECT_EQ(r_output.NumberOfNodes(), 27u); + KRATOS_EXPECT_EQ(r_output.NumberOfElements(), 48u); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test that the bounding box helper correctly handles a node-only model part +/// (no elements), which is the typical output of StlIO (conditions only). +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModelerBoundingBoxNodeOnly, KratosCoreFastSuite) +{ + Model model; + auto& r_source = CreateBoxSourceModelPart(model, "source", -2.0, -3.0, -4.0, 2.0, 3.0, 4.0); + auto& r_output = model.CreateModelPart("output"); + r_output.CreateNewProperties(0); + + CartesianMeshGeneratorModeler modeler(r_source, 2.0); + Point min_pt, max_pt; + modeler.CalculateBoundingBox(r_source, min_pt, max_pt); + + KRATOS_EXPECT_NEAR(min_pt.X(), -2.0, 1e-12); + KRATOS_EXPECT_NEAR(min_pt.Y(), -3.0, 1e-12); + KRATOS_EXPECT_NEAR(min_pt.Z(), -4.0, 1e-12); + KRATOS_EXPECT_NEAR(max_pt.X(), 2.0, 1e-12); + KRATOS_EXPECT_NEAR(max_pt.Y(), 3.0, 1e-12); + KRATOS_EXPECT_NEAR(max_pt.Z(), 4.0, 1e-12); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +/// Test CalculateDivisionNumbers: exact multiples produce the right segment count. +KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModelerDivisionNumbers, KratosCoreFastSuite) +{ + Model model; + // 3x2x1 box, element size 0.5 → 6, 4, 2 segments + auto& r_source = CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 3.0, 2.0, 1.0); + auto& r_output = model.CreateModelPart("output"); + r_output.CreateNewProperties(0); + + CartesianMeshGeneratorModeler modeler(r_source, 0.5); + modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + + // (6+1)*(4+1)*(2+1) = 7*5*3 = 105 nodes + KRATOS_EXPECT_EQ(r_output.NumberOfNodes(), 105u); + // 6*4*2*6 = 288 tetrahedra + KRATOS_EXPECT_EQ(r_output.NumberOfElements(), 288u); +} + +} // namespace Kratos::Testing From 09af01bee340d9464135fa9122164d02dbabfd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 16:05:01 +0200 Subject: [PATCH 05/50] Add tests for CartesianMeshGeneratorModeler functionality --- kratos/tests/test_KratosCore.py | 2 + .../test_cartesian_mesh_generator_modeler.py | 188 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 kratos/tests/test_cartesian_mesh_generator_modeler.py diff --git a/kratos/tests/test_KratosCore.py b/kratos/tests/test_KratosCore.py index 674c707f139d..892819a2ede9 100644 --- a/kratos/tests/test_KratosCore.py +++ b/kratos/tests/test_KratosCore.py @@ -100,6 +100,7 @@ import test_import_obj_modeler import test_vectorized_interpolation import test_clean_up_problematic_triangles_modeler +import test_cartesian_mesh_generator_modeler import test_tetrahedral_mesh_orientation_check import test_nd_data import test_tensor_adaptors @@ -230,6 +231,7 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_import_obj_modeler.TestImportOBJModeler])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vectorized_interpolation.TestVectorizedInterpolation])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_clean_up_problematic_triangles_modeler.TestCleanUpProblematicTrianglesModeler])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_cartesian_mesh_generator_modeler.TestCartesianMeshGeneratorModeler])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_tetrahedral_mesh_orientation_check.TestTetrahedralMeshOrientationCheck])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_nd_data.TestNDData])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_tensor_adaptors.TestTensorAdaptors])) diff --git a/kratos/tests/test_cartesian_mesh_generator_modeler.py b/kratos/tests/test_cartesian_mesh_generator_modeler.py new file mode 100644 index 000000000000..6b4495aeed86 --- /dev/null +++ b/kratos/tests/test_cartesian_mesh_generator_modeler.py @@ -0,0 +1,188 @@ +import KratosMultiphysics +import KratosMultiphysics.KratosUnittest as KratosUnittest + + +def _CreateBoxSourceModelPart(model, name, x_min, y_min, z_min, x_max, y_max, z_max): + """Create a model part containing only the 8 corner nodes of an axis-aligned box.""" + mp = model.CreateModelPart(name) + mp.CreateNewNode(1, x_min, y_min, z_min) + mp.CreateNewNode(2, x_max, y_min, z_min) + mp.CreateNewNode(3, x_max, y_max, z_min) + mp.CreateNewNode(4, x_min, y_max, z_min) + mp.CreateNewNode(5, x_min, y_min, z_max) + mp.CreateNewNode(6, x_max, y_min, z_max) + mp.CreateNewNode(7, x_max, y_max, z_max) + mp.CreateNewNode(8, x_min, y_max, z_max) + return mp + + +class TestCartesianMeshGeneratorModeler(KratosUnittest.TestCase): + + # ------------------------------------------------------------------ + # Direct API (ModelPart + element_size constructor) + # ------------------------------------------------------------------ + + def test_3d_node_count(self): + """1x1x1 box, element_size=0.5 → 3^3=27 nodes, 2^3*6=48 tets.""" + model = KratosMultiphysics.Model() + source = _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + output = model.CreateModelPart("output") + output.CreateNewProperties(0) + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, 0.5) + modeler.GenerateMesh(output, "Element3D4N") + + self.assertEqual(output.NumberOfNodes(), 27) + self.assertEqual(output.NumberOfElements(), 48) + + def test_3d_nodes_inside_bounding_box(self): + """All generated nodes must lie inside (or on the boundary of) the source BB.""" + model = KratosMultiphysics.Model() + source = _CreateBoxSourceModelPart(model, "source", -1.0, -1.0, -1.0, 1.0, 1.0, 1.0) + output = model.CreateModelPart("output") + output.CreateNewProperties(0) + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, 0.5) + modeler.GenerateMesh(output, "Element3D4N") + + tol = 1e-12 + for node in output.Nodes: + self.assertGreaterEqual(node.X, -1.0 - tol) + self.assertLessEqual(node.X, 1.0 + tol) + self.assertGreaterEqual(node.Y, -1.0 - tol) + self.assertLessEqual(node.Y, 1.0 + tol) + self.assertGreaterEqual(node.Z, -1.0 - tol) + self.assertLessEqual(node.Z, 1.0 + tol) + + def test_3d_element_connectivity(self): + """Each element must have 4 nodes that exist in the output model part.""" + model = KratosMultiphysics.Model() + source = _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + output = model.CreateModelPart("output") + output.CreateNewProperties(0) + + # element_size = 1.0 → 1 cell per direction → 6 tetrahedra + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, 1.0) + modeler.GenerateMesh(output, "Element3D4N") + + self.assertEqual(output.NumberOfElements(), 6) + node_ids = {node.Id for node in output.Nodes} + for elem in output.Elements: + self.assertEqual(len(elem.GetNodes()), 4) + for node in elem.GetNodes(): + self.assertIn(node.Id, node_ids) + + def test_3d_non_unit_box(self): + """3x2x1 box, element_size=0.5 → 7*5*3=105 nodes, 6*4*2*6=288 tets.""" + model = KratosMultiphysics.Model() + source = _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 3.0, 2.0, 1.0) + output = model.CreateModelPart("output") + output.CreateNewProperties(0) + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, 0.5) + modeler.GenerateMesh(output, "Element3D4N") + + self.assertEqual(output.NumberOfNodes(), 105) + self.assertEqual(output.NumberOfElements(), 288) + + def test_3d_uniform_spacing(self): + """Node coordinates should be uniformly spaced by element_size.""" + model = KratosMultiphysics.Model() + source = _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + output = model.CreateModelPart("output") + output.CreateNewProperties(0) + + element_size = 0.5 + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, element_size) + modeler.GenerateMesh(output, "Element3D4N") + + # Collect unique X values and check spacing + xs = sorted({round(node.X, 10) for node in output.Nodes}) + for i in range(1, len(xs)): + self.assertAlmostEqual(xs[i] - xs[i-1], element_size, places=10) + + # ------------------------------------------------------------------ + # Factory / registry constructor (Model + Parameters) + # ------------------------------------------------------------------ + + def test_setup_model_part(self): + """SetupModelPart() via factory constructor must produce the same mesh.""" + model = KratosMultiphysics.Model() + _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 2.0, 2.0, 2.0) + + params = KratosMultiphysics.Parameters("""{ + "input_model_part_name" : "source", + "output_model_part_name" : "output", + "element_name" : "Element3D4N", + "element_size" : 1.0 + }""") + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(model, params) + modeler.SetupModelPart() + + output = model.GetModelPart("output") + # 2x2x2 box, element_size=1 → 3^3=27 nodes, 2^3*6=48 tets + self.assertEqual(output.NumberOfNodes(), 27) + self.assertEqual(output.NumberOfElements(), 48) + + def test_setup_model_part_creates_output(self): + """SetupModelPart() must create the output model part if it does not exist.""" + model = KratosMultiphysics.Model() + _CreateBoxSourceModelPart(model, "box", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + + params = KratosMultiphysics.Parameters("""{ + "input_model_part_name" : "box", + "output_model_part_name" : "mesh", + "element_name" : "Element3D4N", + "element_size" : 1.0 + }""") + + KratosMultiphysics.CartesianMeshGeneratorModeler(model, params).SetupModelPart() + self.assertTrue(model.HasModelPart("mesh")) + + def test_missing_input_name_raises(self): + """Empty input_model_part_name must raise an error.""" + model = KratosMultiphysics.Model() + model.CreateModelPart("source") + + params = KratosMultiphysics.Parameters("""{ + "input_model_part_name" : "", + "output_model_part_name" : "output", + "element_name" : "Element3D4N", + "element_size" : 1.0 + }""") + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(model, params) + with self.assertRaises(RuntimeError): + modeler.SetupModelPart() + + def test_missing_output_name_raises(self): + """Empty output_model_part_name must raise an error.""" + model = KratosMultiphysics.Model() + _CreateBoxSourceModelPart(model, "source", 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + + params = KratosMultiphysics.Parameters("""{ + "input_model_part_name" : "source", + "output_model_part_name" : "", + "element_name" : "Element3D4N", + "element_size" : 1.0 + }""") + + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(model, params) + with self.assertRaises(RuntimeError): + modeler.SetupModelPart() + + # ------------------------------------------------------------------ + # Info / string interface + # ------------------------------------------------------------------ + + def test_info(self): + """Info() must return the class name.""" + model = KratosMultiphysics.Model() + source = model.CreateModelPart("source") + modeler = KratosMultiphysics.CartesianMeshGeneratorModeler(source, 1.0) + self.assertEqual(str(modeler).strip(), "CartesianMeshGeneratorModeler") + +if __name__ == '__main__': + KratosMultiphysics.Logger.GetDefaultOutput().SetSeverity(KratosMultiphysics.Logger.Severity.WARNING) + KratosUnittest.main() From 9008d33619529ddd741552a38ac8386a4c5c1b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 5 Jun 2026 17:46:54 +0200 Subject: [PATCH 06/50] Enhance CartesianMeshGeneratorModeler to set nodal solution step variables and buffer size during mesh generation --- .../modeler/cartesian_mesh_generator_modeler.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/kratos/modeler/cartesian_mesh_generator_modeler.cpp b/kratos/modeler/cartesian_mesh_generator_modeler.cpp index a05e3a0a8d79..d19934f604a7 100644 --- a/kratos/modeler/cartesian_mesh_generator_modeler.cpp +++ b/kratos/modeler/cartesian_mesh_generator_modeler.cpp @@ -137,6 +137,8 @@ void CartesianMeshGeneratorModeler::GenerateMesh( ModelPart::NodesContainerType::ContainerType& r_nodes_array = rModelPart.NodesArray(); r_nodes_array.resize(total_nodes); + auto p_variables_list = rModelPart.pGetNodalSolutionStepVariablesList(); + const SizeType buffer_size = rModelPart.GetBufferSize(); for (unsigned int k = 0; k < nz; k++) { for (unsigned int j = 0; j < ny; j++) { for (unsigned int i = 0; i < nx; i++) { @@ -145,6 +147,8 @@ void CartesianMeshGeneratorModeler::GenerateMesh( x0 + i * mElementSize, y0 + j * mElementSize, z0 + k * mElementSize)); + p_node->SetSolutionStepVariablesList(p_variables_list); + p_node->SetBufferSize(buffer_size); node_ptrs[NodeIdx3D(i,j,k)] = p_node; r_nodes_array[NodeIdx3D(i,j,k)] = p_node; } @@ -226,14 +230,20 @@ void CartesianMeshGeneratorModeler::GenerateMesh( ModelPart::ElementsContainerType::ContainerType& r_elements_array = rModelPart.ElementsArray(); + auto p_variables_list = rModelPart.pGetNodalSolutionStepVariablesList(); + const SizeType buffer_size = rModelPart.GetBufferSize(); for (unsigned int k = 0; k < mDivisionsNumber[2]; k++) for (unsigned int j = 0; j < mDivisionsNumber[1]; j++) - for (unsigned int i = 0; i < mDivisionsNumber[0]; i++) - temp_nodes_array[NodeIndex(i,j,k)] = Node::Pointer(new Node( + for (unsigned int i = 0; i < mDivisionsNumber[0]; i++) { + auto p_node = Node::Pointer(new Node( start_node_id++, x0 + i * mElementSize, y0 + j * mElementSize, z0 + k * mElementSize)); + p_node->SetSolutionStepVariablesList(p_variables_list); + p_node->SetBufferSize(buffer_size); + temp_nodes_array[NodeIndex(i,j,k)] = p_node; + } unsigned int number_of_active_nodes = 0; for (unsigned int i = 0; i < number_of_nodes; i++) @@ -528,4 +538,4 @@ void CartesianMeshGeneratorModeler::PrintData(std::ostream& rOStream) const { } -} // namespace Kratos +} // namespace Kratos \ No newline at end of file From fcd68be27899f69bde01481c894c821d36b30bef Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 17 Apr 2026 12:13:05 +0200 Subject: [PATCH 07/50] add vtm multi block output and .series output --- kratos/input_output/vtu_output.cpp | 323 ++++++++--------------------- kratos/input_output/vtu_output.h | 10 +- 2 files changed, 100 insertions(+), 233 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 636b95dd91f5..508467c79428 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -139,15 +139,6 @@ std::string GetEntityName(const std::optional NDDataPointerType GetWritingNDData( const std::vector& rWritingIndices, @@ -648,113 +639,6 @@ const typename VtuOutput::DataList::value_type& GetContainerMap( }, pCellPointer); } -std::string WritePartitionedUnstructuredGridData( - XmlElementsArray& rPointDataElement, - XmlElementsArray& rCellDataElement, - const std::string& rOutputVtuFileName, - const DataCommunicator& rDataCommunicator) -{ - const int writing_rank = 0; - - // remove the rank from the rOutputVtuFileName. - const auto& r_base_name = rOutputVtuFileName.substr(0, rOutputVtuFileName.rfind("_")); - - const auto& p_vtu_file_name = r_base_name + ".pvtu"; - - if (rDataCommunicator.Rank() == writing_rank) { - // create the pvtu file - XmlElementsArray p_vtu_file_element("VTKFile"); - p_vtu_file_element.AddAttribute("type", "PUnstructuredGrid"); - p_vtu_file_element.AddAttribute("version", "0.1"); - p_vtu_file_element.AddAttribute("byte_order", GetEndianness()); - - // create the unstructured grid - auto p_unstructured_grid_element = Kratos::make_shared("PUnstructuredGrid"); - p_unstructured_grid_element->AddAttribute("GhostLevel", "0"); - p_vtu_file_element.AddElement(p_unstructured_grid_element); - - // ppoints_element - auto p_points_element = Kratos::make_shared("PPoints"); - p_unstructured_grid_element->AddElement(p_points_element); - - // position element - auto p_position_element = Kratos::make_shared("PDataArray"); - p_position_element->AddAttribute("type", "Float64"); - p_position_element->AddAttribute("Name", "Position"); - p_position_element->AddAttribute("NumberOfComponents", "3"); - p_points_element->AddElement(p_position_element); - - // pcells element - auto p_cells_element = Kratos::make_shared("PCells"); - p_unstructured_grid_element->AddElement(p_cells_element); - - // connectivity element - auto p_connectivity_element = Kratos::make_shared("PDataArray"); - p_connectivity_element->AddAttribute("type", "Int32"); - p_connectivity_element->AddAttribute("Name", "connectivity"); - p_connectivity_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_connectivity_element); - - // offsets element - auto p_offsets_element = Kratos::make_shared("PDataArray"); - p_offsets_element->AddAttribute("type", "Int32"); - p_offsets_element->AddAttribute("Name", "offsets"); - p_offsets_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_offsets_element); - - // types element - auto p_types_element = Kratos::make_shared("PDataArray"); - p_types_element->AddAttribute("type", "UInt8"); - p_types_element->AddAttribute("Name", "types"); - p_types_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_types_element); - - // ppoint data element - auto p_point_data_element = Kratos::make_shared("PPointData"); - p_unstructured_grid_element->AddElement(p_point_data_element); - - // now add the point data fields - for (const auto& p_element : rPointDataElement.GetElements()) { - auto p_current_element = Kratos::make_shared("PDataArray"); - CopyAttributes(*p_element, *p_current_element); - p_point_data_element->AddElement(p_current_element); - } - - // pcell data element - auto p_cell_data_element = Kratos::make_shared("PCellData"); - p_unstructured_grid_element->AddElement(p_cell_data_element); - - // now add the cell data fields - for (const auto& p_element : rCellDataElement.GetElements()) { - auto p_current_element = Kratos::make_shared("PDataArray"); - CopyAttributes(*p_element, *p_current_element); - p_cell_data_element->AddElement(p_current_element); - } - - // now add the piece elements - for (int i_rank = 0; i_rank < rDataCommunicator.Size(); ++i_rank) { - const auto& r_file_name = r_base_name + "_" + std::to_string(i_rank) + ".vtu"; - auto piece = Kratos::make_shared("Piece"); - // since we are writing to the same folder the pvtu files - piece->AddAttribute( - "Source", std::filesystem::relative( - std::filesystem::absolute(r_file_name), - std::filesystem::absolute(p_vtu_file_name).parent_path()) - .generic_string()); - p_unstructured_grid_element->AddElement(piece); - } - - // writing to file - std::ofstream output_file; - output_file.open(p_vtu_file_name, std::ios::out | std::ios::trunc); - output_file << "" << std::endl; - p_vtu_file_element.Write(output_file); - - } - - return p_vtu_file_name; -} - template void PrintLocationData( std::ostream& rOStream, @@ -844,7 +728,7 @@ VtuOutput::VtuOutput( const bool OutputSubModelParts, const bool WriteIds, const IndexType EchoLevel) - : mIsPVDFileHeaderWritten(false), + : mIsSeriesFileHeaderWritten(false), mrModelPart(rModelPart), mConfiguration(IsInitialConfiguration ? Globals::Configuration::Initial : Globals::Configuration::Current), mEchoLevel(EchoLevel), @@ -913,7 +797,7 @@ void VtuOutput::AddFlag( { KRATOS_TRY - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + KRATOS_ERROR_IF(mIsSeriesFileHeaderWritten) << "Flags can be added only before the first call to the PrintOutput [ flag name = " << rFlagName << " ].\n"; @@ -957,7 +841,7 @@ void VtuOutput::AddVariable( { KRATOS_TRY - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + KRATOS_ERROR_IF(mIsSeriesFileHeaderWritten) << "Variables can be added only before the first call to the PrintOutput [ variable name = " << rVariable.Name() << " ].\n"; @@ -1007,7 +891,7 @@ void VtuOutput::AddIntegrationPointVariable( { KRATOS_TRY - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + KRATOS_ERROR_IF(mIsSeriesFileHeaderWritten) << "Integration point variables can be added only before the first call to the PrintOutput [ integration point variable name = " << rVariable.Name() << " ].\n"; @@ -1038,7 +922,7 @@ void VtuOutput::AddTensorAdaptor( { KRATOS_TRY - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + KRATOS_ERROR_IF(mIsSeriesFileHeaderWritten) << "TensorAdaptors can be added only before the first call to the PrintOutput [ tensor adaptor name = " << rTensorAdaptorName << " ].\n"; @@ -1162,7 +1046,7 @@ void VtuOutput::EmplaceTensorAdaptor( const std::string& rTensorAdaptorName, TTensorAdaptorPointerType pTensorAdaptor) { - if (!mIsPVDFileHeaderWritten) { + if (!mIsSeriesFileHeaderWritten) { AddTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); } else { ReplaceTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); @@ -1254,7 +1138,7 @@ std::pair VtuOutput::WriteUnstructuredGridData( // identify suffix with the entity type. const std::string& suffix = "_" + GetEntityName(rUnstructuredGridData.mpCells) + "s"; - const std::string pvd_data_set_name = rUnstructuredGridData.mpModelPart->FullName() + suffix; + const std::string block_name = rUnstructuredGridData.mpModelPart->FullName() + suffix; // append with the step value and rank and extension output_vtu_file_name << suffix << "_" << Step @@ -1270,16 +1154,8 @@ std::pair VtuOutput::WriteUnstructuredGridData( vtk_file_element.Write(output_file); output_file.close(); - // if it is run on a distributed system, create the pvtu file. - if (r_data_communicator.IsDistributed()) { - return std::make_pair(pvd_data_set_name, - WritePartitionedUnstructuredGridData( - *point_data_element, *cell_data_element, - output_vtu_file_name.str(), r_data_communicator)); - } - // return the final file name for - return std::make_pair(pvd_data_set_name, output_vtu_file_name.str()); + return std::make_pair(block_name, output_vtu_file_name.str()); } template @@ -1450,14 +1326,6 @@ std::pair VtuOutput::WriteIntegrationPointData( vtk_file_element.Write(output_file); output_file.close(); - if (r_data_communicator.IsDistributed()) { - return std::make_pair( - rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", - WritePartitionedUnstructuredGridData( - *point_data_element, *Kratos::make_shared(""), - output_vtu_file_name.str(), r_data_communicator)); - } - return std::make_pair(rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", output_vtu_file_name.str()); } @@ -1468,7 +1336,7 @@ std::pair VtuOutput::WriteIntegrationPointData( template void VtuOutput::WriteData( - std::vector>& rPVDFileNameInfo, + std::vector>& rBlockFileNameInfo, TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, UnstructuredGridData& rUnstructuredGridData, @@ -1477,11 +1345,11 @@ void VtuOutput::WriteData( { KRATOS_TRY - rPVDFileNameInfo.push_back(WriteUnstructuredGridData( + rBlockFileNameInfo.push_back(WriteUnstructuredGridData( rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, rUnstructuredGridData, rOutputPrefix, Step)); - rPVDFileNameInfo.push_back(WriteIntegrationPointData( + rBlockFileNameInfo.push_back(WriteIntegrationPointData( rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, rUnstructuredGridData, rOutputPrefix, Step)); @@ -1490,154 +1358,147 @@ void VtuOutput::WriteData( void VtuOutput::PrintOutput(const std::string& rOutputFileNamePrefix) { - KRATOS_TRY - const auto& r_process_info = mrModelPart.GetProcessInfo(); + PrintOutput(rOutputFileNamePrefix, r_process_info[STEP], r_process_info[TIME]); +} - // here we do not check whether the r_process_info has the time variable specified - // because, in a const DataValueContainer, if the variable is not there, it returns the - // zero value of the variable. - const double time = r_process_info[TIME]; - const IndexType step = r_process_info[STEP]; +void VtuOutput::PrintOutput( + const std::string& rOutputFileNamePrefix, + const int Step, + const double Time) +{ + KRATOS_TRY std::filesystem::create_directories(rOutputFileNamePrefix); - std::vector> pvd_file_name_info; + std::vector> block_file_name_info; for (auto& r_unstructured_grid_data : mUnstructuredGridDataList) { switch (mOutputFormat) { case ASCII: { WriteData( - pvd_file_name_info, + block_file_name_info, [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::ASCII, this->mPrecision); }, [](auto& rVtkFileElement, auto pXmlDataElementWrapper) {}, r_unstructured_grid_data, rOutputFileNamePrefix, - step); + Step); break; } case BINARY: { WriteData( - pvd_file_name_info, + block_file_name_info, [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::BINARY, this->mPrecision); }, [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddAttribute("header_type", "UInt64"); }, r_unstructured_grid_data, rOutputFileNamePrefix, - step); + Step); break; } case RAW: { WriteData( - pvd_file_name_info, + block_file_name_info, [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::RAW); }, [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); }, r_unstructured_grid_data, rOutputFileNamePrefix, - step); + Step); break; } case COMPRESSED_RAW: { WriteData( - pvd_file_name_info, + block_file_name_info, [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::COMPRESSED_RAW); }, [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); rVtkFileElement.AddAttribute("compressor", "vtkZLibDataCompressor"); }, r_unstructured_grid_data, rOutputFileNamePrefix, - step); + Step); break; } } } - // now generate the *.pvd file if (mrModelPart.GetCommunicator().MyPID() == 0) { + // now generate the multi block set *.vtm file for the current step KRATOS_INFO_IF("VtuOutput", mEchoLevel > 1) << "Writing \"" << mrModelPart.FullName() - << "\" PVD file...\n"; - // Single pvd file links all the vtu files from sum-model parts - // partitioned model_parts and time step vtu files together. - - if (!mIsPVDFileHeaderWritten) { - mIsPVDFileHeaderWritten = true; - - // creates the pvd file element - XmlElementsArray pvd_file_element("VTKFile"); - pvd_file_element.AddAttribute("type", "Collection"); - pvd_file_element.AddAttribute("version", "1.0"); - pvd_file_element.AddAttribute("byte_order", GetEndianness()); - - // creates the collection element - auto collection_element = Kratos::make_shared("Collection"); - pvd_file_element.AddElement(collection_element); - - // now iterate through all the time steps and correctly write - // the file names for each time step. - IndexType local_index = 0; - for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { - if (pvd_file_name_info[i].second != "") { - auto current_element = Kratos::make_shared("DataSet"); - - // write the time with the specified precision. - std::stringstream str_time; - str_time << std::scientific << std::setprecision(mPrecision) << time; - - current_element->AddAttribute("timestep", str_time.str()); - current_element->AddAttribute("name", pvd_file_name_info[i].first); - current_element->AddAttribute("part", std::to_string(local_index++)); - current_element->AddAttribute( - "file", std::filesystem::relative( - std::filesystem::absolute(pvd_file_name_info[i].second), - std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) - .generic_string()); - collection_element->AddElement(current_element); - } - } - - std::ofstream output_file; - output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::out | std::ios::trunc); - output_file << "" << std::endl; - pvd_file_element.Write(output_file); - output_file.close(); - } else { - std::ofstream output_file; - output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::in | std::ios::out); - output_file.seekp(-28, std::ios::end); - - // now iterate through all the time steps and correctly write - // the file names for each time step. - IndexType local_index = 0; - for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { - if (pvd_file_name_info[i].second != "") { - auto current_element = Kratos::make_shared("DataSet"); - - // write the time with the specified precision. - std::stringstream str_time; - str_time << std::scientific << std::setprecision(mPrecision) << time; - - current_element->AddAttribute("timestep", str_time.str()); - current_element->AddAttribute("name", pvd_file_name_info[i].first); - current_element->AddAttribute("part", std::to_string(local_index++)); - current_element->AddAttribute( - "file", std::filesystem::relative( - std::filesystem::absolute(pvd_file_name_info[i].second), + << "\" VTM file...\n"; + // Single vtm file links all the vtu files from sub-model parts + // partitioned model_parts vtu files together. + + // creates the vtm file element + XmlElementsArray vtm_file_element("VTKFile"); + vtm_file_element.AddAttribute("type", "vtkMultiBlockDataSet"); + vtm_file_element.AddAttribute("version", "1.0"); + vtm_file_element.AddAttribute("byte_order", GetEndianness()); + + // creates the collection element + auto multi_block_element = Kratos::make_shared("vtkMultiBlockDataSet"); + vtm_file_element.AddElement(multi_block_element); + + // now iterate through all the written blocks + IndexType local_index = 0; + for (IndexType i = 0; i < block_file_name_info.size(); ++i) { + if (block_file_name_info[i].second != "") { + auto current_block = Kratos::make_shared("Block"); + current_block->AddAttribute("index", std::to_string(local_index++)); + current_block->AddAttribute("name", block_file_name_info[i].first); + + const auto& r_base_name = (mrModelPart.GetCommunicator().IsDistributed()) ? block_file_name_info[i].second.substr(0, block_file_name_info[i].second.rfind("_")) : block_file_name_info[i].second; + for (int i_partition = 0; i_partition < mrModelPart.GetCommunicator().TotalProcesses(); ++i_partition) { + auto current_partition_element = Kratos::make_shared("DataSet"); + current_partition_element->AddAttribute("index", std::to_string(i_partition)); + current_partition_element->AddAttribute("file", std::filesystem::relative( + std::filesystem::absolute(r_base_name + ((mrModelPart.GetCommunicator().IsDistributed()) ? "_" + std::to_string(i_partition) + ".vtu" : "")), std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) .generic_string()); - current_element->Write(output_file, 2); + current_partition_element->AddAttribute("name", block_file_name_info[i].first + "_" + std::to_string(i_partition)); + current_block->AddElement(current_partition_element); } - } - output_file << " " << std::endl <<"" << std::endl; - output_file.close(); + multi_block_element->AddElement(current_block); + } } + std::ofstream output_file; + output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc); + output_file << "" << std::endl; + vtm_file_element.Write(output_file); + output_file.close(); + + std::stringstream str_time; + str_time << std::scientific << std::setprecision(mPrecision) << Time; + + const std::string relative_vtm_file_name = std::filesystem::relative(std::filesystem::absolute(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm"), + std::filesystem::absolute(rOutputFileNamePrefix).parent_path()).generic_string(); + + // now write the series file having the time + if (!mIsSeriesFileHeaderWritten) { + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::out | std::ios::trunc); + output_file << "{" << std::endl; + output_file << " \"file-series-version\" : \"1.0\"," << std::endl; + output_file << " \"files\" : [" << std::endl; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; + output_file << " ]" << std::endl; + output_file << "}"; + } else { + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out); + output_file.seekp(-8, std::ios::end); + output_file << "," << std::endl; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; + output_file << " ]" << std::endl; + output_file << "}"; + } } + mIsSeriesFileHeaderWritten = true; + KRATOS_CATCH(""); } diff --git a/kratos/input_output/vtu_output.h b/kratos/input_output/vtu_output.h index b711bc4395a7..be347137681a 100644 --- a/kratos/input_output/vtu_output.h +++ b/kratos/input_output/vtu_output.h @@ -308,7 +308,13 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO * * @param rOutputFilenamePrefix The prefix to use for the output filename. */ - void PrintOutput(const std::string& rOutputFilenamePrefix); + void PrintOutput( + const std::string& rOutputFilenamePrefix); + + void PrintOutput( + const std::string& rOutputFilenamePrefix, + const int Step, + const double Time); ///@} ///@name Input and output @@ -329,7 +335,7 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO ///@name Private member variables ///@{ - bool mIsPVDFileHeaderWritten; + bool mIsSeriesFileHeaderWritten; ModelPart& mrModelPart; From 0dcf606bc4dc2c7e86ef687f7c773ef5c4b42bb6 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 17 Apr 2026 12:13:39 +0200 Subject: [PATCH 08/50] expose to python --- kratos/python/add_io_to_python.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kratos/python/add_io_to_python.cpp b/kratos/python/add_io_to_python.cpp index e00219ab6a72..7d407621568b 100644 --- a/kratos/python/add_io_to_python.cpp +++ b/kratos/python/add_io_to_python.cpp @@ -248,7 +248,8 @@ void AddIOToPython(pybind11::module& m) .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) .def("GetModelPart", &VtuOutput::GetModelPart, py::return_value_policy::reference) .def("GetOutputContainerList", &VtuOutput::GetOutputContainerList) - .def("PrintOutput", &VtuOutput::PrintOutput, py::arg("output_file_name_prefix")) + .def("PrintOutput", py::overload_cast(&VtuOutput::PrintOutput), py::arg("output_file_name_prefix")) + .def("PrintOutput", py::overload_cast(&VtuOutput::PrintOutput), py::arg("output_file_name_prefix"), py::arg("step"), py::arg("time")) .def("__str__", PrintObject) ; From 9d3a4b1f4e539aabe457afb5b12041de9bf29a78 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 17 Apr 2026 12:13:51 +0200 Subject: [PATCH 09/50] update opt vtu output --- .../processes/optimization_problem_vtu_output_process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py index 872fbf7f27e4..3886aafecb8a 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py @@ -63,7 +63,7 @@ def WriteOutput(self): output_file_name = self.output_file_name_prefix output_file_name = output_file_name.replace("", self.model_part.FullName()) output_file_name = output_file_name.replace("", self.model_part.Name) - self.vtu_output.PrintOutput(str(self.output_path / output_file_name)) + self.vtu_output.PrintOutput(str(self.output_path / output_file_name), self.optimization_problem.GetStep(), self.optimization_problem.GetStep()) def __str__(self) -> str: return f"TensorAdaptorVtuOutput with \"{self.vtu_output.GetModelPart().FullName()}\"" From 3dffec290c9f1935430dcb81b1848c69776c1af4 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 17 Apr 2026 12:16:11 +0200 Subject: [PATCH 10/50] fix opt app test --- .../test_optimization_problem_field_output_process.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_field_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_field_output_process.py index a48f74e6d72d..f25f436565e0 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_field_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_field_output_process.py @@ -182,7 +182,7 @@ def test_OptimizationProblemVtuOutputProcess(self): CompareTwoFilesCheckProcess(Kratos.Parameters(""" { "reference_file_name" : "test_1_orig.vtu", - "output_file_name" : "Optimization_Results/test_1/test_1_elements_0.vtu", + "output_file_name" : "Optimization_Results/test_1/test_1_elements_9.vtu", "remove_output_file" : true, "comparison_type" : "vtu" }""")).Execute() @@ -190,7 +190,7 @@ def test_OptimizationProblemVtuOutputProcess(self): CompareTwoFilesCheckProcess(Kratos.Parameters(""" { "reference_file_name" : "test_2_orig.vtu", - "output_file_name" : "Optimization_Results/test_2/test_2_elements_0.vtu", + "output_file_name" : "Optimization_Results/test_2/test_2_elements_9.vtu", "remove_output_file" : true, "comparison_type" : "vtu" }""")).Execute() From 4aac3665da3cfbd6f3ff8a98808cb3e675e5f21b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 17 Apr 2026 14:46:13 +0200 Subject: [PATCH 11/50] update vtu output process --- kratos/python_scripts/vtu_output_process.py | 56 +++++++++------------ 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/kratos/python_scripts/vtu_output_process.py b/kratos/python_scripts/vtu_output_process.py index 30bd78ce3232..9a22b5892e00 100644 --- a/kratos/python_scripts/vtu_output_process.py +++ b/kratos/python_scripts/vtu_output_process.py @@ -2,7 +2,7 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.kratos_utilities as kratos_utils -def Factory(parameters: Kratos.Parameters, model: Kratos.Model): +def Factory(parameters: Kratos.Parameters, model: Kratos.Model) -> Kratos.OutputProcess: if not isinstance(parameters, Kratos.Parameters): raise Exception("expected input shall be a Parameters object, encapsulating a json string") if not isinstance(model, Kratos.Model): @@ -17,6 +17,7 @@ def GetDefaultParameters(self) -> Kratos.Parameters: { "model_part_name" : "PLEASE_SPECIFY_MODEL_PART_NAME", "file_format" : "binary", + "echo_level" : 0, "output_precision" : 7, "output_control_type" : "step", "output_interval" : 1.0, @@ -24,6 +25,7 @@ def GetDefaultParameters(self) -> Kratos.Parameters: "output_path" : "VTU_Output", "save_output_files_in_folder" : true, "write_deformed_configuration" : false, + "write_ids" : false, "nodal_solution_step_data_variables": [], "nodal_data_value_variables" : [], "nodal_flags" : [], @@ -40,7 +42,9 @@ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters) -> None: parameters.ValidateAndAssignDefaults(self.GetDefaultParameters()) self.model_part = model[parameters["model_part_name"].GetString()] + self.echo_level = parameters["echo_level"].GetInt() self.write_deformed_configuration = parameters["write_deformed_configuration"].GetBool() + self.write_ids = parameters["write_ids"].GetBool() self.output_precision = parameters["output_precision"].GetInt() self.output_sub_model_parts = parameters["output_sub_model_parts"].GetBool() @@ -57,8 +61,12 @@ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters) -> None: self.writer_format = Kratos.VtuOutput.ASCII elif file_format == "binary": self.writer_format = Kratos.VtuOutput.BINARY + elif file_format == "raw": + self.writer_format = Kratos.VtuOutput.RAW + elif file_format == "compressed_raw": + self.writer_format = Kratos.VtuOutput.COMPRESSED_RAW else: - raise RuntimeError(f"Unsupported file format requested [ requested format = {file_format} ]. Supported file formats:\n\tascii\n\tbinary") + raise RuntimeError(f"Unsupported file format requested [ requested format = {file_format} ]. Supported file formats:\n\tascii\n\tbinary\n\traw\n\tcompressed_raw") if parameters["save_output_files_in_folder"].GetBool(): self.output_path = Path(parameters["output_path"].GetString()) @@ -70,46 +78,30 @@ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters) -> None: else: self.output_path = Path(".") - self.vtu_output_ios: 'list[Kratos.VtuOutput]' = [] - self.__controller = Kratos.OutputController(model, parameters) def ExecuteInitialize(self) -> None: - # check and create all the vtu outputs - self.vtu_output_ios.append(Kratos.VtuOutput(self.model_part, not self.write_deformed_configuration, self.writer_format, self.output_precision)) - - if self.output_sub_model_parts: - for sub_model_part in self.model_part.SubModelParts: - self.vtu_output_ios.append(Kratos.VtuOutput(sub_model_part, not self.write_deformed_configuration, self.writer_format, self.output_precision)) - - for vtu_output_io in self.vtu_output_ios: - self.__AddData(vtu_output_io) - - def PrintOutput(self) -> None: - current_suffix = self.__controller.GetCurrentControlValue() - - for vtu_output in self.vtu_output_ios: - vtu_output.PrintOutput(f"{self.output_path / vtu_output.GetModelPart().FullName()}_{current_suffix}") - - self.__controller.Update() - - def IsOutputStep(self) -> bool: - return self.__controller.Evaluate() + self.vtu_output = Kratos.VtuOutput(self.model_part, not self.write_deformed_configuration, self.writer_format, self.output_precision, self.output_sub_model_parts, self.write_ids, self.echo_level) - def __AddData(self, vtu_output_io: Kratos.VtuOutput) -> None: for variable in self.nodal_solution_step_data_variables: - vtu_output_io.AddHistoricalVariable(Kratos.KratosGlobals.GetVariable(variable)) + self.vtu_output.AddVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.Globals.DataLocation.NodeHistorical) for variable in self.nodal_data_value_variables: - vtu_output_io.AddNonHistoricalVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.VtuOutput.NODES) + self.vtu_output.AddVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.Globals.DataLocation.NodeNonHistorical) for variable in self.condition_data_value_variables: - vtu_output_io.AddNonHistoricalVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.VtuOutput.CONDITIONS) + self.vtu_output.AddVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.Globals.DataLocation.Condition) for variable in self.element_data_value_variables: - vtu_output_io.AddNonHistoricalVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.VtuOutput.ELEMENTS) + self.vtu_output.AddVariable(Kratos.KratosGlobals.GetVariable(variable), Kratos.Globals.DataLocation.Element) for flag in self.nodal_flags: - vtu_output_io.AddFlagVariable(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.VtuOutput.NODES) + self.vtu_output.AddFlag(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.Globals.DataLocation.NodeNonHistorical) for flag in self.condition_flags: - vtu_output_io.AddFlagVariable(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.VtuOutput.CONDITIONS) + self.vtu_output.AddFlag(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.Globals.DataLocation.Condition) for flag in self.element_flags: - vtu_output_io.AddFlagVariable(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.VtuOutput.ELEMENTS) + self.vtu_output.AddFlag(flag, Kratos.KratosGlobals.GetFlag(flag), Kratos.Globals.DataLocation.Element) + def PrintOutput(self) -> None: + self.vtu_output.PrintOutput(f"{self.output_path / self.model_part.FullName()}") + self.__controller.Update() + + def IsOutputStep(self) -> bool: + return self.__controller.Evaluate() \ No newline at end of file From 08a49a430b382227eda40a3181b7971b09c471d3 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 2 May 2026 11:14:52 +0200 Subject: [PATCH 12/50] add vtm ref files --- .../ascii2D/Main.vtm.series | 6 ++++++ .../ascii2D/Main_0.vtm | 17 +++++++++++++++++ .../ascii3D/Main.vtm.series | 6 ++++++ .../ascii3D/Main_0.vtm | 11 +++++++++++ .../binary2D/Main.vtm.series | 6 ++++++ .../binary2D/Main_0.vtm | 17 +++++++++++++++++ .../binary3D/Main.vtm.series | 6 ++++++ .../binary3D/Main_0.vtm | 11 +++++++++++ .../compressed_raw2D/Main.vtm.series | 6 ++++++ .../compressed_raw2D/Main_0.vtm | 17 +++++++++++++++++ .../compressed_raw3D/Main.vtm.series | 6 ++++++ .../compressed_raw3D/Main_0.vtm | 11 +++++++++++ .../raw2D/Main.vtm.series | 6 ++++++ .../raw2D/Main_0.vtm | 17 +++++++++++++++++ .../raw3D/Main.vtm.series | 6 ++++++ .../raw3D/Main_0.vtm | 11 +++++++++++ 16 files changed, 160 insertions(+) create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main_0.vtm create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.vtm.series create mode 100755 kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main_0.vtm diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main_0.vtm new file mode 100755 index 000000000000..056a2a04577a --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main_0.vtm @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main_0.vtm new file mode 100755 index 000000000000..ceaefbaf5e98 --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main_0.vtm @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main_0.vtm new file mode 100755 index 000000000000..056a2a04577a --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main_0.vtm @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main_0.vtm new file mode 100755 index 000000000000..ceaefbaf5e98 --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main_0.vtm @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main_0.vtm new file mode 100755 index 000000000000..056a2a04577a --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main_0.vtm @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main_0.vtm new file mode 100755 index 000000000000..ceaefbaf5e98 --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main_0.vtm @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main_0.vtm new file mode 100755 index 000000000000..056a2a04577a --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main_0.vtm @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.vtm.series b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.vtm.series new file mode 100755 index 000000000000..5ff185d12b7e --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.vtm.series @@ -0,0 +1,6 @@ +{ + "file-series-version" : "1.0", + "files" : [ + { "name" : "Main_0.vtm", "time" : 1.000000000e+00 } + ] +} \ No newline at end of file diff --git a/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main_0.vtm b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main_0.vtm new file mode 100755 index 000000000000..ceaefbaf5e98 --- /dev/null +++ b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main_0.vtm @@ -0,0 +1,11 @@ + + + + + + + + + + + From e0e2b0f89d6dcbeb21e8232282287b55d8ae4748 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 2 May 2026 11:15:12 +0200 Subject: [PATCH 13/50] fix seek -8 with reverse search --- kratos/input_output/vtu_output.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 508467c79428..7a671e990ecc 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -1466,7 +1466,7 @@ void VtuOutput::PrintOutput( } } - std::ofstream output_file; + std::fstream output_file; output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc); output_file << "" << std::endl; vtm_file_element.Write(output_file); @@ -1487,13 +1487,33 @@ void VtuOutput::PrintOutput( output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; output_file << " ]" << std::endl; output_file << "}"; + output_file.close(); } else { output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out); - output_file.seekp(-8, std::ios::end); + output_file.seekg(0, std::ios::end); + const auto file_size = output_file.tellg(); + + std::streamoff last_object_end_pos = -1; + char pattern_buffer[2]; + for (std::streamoff i = static_cast(file_size) - 2; i >= 0; --i) { + output_file.seekg(i, std::ios::beg); + output_file.read(pattern_buffer, 2); + if (output_file.gcount() == 2 && pattern_buffer[0] == ' ' && pattern_buffer[1] == '}') { + last_object_end_pos = i + 2; + break; + } + } + + KRATOS_ERROR_IF(last_object_end_pos < 0) + << "Unable to find the last file entry in '" << rOutputFileNamePrefix << ".vtm.series'.\n"; + + output_file.clear(); + output_file.seekp(last_object_end_pos, std::ios::beg); output_file << "," << std::endl; output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; output_file << " ]" << std::endl; output_file << "}"; + output_file.close(); } } From a903f5c96ca452672ea612f33c9c7c3eb1c820ca Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 2 May 2026 11:15:26 +0200 Subject: [PATCH 14/50] fix unit tests --- kratos/tests/test_vtu_output.py | 60 +++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index 13a0c7015ab7..52ee99b51fff 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -1,5 +1,6 @@ import math, typing from pathlib import Path +import json import xml.etree.ElementTree as ET import KratosMultiphysics as Kratos @@ -125,7 +126,8 @@ def check_file(output_file_name: str, reference_file_name: str): for file_path in Path(reference_prefix).iterdir(): self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") check_file(f"{output_prefix}/{file_path.name}", str(file_path)) - check_file(f"{output_prefix}.pvd", f"{reference_prefix}.pvd") + check_file(f"{output_prefix}.vtm.series", f"{reference_prefix}.vtm.series") + check_file(f"{output_prefix}_0.vtm", f"{reference_prefix}_0.vtm") class TestVtuOutput2D(TestVtuOutputBase, kratos_unittest.TestCase): @classmethod @@ -350,7 +352,9 @@ def test_PointVariableAddition(self): { "PRESSURE": (1, "Float64") })) - TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/variable_test.pvd", list_of_vtu_file_names, [1 + 1e-9]) + + TestVtuOutput.CheckVtmFile(self, f"temp/vtu_output/variable_test_0.vtm", list_of_vtu_file_names) + TestVtuOutput.CheckSeriesFile(self, "temp/vtu_output/variable_test.vtm.series", ["variable_test_0.vtm"], [1 + 1e-9]) def test_CellVariableAddition(self): vtu_output = Kratos.VtuOutput(self.model_part, output_format=Kratos.VtuOutput.ASCII, output_sub_model_parts=True) @@ -373,8 +377,8 @@ def test_CellVariableAddition(self): model_part = vtu_output.GetModelPart() unstructured_grid_list = self.GetUnstructuredGridList(model_part, model_part.GetCommunicator().GetDataCommunicator(), True) - list_of_vtu_file_names: 'list[str]' = [] for step in range(2): + list_of_vtu_file_names: 'list[str]' = [] for model_part, use_nodes, container in unstructured_grid_list: vtu_file_name = TestVtuOutput.GetUnstructuredGridName((model_part, use_nodes, container), "temp/vtu_output/time_step_test", step, model_part.GetCommunicator().GetDataCommunicator()) list_of_vtu_file_names.append(vtu_file_name) @@ -402,8 +406,9 @@ def test_CellVariableAddition(self): { "DISPLACEMENT": (3, "Float64") })) + TestVtuOutput.CheckVtmFile(self, f"temp/vtu_output/time_step_test_{step}.vtm", list_of_vtu_file_names) - TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/time_step_test.pvd", list_of_vtu_file_names, [1, 1 + 1e-9]) + TestVtuOutput.CheckSeriesFile(self, "temp/vtu_output/time_step_test.vtm.series", ["time_step_test_0.vtm", "time_step_test_1.vtm"], [1, 1 + 1e-9]) @staticmethod def GetUnstructuredGridList(model_part: Kratos.ModelPart, data_communicator: Kratos.DataCommunicator, recursively: bool) -> 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]': @@ -516,25 +521,46 @@ def CheckVtuFile( kratos_utils.DeleteFileIfExisting(vtu_file_name) @staticmethod - def CheckPvdFile(test_class: kratos_unittest.TestCase, pvd_file_name: str, vtu_file_name_list: 'list[str]', time_step_list: 'list[float]'): - test_class.assertTrue(Path(pvd_file_name).is_file(), f"The file {pvd_file_name} not found.") - tree = ET.parse(pvd_file_name) + def CheckVtmFile(test_class: kratos_unittest.TestCase, vtm_file_name: str, vtu_file_name_list: 'list[str]'): + test_class.assertTrue(Path(vtm_file_name).is_file(), f"The file {vtm_file_name} not found.") + tree = ET.parse(vtm_file_name) root = tree.getroot() test_class.assertEqual(root.tag, "VTKFile") - test_class.assertEqual(root.get("type"), "Collection") + test_class.assertEqual(root.get("type"), "vtkMultiBlockDataSet") test_class.assertEqual(root.get("version"), "1.0") - collection = root.find("Collection") - datasets = collection.findall("DataSet") - test_class.assertEqual(len(datasets), len(vtu_file_name_list), f"file name = {pvd_file_name}, list_of_time_steps = {time_step_list}, list_of_vtu_files = \n" + "\n\t".join(vtu_file_name_list)) - for i, dataset in enumerate(datasets): - relative_path = Path(vtu_file_name_list[i]).absolute().relative_to(Path(pvd_file_name).absolute().parent) + collection = root.find("vtkMultiBlockDataSet") + blocks = collection.findall("Block") + test_class.assertEqual(len(blocks), len(vtu_file_name_list), f"file name = {vtm_file_name}, list_of_vtu_files = \n\t" + "\n\t".join(vtu_file_name_list)) + for i, block in enumerate(blocks): + vtu_file_name = vtu_file_name_list[i] + name = vtu_file_name[vtu_file_name.rfind("/")+1:vtu_file_name.rfind("_")] + test_class.assertEqual(block.get("index"), f"{i}") + test_class.assertEqual(block.get("name"), name) + + datasets = block.findall("DataSet") + test_class.assertEqual(len(datasets), 1) + dataset = datasets[0] + + relative_path = Path(vtu_file_name_list[i]).absolute().relative_to(Path(vtm_file_name).absolute().parent) test_class.assertEqual(dataset.get("file"), str(relative_path)) - test_class.assertEqual(dataset.get("name"), relative_path.name[:relative_path.name.rfind("_")]) - test_class.assertEqual(dataset.get("part"), str(i % (len(vtu_file_name_list) // len(time_step_list)))) - test_class.assertEqual(dataset.get("timestep"), f"{time_step_list[i // (len(vtu_file_name_list) // len(time_step_list))]:0.9e}", f"file name = {relative_path}") - kratos_utils.DeleteFileIfExisting(pvd_file_name) + test_class.assertEqual(dataset.get("name"), relative_path.name[:relative_path.name.rfind("_") + 1] + "0") + kratos_utils.DeleteFileIfExisting(vtm_file_name) + + @staticmethod + def CheckSeriesFile(test_class: kratos_unittest.TestCase, series_file_name: str, vtm_file_name_list: 'list[str]', time_step_list: 'list[float]'): + test_class.assertTrue(Path(series_file_name).is_file(), f"The file {series_file_name} not found.") + with open(series_file_name, "r") as file_input: + data = json.loads(file_input.read()) + + test_class.assertEqual(data["file-series-version"], "1.0") + files = data["files"] + test_class.assertEqual(len(files), len(vtm_file_name_list)) + for i, vtu_file_name in enumerate(vtm_file_name_list): + test_class.assertEqual(files[i]["name"], vtu_file_name) + test_class.assertEqual(files[i]["time"], time_step_list[i]) + kratos_utils.DeleteFileIfExisting(series_file_name) @staticmethod def CheckGaussVtuFile(test_class: kratos_unittest.TestCase, model_part: Kratos.ModelPart, container, prefix: str, step_id: int, output_type: str, data_communicator: Kratos.DataCommunicator, point_fields): From 8a678dab5c069d6f34e56265b043a09f8c33a060 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 2 May 2026 11:15:36 +0200 Subject: [PATCH 15/50] add unit tests to the core --- kratos/tests/test_KratosCore.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kratos/tests/test_KratosCore.py b/kratos/tests/test_KratosCore.py index 892819a2ede9..13f34e51554d 100644 --- a/kratos/tests/test_KratosCore.py +++ b/kratos/tests/test_KratosCore.py @@ -108,6 +108,7 @@ import test_connectivity_ids_tensor_adaptor import test_constraint_restart import test_ensight_output_process +import test_vtu_output # Import modules required for sequential orchestrator test from test_sequential_orchestrator import EmptyAnalysisStage @@ -239,6 +240,9 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_connectivity_ids_tensor_adaptor.TestConnectivityIdsTensorAdaptor])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_constraint_restart.TestConstraintRestart])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_ensight_output_process.TestEnsightOutputProcess])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput2D])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput3D])) if sympy_available: smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_sympy_fe_utilities.TestSympyFEUtilities])) From 8170ed737d8bb94727a3922025a6bf893eb6fdf9 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Wed, 27 May 2026 05:45:19 +0200 Subject: [PATCH 16/50] add ignore files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 08687cef6686..b43fe0c279ae 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ kratos/scripts/wheels/README.md # Times files *.time +*.series # Prerequisites *.d @@ -64,6 +65,7 @@ kratos/scripts/wheels/README.md # VTK post files *.vtk *.vtu +*.vtm *.pvd *.pvtu From f8cd65ff6b4c4fd01954c22b447d35f7c35ae0ac Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 28 May 2026 06:01:37 +0200 Subject: [PATCH 17/50] fix for windows --- kratos/tests/test_vtu_output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index 52ee99b51fff..78a08df247f4 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -544,7 +544,7 @@ def CheckVtmFile(test_class: kratos_unittest.TestCase, vtm_file_name: str, vtu_ dataset = datasets[0] relative_path = Path(vtu_file_name_list[i]).absolute().relative_to(Path(vtm_file_name).absolute().parent) - test_class.assertEqual(dataset.get("file"), str(relative_path)) + test_class.assertEqual(dataset.get("file"), relative_path.as_posix()) test_class.assertEqual(dataset.get("name"), relative_path.name[:relative_path.name.rfind("_") + 1] + "0") kratos_utils.DeleteFileIfExisting(vtm_file_name) From fd1b422b2fa3d919b428857502705b76a950ad66 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 29 May 2026 08:36:19 +0200 Subject: [PATCH 18/50] shifting to binary writing to avoid new line probs with windows --- kratos/input_output/vtu_output.cpp | 30 +++++++++---------- kratos/tests/test_vtu_output.py | 5 ++-- .../xml_appended_data_element_wrapper.cpp | 2 +- .../xml_ascii_nd_data_element.cpp | 2 +- .../xml_base64_binary_nd_data_element.cpp | 2 +- .../utilities/xml_utilities/xml_element.cpp | 6 ++-- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 7a671e990ecc..559f90e2df4e 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -1150,7 +1150,7 @@ std::pair VtuOutput::WriteUnstructuredGridData( // write the vtu file. std::ofstream output_file; output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "" << std::endl; + output_file << "" << "\n"; vtk_file_element.Write(output_file); output_file.close(); @@ -1321,8 +1321,8 @@ std::pair VtuOutput::WriteIntegrationPointData( << ".vtu"; std::ofstream output_file; - output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); - output_file << "" << std::endl; + output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); + output_file << "" << "\n"; vtk_file_element.Write(output_file); output_file.close(); @@ -1467,8 +1467,8 @@ void VtuOutput::PrintOutput( } std::fstream output_file; - output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc); - output_file << "" << std::endl; + output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc | std::ios::binary); + output_file << "" << "\n"; vtm_file_element.Write(output_file); output_file.close(); @@ -1480,16 +1480,16 @@ void VtuOutput::PrintOutput( // now write the series file having the time if (!mIsSeriesFileHeaderWritten) { - output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::out | std::ios::trunc); - output_file << "{" << std::endl; - output_file << " \"file-series-version\" : \"1.0\"," << std::endl; - output_file << " \"files\" : [" << std::endl; - output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; - output_file << " ]" << std::endl; + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::out | std::ios::trunc | std::ios::binary); + output_file << "{" << "\n"; + output_file << " \"file-series-version\" : \"1.0\"," << "\n"; + output_file << " \"files\" : [" << "\n"; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << "\n"; + output_file << " ]" << "\n"; output_file << "}"; output_file.close(); } else { - output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out); + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out | std::ios::binary); output_file.seekg(0, std::ios::end); const auto file_size = output_file.tellg(); @@ -1509,9 +1509,9 @@ void VtuOutput::PrintOutput( output_file.clear(); output_file.seekp(last_object_end_pos, std::ios::beg); - output_file << "," << std::endl; - output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; - output_file << " ]" << std::endl; + output_file << "," << "\n"; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << "\n"; + output_file << " ]" << "\n"; output_file << "}"; output_file.close(); } diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index 78a08df247f4..f00984df6adb 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -124,8 +124,9 @@ def check_file(output_file_name: str, reference_file_name: str): CompareTwoFilesCheckProcess(params).Execute() for file_path in Path(reference_prefix).iterdir(): - self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") - check_file(f"{output_prefix}/{file_path.name}", str(file_path)) + if file_path.is_file(): + self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") + check_file(f"{output_prefix}/{file_path.name}", str(file_path)) check_file(f"{output_prefix}.vtm.series", f"{reference_prefix}.vtm.series") check_file(f"{output_prefix}_0.vtm", f"{reference_prefix}_0.vtm") diff --git a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp index b1256ce330d9..cf731a4362b3 100644 --- a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp @@ -128,7 +128,7 @@ void XmlAppendedDataElementWrapper::Write( rOStream.write(mData.data(), mData.size()); - rOStream << std::endl; + rOStream << "\n"; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp index 8ac3eb80773a..3d938d7a66f2 100644 --- a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp @@ -65,7 +65,7 @@ void XmlAsciiNDDataElement::Write( } } - rOStream << std::endl; + rOStream << "\n"; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp index f3ed2b71622f..70e4f25a9da5 100644 --- a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp @@ -63,7 +63,7 @@ void XmlBase64BinaryNDDataElement::Write( base64_encoder.WriteData(span.begin(), span.size()); } - rOStream << std::endl; + rOStream << "\n"; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_element.cpp b/kratos/utilities/xml_utilities/xml_element.cpp index dd3a67847dd5..8437aceb78cd 100644 --- a/kratos/utilities/xml_utilities/xml_element.cpp +++ b/kratos/utilities/xml_utilities/xml_element.cpp @@ -58,7 +58,7 @@ void XmlElement::WriteElementTagStart( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << ">" << std::endl; + rOStream << ">" << "\n"; } void XmlElement::WriteElementTagEnd( @@ -66,7 +66,7 @@ void XmlElement::WriteElementTagEnd( const IndexType Level) const { const std::string tabbing(Level * 3, ' '); - rOStream << tabbing << "" << std::endl; + rOStream << tabbing << "" << "\n"; } void XmlElement::WriteEmptyElementTag( std::ostream& rOStream, @@ -80,7 +80,7 @@ void XmlElement::WriteEmptyElementTag( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << "/>" << std::endl; + rOStream << "/>" << "\n"; } } // namespace Kratos \ No newline at end of file From 20a7d2712ce08efb1ef787d5c3ccdabf7e08789a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Fri, 29 May 2026 08:47:04 +0200 Subject: [PATCH 19/50] Revert "shifting to binary writing to avoid new line probs with windows" This reverts commit b243fd22e71bc2665b185f46eec891eeb005b80a. --- kratos/input_output/vtu_output.cpp | 30 +++++++++---------- kratos/tests/test_vtu_output.py | 5 ++-- .../xml_appended_data_element_wrapper.cpp | 2 +- .../xml_ascii_nd_data_element.cpp | 2 +- .../xml_base64_binary_nd_data_element.cpp | 2 +- .../utilities/xml_utilities/xml_element.cpp | 6 ++-- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 559f90e2df4e..7a671e990ecc 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -1150,7 +1150,7 @@ std::pair VtuOutput::WriteUnstructuredGridData( // write the vtu file. std::ofstream output_file; output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "" << "\n"; + output_file << "" << std::endl; vtk_file_element.Write(output_file); output_file.close(); @@ -1321,8 +1321,8 @@ std::pair VtuOutput::WriteIntegrationPointData( << ".vtu"; std::ofstream output_file; - output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "" << "\n"; + output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); + output_file << "" << std::endl; vtk_file_element.Write(output_file); output_file.close(); @@ -1467,8 +1467,8 @@ void VtuOutput::PrintOutput( } std::fstream output_file; - output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "" << "\n"; + output_file.open(rOutputFileNamePrefix + "_" + std::to_string(Step) + ".vtm", std::ios::out | std::ios::trunc); + output_file << "" << std::endl; vtm_file_element.Write(output_file); output_file.close(); @@ -1480,16 +1480,16 @@ void VtuOutput::PrintOutput( // now write the series file having the time if (!mIsSeriesFileHeaderWritten) { - output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "{" << "\n"; - output_file << " \"file-series-version\" : \"1.0\"," << "\n"; - output_file << " \"files\" : [" << "\n"; - output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << "\n"; - output_file << " ]" << "\n"; + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::out | std::ios::trunc); + output_file << "{" << std::endl; + output_file << " \"file-series-version\" : \"1.0\"," << std::endl; + output_file << " \"files\" : [" << std::endl; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; + output_file << " ]" << std::endl; output_file << "}"; output_file.close(); } else { - output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out | std::ios::binary); + output_file.open(rOutputFileNamePrefix + ".vtm.series", std::ios::in | std::ios::out); output_file.seekg(0, std::ios::end); const auto file_size = output_file.tellg(); @@ -1509,9 +1509,9 @@ void VtuOutput::PrintOutput( output_file.clear(); output_file.seekp(last_object_end_pos, std::ios::beg); - output_file << "," << "\n"; - output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << "\n"; - output_file << " ]" << "\n"; + output_file << "," << std::endl; + output_file << " { \"name\" : \"" + relative_vtm_file_name + "\", \"time\" : " + str_time.str() << " }" << std::endl; + output_file << " ]" << std::endl; output_file << "}"; output_file.close(); } diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index f00984df6adb..78a08df247f4 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -124,9 +124,8 @@ def check_file(output_file_name: str, reference_file_name: str): CompareTwoFilesCheckProcess(params).Execute() for file_path in Path(reference_prefix).iterdir(): - if file_path.is_file(): - self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") - check_file(f"{output_prefix}/{file_path.name}", str(file_path)) + self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") + check_file(f"{output_prefix}/{file_path.name}", str(file_path)) check_file(f"{output_prefix}.vtm.series", f"{reference_prefix}.vtm.series") check_file(f"{output_prefix}_0.vtm", f"{reference_prefix}_0.vtm") diff --git a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp index cf731a4362b3..b1256ce330d9 100644 --- a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp @@ -128,7 +128,7 @@ void XmlAppendedDataElementWrapper::Write( rOStream.write(mData.data(), mData.size()); - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp index 3d938d7a66f2..8ac3eb80773a 100644 --- a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp @@ -65,7 +65,7 @@ void XmlAsciiNDDataElement::Write( } } - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp index 70e4f25a9da5..f3ed2b71622f 100644 --- a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp @@ -63,7 +63,7 @@ void XmlBase64BinaryNDDataElement::Write( base64_encoder.WriteData(span.begin(), span.size()); } - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_element.cpp b/kratos/utilities/xml_utilities/xml_element.cpp index 8437aceb78cd..dd3a67847dd5 100644 --- a/kratos/utilities/xml_utilities/xml_element.cpp +++ b/kratos/utilities/xml_utilities/xml_element.cpp @@ -58,7 +58,7 @@ void XmlElement::WriteElementTagStart( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << ">" << "\n"; + rOStream << ">" << std::endl; } void XmlElement::WriteElementTagEnd( @@ -66,7 +66,7 @@ void XmlElement::WriteElementTagEnd( const IndexType Level) const { const std::string tabbing(Level * 3, ' '); - rOStream << tabbing << "" << "\n"; + rOStream << tabbing << "" << std::endl; } void XmlElement::WriteEmptyElementTag( std::ostream& rOStream, @@ -80,7 +80,7 @@ void XmlElement::WriteEmptyElementTag( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << "/>" << "\n"; + rOStream << "/>" << std::endl; } } // namespace Kratos \ No newline at end of file From e481b09f10fa9d0a922c0f73ec255aabbdbd1d33 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 29 May 2026 09:01:35 +0200 Subject: [PATCH 20/50] minor --- kratos/tests/test_vtu_output.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index 78a08df247f4..df17bae863f9 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -1,6 +1,7 @@ import math, typing from pathlib import Path import json +import filecmp import xml.etree.ElementTree as ET import KratosMultiphysics as Kratos @@ -113,19 +114,34 @@ def test_WriteMeshCompressedRawWithError(self): def Check(self, output_prefix, reference_prefix): def check_file(output_file_name: str, reference_file_name: str): + if reference_file_name.endswith(".vtm.series"): + with open(reference_file_name, "r") as reference_file: + reference_data = json.load(reference_file) + with open(output_file_name, "r") as output_file: + output_data = json.load(output_file) + self.assertEqual(output_data, reference_data) + return + + if reference_file_name.endswith(".vtu"): + with open(reference_file_name, "rb") as reference_file: + if b'' in reference_file.read(): + self.assertTrue(filecmp.cmp(reference_file_name, output_file_name, shallow=False)) + return + ## Settings string in json format params = Kratos.Parameters("""{ "reference_file_name" : "", "output_file_name" : "", - "comparison_type" : "deterministic" + "comparison_type" : "xml" }""") params["reference_file_name"].SetString(reference_file_name) params["output_file_name"].SetString(output_file_name) CompareTwoFilesCheckProcess(params).Execute() for file_path in Path(reference_prefix).iterdir(): - self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") - check_file(f"{output_prefix}/{file_path.name}", str(file_path)) + if file_path.is_file(): + self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") + check_file(f"{output_prefix}/{file_path.name}", str(file_path)) check_file(f"{output_prefix}.vtm.series", f"{reference_prefix}.vtm.series") check_file(f"{output_prefix}_0.vtm", f"{reference_prefix}_0.vtm") From eb46ec919982addabeae17483f5a181d3043f33e Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Sat, 6 Jun 2026 09:39:03 +0200 Subject: [PATCH 21/50] correct bug in projection utilities --- .../custom_utilities/projection_utilities.cpp | 112 +++++++++++++----- 1 file changed, 81 insertions(+), 31 deletions(-) diff --git a/applications/MappingApplication/custom_utilities/projection_utilities.cpp b/applications/MappingApplication/custom_utilities/projection_utilities.cpp index 924cf7b93850..2b7ad4e1a10d 100644 --- a/applications/MappingApplication/custom_utilities/projection_utilities.cpp +++ b/applications/MappingApplication/custom_utilities/projection_utilities.cpp @@ -66,41 +66,91 @@ void FillEquationIdVectorIBRA(const GeometryType::Pointer pGeometry, const IndexType polynomial_degree_u = pGeometry->PolynomialDegree(0); const IndexType polynomial_degree_v = pGeometry->PolynomialDegree(1); - // Get the knot vectors of the nurbs surface and extend them to be consistent - std::vector knot_vector_u, knot_vector_v; - pGeometry->SpansLocalSpace(knot_vector_u, 0); - pGeometry->SpansLocalSpace(knot_vector_v, 1); - knot_vector_u.insert(knot_vector_u.begin(), polynomial_degree_u - 1, knot_vector_u.front()); - knot_vector_u.insert(knot_vector_u.end(), polynomial_degree_u - 1, knot_vector_u.back()); - knot_vector_v.insert(knot_vector_v.begin(), polynomial_degree_v - 1, knot_vector_v.front()); - knot_vector_v.insert(knot_vector_v.end(), polynomial_degree_v - 1, knot_vector_v.back()); - - // shape function container. - NurbsSurfaceShapeFunction shape_function_container( - polynomial_degree_u, polynomial_degree_v, 0); - - // Transform the knot vectors to the required format for the shape function container - Vector vector_knot_vector_u(knot_vector_u.size()), vector_knot_vector_v(knot_vector_v.size()); - for (IndexType i = 0; i < knot_vector_u.size(); ++i) { - vector_knot_vector_u[i] = knot_vector_u[i]; - } + // Downcast the geometry to a nurbs surface + auto p_nurbs_surface = dynamic_cast(pGeometry.get()); - for (IndexType i = 0; i < knot_vector_v.size(); ++i) { - vector_knot_vector_v[i] = knot_vector_v[i]; - } + KRATOS_ERROR_IF_NOT(p_nurbs_surface) + << "Geometry is not a NurbsSurfaceGeometryType!" << std::endl; + + // Number of CPs in the u and v directions + const SizeType num_cp_u = pGeometry->PointsNumberInDirection(0); + const SizeType num_cp_v = pGeometry->PointsNumberInDirection(1); + + // Expected size of the knot vectors in the u and v directions + const SizeType expected_size_u = num_cp_u + polynomial_degree_u + 1; + const SizeType expected_size_v = num_cp_v + polynomial_degree_v + 1; + + const Vector raw_knots_u = p_nurbs_surface->KnotsU(); + const Vector raw_knots_v = p_nurbs_surface->KnotsV(); + + auto ExtendEndKnotsIfNeeded = [](const Vector& rRawKnots, + const SizeType ExpectedSize) + { + if (rRawKnots.size() == ExpectedSize) { + return rRawKnots; + } + + if (rRawKnots.size() + 2 == ExpectedSize) { + Vector extended_knots(ExpectedSize); + + extended_knots[0] = rRawKnots[0]; + + for (IndexType i = 0; i < rRawKnots.size(); ++i) { + extended_knots[i + 1] = rRawKnots[i]; + } + + extended_knots[ExpectedSize - 1] = + rRawKnots[rRawKnots.size() - 1]; + + return extended_knots; + } + + return Vector(); + }; + + // Extend the knot vectors if they dont have the correct size + const Vector vector_knot_vector_u = ExtendEndKnotsIfNeeded(raw_knots_u, expected_size_u); + const Vector vector_knot_vector_v = ExtendEndKnotsIfNeeded(raw_knots_v, expected_size_v); + + NurbsSurfaceShapeFunction shape_function_container(polynomial_degree_u, polynomial_degree_v, 0); + + const IndexType lower_span_u = NurbsUtilities::GetLowerSpan(polynomial_degree_u, vector_knot_vector_u, rCoordinates[0]); + const IndexType lower_span_v = NurbsUtilities::GetLowerSpan(polynomial_degree_v, vector_knot_vector_v, rCoordinates[1]); + + KRATOS_ERROR_IF(lower_span_u == 0 || lower_span_v == 0) + << "Invalid span for shifted convention." << std::endl; + + const IndexType span_u_for_container = lower_span_u - 1; + const IndexType span_v_for_container = lower_span_v - 1; + + shape_function_container.ComputeBSplineShapeFunctionValuesAtSpan(vector_knot_vector_u, vector_knot_vector_v, span_u_for_container, + span_v_for_container, rCoordinates[0], rCoordinates[1]); + + const IndexType num_nonzero_cps = shape_function_container.NumberOfNonzeroControlPoints(); + + const std::vector cp_indices = shape_function_container.ControlPointIndices(num_cp_u, num_cp_v); + + KRATOS_ERROR_IF(cp_indices.size() != num_nonzero_cps) + << "Mismatch between number of active control points (" + << num_nonzero_cps + << ") and returned indices (" + << cp_indices.size() + << ")." << std::endl; + + rEquationIds.clear(); + rEquationIds.resize(num_nonzero_cps); + + for (IndexType j = 0; j < num_nonzero_cps; ++j) { + const int cp_index = cp_indices[j]; - shape_function_container.ComputeBSplineShapeFunctionValues(vector_knot_vector_u, vector_knot_vector_v, rCoordinates[0], rCoordinates[1]); + auto p_point = pGeometry->pGetPoint(cp_index); - IndexType num_nonzero_cps = shape_function_container.NumberOfNonzeroControlPoints(); + KRATOS_DEBUG_ERROR_IF_NOT(p_point->Has(INTERFACE_EQUATION_ID)) + << *p_point + << " does not have an INTERFACE_EQUATION_ID" + << std::endl; - /// Get List of Control Points - PointsArrayType nonzero_control_points(num_nonzero_cps); - std::vector cp_indices = shape_function_container.ControlPointIndices( - pGeometry->PointsNumberInDirection(0), pGeometry->PointsNumberInDirection(1)); - - for (IndexType j = 0; j < num_nonzero_cps; j++) { - KRATOS_DEBUG_ERROR_IF_NOT(pGeometry->pGetPoint(cp_indices[j])->Has(INTERFACE_EQUATION_ID)) << pGeometry->pGetPoint(cp_indices[j]) << " does not have an \"INTERFACE_EQUATION_ID\"" << std::endl; - rEquationIds.push_back(pGeometry->pGetPoint(cp_indices[j])->GetValue(INTERFACE_EQUATION_ID)); + rEquationIds[j] = p_point->GetValue(INTERFACE_EQUATION_ID); } KRATOS_CATCH("") From f2d537dfda6565bb95601684bdeffe7bd8ac937f Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Sun, 7 Jun 2026 21:25:15 +0200 Subject: [PATCH 22/50] solve bug --- .../custom_utilities/projection_utilities.cpp | 72 +++---------------- 1 file changed, 11 insertions(+), 61 deletions(-) diff --git a/applications/MappingApplication/custom_utilities/projection_utilities.cpp b/applications/MappingApplication/custom_utilities/projection_utilities.cpp index 2b7ad4e1a10d..7ee0d8831ec4 100644 --- a/applications/MappingApplication/custom_utilities/projection_utilities.cpp +++ b/applications/MappingApplication/custom_utilities/projection_utilities.cpp @@ -69,86 +69,36 @@ void FillEquationIdVectorIBRA(const GeometryType::Pointer pGeometry, // Downcast the geometry to a nurbs surface auto p_nurbs_surface = dynamic_cast(pGeometry.get()); - KRATOS_ERROR_IF_NOT(p_nurbs_surface) - << "Geometry is not a NurbsSurfaceGeometryType!" << std::endl; + KRATOS_ERROR_IF_NOT(p_nurbs_surface) << "Geometry is not a NurbsSurfaceGeometryType!" << std::endl; // Number of CPs in the u and v directions const SizeType num_cp_u = pGeometry->PointsNumberInDirection(0); const SizeType num_cp_v = pGeometry->PointsNumberInDirection(1); - // Expected size of the knot vectors in the u and v directions - const SizeType expected_size_u = num_cp_u + polynomial_degree_u + 1; - const SizeType expected_size_v = num_cp_v + polynomial_degree_v + 1; - - const Vector raw_knots_u = p_nurbs_surface->KnotsU(); - const Vector raw_knots_v = p_nurbs_surface->KnotsV(); - - auto ExtendEndKnotsIfNeeded = [](const Vector& rRawKnots, - const SizeType ExpectedSize) - { - if (rRawKnots.size() == ExpectedSize) { - return rRawKnots; - } - - if (rRawKnots.size() + 2 == ExpectedSize) { - Vector extended_knots(ExpectedSize); - - extended_knots[0] = rRawKnots[0]; - - for (IndexType i = 0; i < rRawKnots.size(); ++i) { - extended_knots[i + 1] = rRawKnots[i]; - } - - extended_knots[ExpectedSize - 1] = - rRawKnots[rRawKnots.size() - 1]; - - return extended_knots; - } - - return Vector(); - }; - - // Extend the knot vectors if they dont have the correct size - const Vector vector_knot_vector_u = ExtendEndKnotsIfNeeded(raw_knots_u, expected_size_u); - const Vector vector_knot_vector_v = ExtendEndKnotsIfNeeded(raw_knots_v, expected_size_v); + // Knot vectors in the u and v directions with multiplicity of p at the beginning and end + const Vector knots_u = p_nurbs_surface->KnotsU(); + const Vector knots_v = p_nurbs_surface->KnotsV(); NurbsSurfaceShapeFunction shape_function_container(polynomial_degree_u, polynomial_degree_v, 0); - const IndexType lower_span_u = NurbsUtilities::GetLowerSpan(polynomial_degree_u, vector_knot_vector_u, rCoordinates[0]); - const IndexType lower_span_v = NurbsUtilities::GetLowerSpan(polynomial_degree_v, vector_knot_vector_v, rCoordinates[1]); - - KRATOS_ERROR_IF(lower_span_u == 0 || lower_span_v == 0) - << "Invalid span for shifted convention." << std::endl; - - const IndexType span_u_for_container = lower_span_u - 1; - const IndexType span_v_for_container = lower_span_v - 1; - - shape_function_container.ComputeBSplineShapeFunctionValuesAtSpan(vector_knot_vector_u, vector_knot_vector_v, span_u_for_container, - span_v_for_container, rCoordinates[0], rCoordinates[1]); + shape_function_container.ComputeBSplineShapeFunctionValues(knots_u, knots_v, rCoordinates[0], rCoordinates[1]); + // Get the indices of the non-zero shape functions (i.e. the control points influencing the point defined by rCoordinates) const IndexType num_nonzero_cps = shape_function_container.NumberOfNonzeroControlPoints(); - const std::vector cp_indices = shape_function_container.ControlPointIndices(num_cp_u, num_cp_v); - KRATOS_ERROR_IF(cp_indices.size() != num_nonzero_cps) - << "Mismatch between number of active control points (" - << num_nonzero_cps - << ") and returned indices (" - << cp_indices.size() - << ")." << std::endl; - rEquationIds.clear(); rEquationIds.resize(num_nonzero_cps); for (IndexType j = 0; j < num_nonzero_cps; ++j) { const int cp_index = cp_indices[j]; - auto p_point = pGeometry->pGetPoint(cp_index); + KRATOS_ERROR_IF(cp_index < 0 || cp_index >= static_cast(pGeometry->PointsNumber())) + << "Invalid control point index " << cp_index + << " for geometry with " << pGeometry->PointsNumber() + << " control points." << std::endl; - KRATOS_DEBUG_ERROR_IF_NOT(p_point->Has(INTERFACE_EQUATION_ID)) - << *p_point - << " does not have an INTERFACE_EQUATION_ID" - << std::endl; + auto p_point = pGeometry->pGetPoint(cp_index); rEquationIds[j] = p_point->GetValue(INTERFACE_EQUATION_ID); } From 4344325c50829b3c8e42e6622ccb5de35f3e00f4 Mon Sep 17 00:00:00 2001 From: Richard Faasse <56549273+rfaasse@users.noreply.github.com> Date: Mon, 8 Jun 2026 19:46:14 +0200 Subject: [PATCH 23/50] [GeoMechanicsApplication] Fixed issue with reverse search and point conditions (#14478) --- .../neighbouring_element_finder.cpp | 2 +- .../test_neighbouring_element_finder.cpp | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/applications/GeoMechanicsApplication/custom_utilities/neighbouring_element_finder.cpp b/applications/GeoMechanicsApplication/custom_utilities/neighbouring_element_finder.cpp index 0fdcb51bc6e4..77e50f9892e0 100644 --- a/applications/GeoMechanicsApplication/custom_utilities/neighbouring_element_finder.cpp +++ b/applications/GeoMechanicsApplication/custom_utilities/neighbouring_element_finder.cpp @@ -49,7 +49,7 @@ void NeighbouringElementFinder::AddNeighbouringElementsToEntitiesBasedOnOverlapp { for (const auto& r_boundary_geometry : rBoundaryGeometries) { AddNeighbouringElementsBasedOnBoundaryGeometry(rElement, r_boundary_geometry); - if (mEnableReverseSearch) { + if (r_boundary_geometry.size() > 1 && mEnableReverseSearch) { constexpr auto reverse_search = true; AddNeighbouringElementsBasedOnBoundaryGeometry(rElement, r_boundary_geometry, reverse_search); } diff --git a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_utilities/test_neighbouring_element_finder.cpp b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_utilities/test_neighbouring_element_finder.cpp index 57df632950d6..b5d2256ae111 100644 --- a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_utilities/test_neighbouring_element_finder.cpp +++ b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_utilities/test_neighbouring_element_finder.cpp @@ -272,4 +272,30 @@ KRATOS_TEST_CASE_IN_SUITE(NeighbouringElementFinder_FindsNeighbourElementOfCondi EXPECT_EQ(r_model_part.GetCondition(1).GetValue(NEIGHBOUR_ELEMENTS).size(), 1); } +KRATOS_TEST_CASE_IN_SUITE(NeighbouringElementFinder_FindsNeighbourElementOfPointConditionWhenReverseSearchIsActive, + KratosGeoMechanicsFastSuiteWithoutKernel) +{ + // Arrange + Model model; + auto& r_model_part = model.CreateModelPart("main"); + auto nodes = Testing::ModelSetupUtilities::CreateNodes(r_model_part, {{1, {0.0, 0.0, 0.0}}}); + auto geometry = Kratos::make_shared>(nodes); + + r_model_part.AddElement(Kratos::make_intrusive(1, geometry)); + r_model_part.AddCondition(Kratos::make_intrusive(1, geometry)); + + NeighbouringElementFinder::BoundaryGeneratorByLocalDim boundary_generators; + boundary_generators[std::size_t{0}] = std::make_unique(); + constexpr auto enable_reverse_search = true; + NeighbouringElementFinder finder(enable_reverse_search); + + // Act + EXPECT_NO_THROW(finder.FindEntityNeighbours(r_model_part.Conditions(), r_model_part.Elements(), + boundary_generators)); + + // Assert + const auto& r_neighbours = r_model_part.GetCondition(1).GetValue(NEIGHBOUR_ELEMENTS); + ASSERT_EQ(r_neighbours.size(), 1); +} + } // namespace Kratos::Testing \ No newline at end of file From fdc8a18451d0d31b408d628c691ff99029e65aaf Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Wed, 3 Jun 2026 14:23:33 +0200 Subject: [PATCH 24/50] add penalty coupling and support for shell 6p --- .../coupling_penalty_6p_condition.cpp | 283 ++++++++++++++++++ .../coupling_penalty_6p_condition.h | 249 +++++++++++++++ .../support_penalty_6p_condition.cpp | 199 ++++++++++++ .../support_penalty_6p_condition.h | 253 ++++++++++++++++ .../IgaApplication/iga_application.cpp | 6 + applications/IgaApplication/iga_application.h | 4 + 6 files changed, 994 insertions(+) create mode 100644 applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp create mode 100644 applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h create mode 100644 applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp create mode 100644 applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp new file mode 100644 index 000000000000..948777de998d --- /dev/null +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp @@ -0,0 +1,283 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Ricky Aristio +// + +// System includes + +// External includes + +// Project includes +#include "custom_conditions/coupling_penalty_6p_condition.h" + +namespace Kratos +{ + void CouplingPenalty6pCondition::CalculateAll( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo, + const bool CalculateStiffnessMatrixFlag, + const bool CalculateResidualVectorFlag) + { + KRATOS_TRY + const double penalty = GetProperties()[PENALTY_FACTOR]; + const double penalty_rotation = GetProperties()[PENALTY_ROTATION_FACTOR]; + + const auto& r_geometry_master = GetGeometry().GetGeometryPart(0); + const auto& r_geometry_slave = GetGeometry().GetGeometryPart(1); + + // Size definitions + const SizeType number_of_nodes_master = r_geometry_master.size(); + const SizeType number_of_nodes_slave = r_geometry_slave.size(); + + const SizeType mat_size = 6 * (number_of_nodes_master + number_of_nodes_slave); + + // Memory allocation + if (CalculateStiffnessMatrixFlag) { + if (rLeftHandSideMatrix.size1() != mat_size) { + rLeftHandSideMatrix.resize(mat_size, mat_size, false); + } + noalias(rLeftHandSideMatrix) = ZeroMatrix(mat_size, mat_size); + } + if (CalculateResidualVectorFlag) { + if (rRightHandSideVector.size() != mat_size) { + rRightHandSideVector.resize(mat_size, false); + } + rRightHandSideVector = ZeroVector(mat_size); + } + + // Integration + const GeometryType::IntegrationPointsArrayType& integration_points = r_geometry_master.IntegrationPoints(); + + // Determine the integration: conservative -> initial; non-conservative -> current + Vector determinant_jacobian_vector(integration_points.size()); + const bool integrate_conservative = GetProperties().Has(INTEGRATE_CONSERVATIVE) + ? GetProperties()[INTEGRATE_CONSERVATIVE] + : false; + if (integrate_conservative) { + DeterminantOfJacobianInitial(r_geometry_master, determinant_jacobian_vector); + } + else { + r_geometry_master.DeterminantOfJacobian(determinant_jacobian_vector); + } + + for (IndexType point_number = 0; point_number < integration_points.size(); point_number++) + { + Matrix N_master = r_geometry_master.ShapeFunctionsValues(); + Matrix N_slave = r_geometry_slave.ShapeFunctionsValues(); + + //FOR DISPLACEMENTS + Matrix H = ZeroMatrix(6, mat_size); + for (IndexType i = 0; i < number_of_nodes_master; ++i) + { + IndexType index = 6 * i; + if (Is(IgaFlags::FIX_DISPLACEMENT_X)) + H(0, index) = N_master(point_number, i); + if (Is(IgaFlags::FIX_DISPLACEMENT_Y)) + H(1, index + 1) = N_master(point_number, i); + if (Is(IgaFlags::FIX_DISPLACEMENT_Z)) + H(2, index + 2) = N_master(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_X)) + H(3, index + 3) = N_master(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_Y)) + H(4, index + 4) = N_master(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_Z)) + H(5, index + 5) = N_master(point_number, i); + } + + for (IndexType i = 0; i < number_of_nodes_slave; ++i) + { + IndexType index = 6 * (i + number_of_nodes_master); + if (Is(IgaFlags::FIX_DISPLACEMENT_X)) + H(0, index) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_DISPLACEMENT_Y)) + H(1, index + 1) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_DISPLACEMENT_Z)) + H(2, index + 2) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_X)) + H(3, index + 3) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_Y)) + H(4, index + 4) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_Z)) + H(5, index + 5) = -N_slave(point_number, i); + } + + // Differential area + const double penalty_integration = penalty * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + const double penalty_rotation_integration = penalty_rotation * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + + // Assembly + if (CalculateStiffnessMatrixFlag) { + noalias(rLeftHandSideMatrix) += prod(trans(H), H) * penalty_integration; + } + if (CalculateResidualVectorFlag) { + + Vector u(mat_size); + for (IndexType i = 0; i < number_of_nodes_master; ++i) + { + const array_1d disp = r_geometry_master[i].FastGetSolutionStepValue(DISPLACEMENT); + IndexType index = 6 * i; + u[index] = disp[0]; + u[index + 1] = disp[1]; + u[index + 2] = disp[2]; + + const array_1d rot = r_geometry_master[i].FastGetSolutionStepValue(ROTATION); + u[index + 3] = rot[0]; + u[index + 4] = rot[1]; + u[index + 5] = rot[2]; + } + for (IndexType i = 0; i < number_of_nodes_slave; ++i) + { + const array_1d disp = r_geometry_slave[i].FastGetSolutionStepValue(DISPLACEMENT); + IndexType index = 6 * (i + number_of_nodes_master); + u[index] = disp[0]; + u[index + 1] = disp[1]; + u[index + 2] = disp[2]; + + const array_1d rot = r_geometry_slave[i].FastGetSolutionStepValue(ROTATION); + u[index + 3] = rot[0]; + u[index + 4] = rot[1]; + u[index + 5] = rot[2]; + } + + noalias(rRightHandSideVector) -= prod(prod(trans(H), H), u) * penalty_integration; + } + } + + KRATOS_CATCH("") + } + + void CouplingPenalty6pCondition::DeterminantOfJacobianInitial( + const GeometryType& rGeometry, + Vector& rDeterminantOfJacobian) + { + const IndexType nb_integration_points = rGeometry.IntegrationPointsNumber(); + if (rDeterminantOfJacobian.size() != nb_integration_points) { + rDeterminantOfJacobian.resize(nb_integration_points, false); + } + + const SizeType working_space_dimension = rGeometry.WorkingSpaceDimension(); + const SizeType local_space_dimension = rGeometry.LocalSpaceDimension(); + const SizeType nb_nodes = rGeometry.PointsNumber(); + + Matrix J = ZeroMatrix(working_space_dimension, local_space_dimension); + for (IndexType pnt = 0; pnt < nb_integration_points; pnt++) + { + const Matrix& r_DN_De = rGeometry.ShapeFunctionsLocalGradients()[pnt]; + J.clear(); + for (IndexType i = 0; i < nb_nodes; ++i) { + const array_1d& r_coordinates = rGeometry[i].GetInitialPosition(); + for (IndexType k = 0; k < working_space_dimension; ++k) { + const double value = r_coordinates[k]; + for (IndexType m = 0; m < local_space_dimension; ++m) { + J(k, m) += value * r_DN_De(i, m); + } + } + } + + //Compute the tangent and the normal to the boundary vector + array_1d local_tangent; + GetGeometry().GetGeometryPart(0).Calculate(LOCAL_TANGENT, local_tangent); + + array_1d a_1 = column(J, 0); + array_1d a_2 = column(J, 1); + + rDeterminantOfJacobian[pnt] = norm_2(a_1 * local_tangent[0] + a_2 * local_tangent[1]); + } + } + + int CouplingPenalty6pCondition::Check(const ProcessInfo& rCurrentProcessInfo) const + { + KRATOS_ERROR_IF_NOT(GetProperties().Has(PENALTY_FACTOR)) + << "No penalty factor (PENALTY_FACTOR) defined in property of SupportPenaltyCondition" << std::endl; + return 0; + } + + void CouplingPenalty6pCondition::EquationIdVector( + EquationIdVectorType& rResult, + const ProcessInfo& rCurrentProcessInfo) const + { + KRATOS_TRY; + + const auto& r_geometry_master = GetGeometry().GetGeometryPart(0); + const auto& r_geometry_slave = GetGeometry().GetGeometryPart(1); + + const SizeType number_of_nodes_master = r_geometry_master.size(); + const SizeType number_of_nodes_slave = r_geometry_slave.size(); + + if (rResult.size() != 6 * (number_of_nodes_master + number_of_nodes_slave)) + rResult.resize(6 * (number_of_nodes_master + number_of_nodes_slave), false); + + for (IndexType i = 0; i < number_of_nodes_master; ++i) { + const IndexType index = i * 6; + const auto& r_node = r_geometry_master[i]; + rResult[index] = r_node.GetDof(DISPLACEMENT_X).EquationId(); + rResult[index + 1] = r_node.GetDof(DISPLACEMENT_Y).EquationId(); + rResult[index + 2] = r_node.GetDof(DISPLACEMENT_Z).EquationId(); + rResult[index + 3] = r_node.GetDof(ROTATION_X).EquationId(); + rResult[index + 4] = r_node.GetDof(ROTATION_Y).EquationId(); + rResult[index + 5] = r_node.GetDof(ROTATION_Z).EquationId(); + } + + for (IndexType i = 0; i < number_of_nodes_slave; ++i) { + const IndexType index = 6 * (i + number_of_nodes_master); + const auto& r_node = r_geometry_slave[i]; + rResult[index] = r_node.GetDof(DISPLACEMENT_X).EquationId(); + rResult[index + 1] = r_node.GetDof(DISPLACEMENT_Y).EquationId(); + rResult[index + 2] = r_node.GetDof(DISPLACEMENT_Z).EquationId(); + rResult[index + 3] = r_node.GetDof(ROTATION_X).EquationId(); + rResult[index + 4] = r_node.GetDof(ROTATION_Y).EquationId(); + rResult[index + 5] = r_node.GetDof(ROTATION_Z).EquationId(); + } + + KRATOS_CATCH("") + } + + void CouplingPenalty6pCondition::GetDofList( + DofsVectorType& rElementalDofList, + const ProcessInfo& rCurrentProcessInfo) const + { + KRATOS_TRY; + + const auto r_geometry_master = GetGeometry().GetGeometryPart(0); + const auto r_geometry_slave = GetGeometry().GetGeometryPart(1); + + const SizeType number_of_nodes_master = r_geometry_master.size(); + const SizeType number_of_nodes_slave = r_geometry_slave.size(); + + rElementalDofList.resize(0); + rElementalDofList.reserve(6 * (number_of_nodes_master + number_of_nodes_slave)); + + for (IndexType i = 0; i < number_of_nodes_master; ++i) { + const auto& r_node = r_geometry_master.GetPoint(i); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_X)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Y)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Z)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_X)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Y)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Z)); + + } + + for (IndexType i = 0; i < number_of_nodes_slave; ++i) { + const auto& r_node = r_geometry_slave.GetPoint(i); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_X)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Y)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Z)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_X)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Y)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Z)); + } + + KRATOS_CATCH("") + } +} // Namespace Kratos + + diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h new file mode 100644 index 000000000000..56ae604541cc --- /dev/null +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h @@ -0,0 +1,249 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Ricky Aristio +// + +#pragma once + +// System includes +#include "includes/define.h" +#include "includes/condition.h" + +// External includes + +// Project includes +#include "iga_application_variables.h" +#include "custom_utilities/iga_flags.h" + +#include "geometries/coupling_geometry.h" + +namespace Kratos +{ + +/// Penalty factor based coupling condition. +/** This condition can be used to apply continuity between different +* discretizations with the penalty approach. +* +* The aproach is described in https://doi.org/10.1186/s40323-018-0109-4 +* Eq 15 ff +* +* The condition needs a PENALTY as parameter in the Properties. +* The Geometry needs to be of type CouplingMasterSlave and must have +* at least one slave geometry. +* The continuities can be enabled or disabled with the +* FIX_DISPLACEMENT_{dir} flags. +*/ +class CouplingPenalty6pCondition + : public Condition +{ +public: + ///@name Type Definitions + ///@{ + + /// Counted pointer of CouplingPenalty6pCondition + KRATOS_CLASS_POINTER_DEFINITION(CouplingPenalty6pCondition); + + /// Size types + typedef std::size_t SizeType; + typedef std::size_t IndexType; + + ///@} + ///@name Life Cycle + ///@{ + + /// Constructor with Id and geometry + CouplingPenalty6pCondition( + IndexType NewId, + GeometryType::Pointer pGeometry) + : Condition(NewId, pGeometry) + {}; + + /// Constructor with Id, geometry and property + CouplingPenalty6pCondition( + IndexType NewId, + GeometryType::Pointer pGeometry, + PropertiesType::Pointer pProperties) + : Condition(NewId, pGeometry, pProperties) + {}; + + /// Default constructor + CouplingPenalty6pCondition() + : Condition() + {}; + + /// Destructor. + virtual ~CouplingPenalty6pCondition() = default; + + ///@} + ///@name Life Cycle + ///@{ + + /// Create with Id, pointer to geometry and pointer to property + Condition::Pointer Create( + IndexType NewId, + GeometryType::Pointer pGeom, + PropertiesType::Pointer pProperties + ) const override + { + return Kratos::make_intrusive( + NewId, pGeom, pProperties); + }; + + /// Create with Id, pointer to geometry and pointer to property + Condition::Pointer Create( + IndexType NewId, + NodesArrayType const& ThisNodes, + PropertiesType::Pointer pProperties + ) const override + { + return Kratos::make_intrusive< CouplingPenalty6pCondition >( + NewId, GetGeometry().Create(ThisNodes), pProperties); + }; + + ///@} + ///@name Operations + ///@{ + + /** + * @brief This is called during the assembling process in order + * to calculate the condition right hand side matrix + * @param rLeftHandSideMatrix the condition right hand side matrix + * @param rCurrentProcessInfo the current process info + */ + void CalculateRightHandSide( + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo) override + { + MatrixType left_hand_side_matrix = Matrix(0, 0); + + CalculateAll(left_hand_side_matrix, rRightHandSideVector, + rCurrentProcessInfo, false, true); + } + + /** + * @brief This is called during the assembling process in order + * to calculate the condition left hand side matrix + * @param rLeftHandSideMatrix the condition left hand side matrix + * @param rCurrentProcessInfo the current process info + */ + void CalculateLeftHandSide( + MatrixType& rLeftHandSideMatrix, + const ProcessInfo& rCurrentProcessInfo) override + { + VectorType right_hand_side_vector = Vector(0); + + CalculateAll(rLeftHandSideMatrix, right_hand_side_vector, + rCurrentProcessInfo, true, false); + } + + /** + * @brief This function provides a more general interface to the element. + * @details It is designed so that rLHSvariables and rRHSvariables are + * passed to the element thus telling what is the desired output + * @param rLeftHandSideMatrix container with the output Left Hand Side matrix + * @param rRightHandSideVector container for the desired RHS output + * @param rCurrentProcessInfo the current process info instance + */ + void CalculateLocalSystem( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo) override + { + CalculateAll(rLeftHandSideMatrix, rRightHandSideVector, + rCurrentProcessInfo, true, true); + } + + /** + * @brief Sets on rResult the ID's of the element degrees of freedom + * @param rResult The vector containing the equation id + * @param rCurrentProcessInfo The current process info instance + */ + void EquationIdVector( + EquationIdVectorType& rResult, + const ProcessInfo& rCurrentProcessInfo + ) const override; + + /** + * @brief Sets on rElementalDofList the degrees of freedom of the considered element geometry + * @param rElementalDofList The vector containing the dof of the element + * @param rCurrentProcessInfo The current process info instance + */ + void GetDofList( + DofsVectorType& rElementalDofList, + const ProcessInfo& rCurrentProcessInfo + ) const override; + + /// Calculates left (K) and right (u) hand sides, according to the flags + void CalculateAll( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo, + const bool CalculateStiffnessMatrixFlag, + const bool CalculateResidualVectorFlag + ); + + void DeterminantOfJacobianInitial( + const GeometryType& rGeometry, + Vector& rDeterminantOfJacobian); + + ///@} + ///@name Check + ///@{ + + /// Performs check if Penalty factor is provided. + int Check(const ProcessInfo& rCurrentProcessInfo) const override; + + ///@} + ///@name Input and output + ///@{ + + /// Turn back information as a string. + std::string Info() const override + { + std::stringstream buffer; + buffer << "\"CouplingPenalty6pCondition\" #" << Id(); + return buffer.str(); + } + + /// Print information about this object. + void PrintInfo(std::ostream& rOStream) const override + { + rOStream << "\"CouplingPenalty6pCondition\" #" << Id(); + } + + /// Print object's data. + void PrintData(std::ostream& rOStream) const override { + pGetGeometry()->PrintData(rOStream); + } + + ///@} + +private: + + ///@name Serialization + ///@{ + + friend class Serializer; + + virtual void save(Serializer& rSerializer) const override + { + KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, Condition); + } + + virtual void load(Serializer& rSerializer) override + { + KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, Condition); + } + + ///@} + +}; // Class CouplingPenalty6pCondition + +} // namespace Kratos. \ No newline at end of file diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp new file mode 100644 index 000000000000..4004e491fb92 --- /dev/null +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp @@ -0,0 +1,199 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Ricky Aristio +// Tobias Teschemacher +// + +// System includes + +// External includes + +// Project includes +#include "custom_conditions/support_penalty_6p_condition.h" + +namespace Kratos +{ + void SupportPenalty6pCondition::CalculateAll( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo, + const bool CalculateStiffnessMatrixFlag, + const bool CalculateResidualVectorFlag + ) + { + KRATOS_TRY + const double penalty = GetProperties()[PENALTY_FACTOR]; + const double penalty_rotation = GetProperties()[PENALTY_ROTATION_FACTOR]; + + const auto& r_geometry = GetGeometry(); + const SizeType number_of_nodes = r_geometry.size(); + const SizeType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes; + + // Integration + const GeometryType::IntegrationPointsArrayType& integration_points = r_geometry.IntegrationPoints(); + + // Determine the integration: conservative -> initial; non-conservative -> current + Vector determinant_jacobian_vector(integration_points.size()); + const bool integrate_conservative = GetProperties().Has(INTEGRATE_CONSERVATIVE) + ? GetProperties()[INTEGRATE_CONSERVATIVE] + : false; + if (integrate_conservative) { + DeterminantOfJacobianInitial(r_geometry, determinant_jacobian_vector); + } else { + r_geometry.DeterminantOfJacobian(determinant_jacobian_vector); + } + + for (IndexType point_number = 0; point_number < integration_points.size(); ++point_number) + { + const Matrix& N = r_geometry.ShapeFunctionsValues(); + + //FOR DISPLACEMENTS + Matrix H = ZeroMatrix(6, mat_size); + for (IndexType i = 0; i < number_of_nodes; ++i) + { + IndexType index = 6 * i; + H(0, index) = N(point_number, i); + H(1, index + 1) = N(point_number, i); + H(2, index + 2) = N(point_number, i); + H(3, index + 3) = N(point_number, i); + H(4, index + 4) = N(point_number, i); + H(5, index + 5) = N(point_number, i); + } + + // Differential area + const double penalty_integration = penalty * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + const double penalty_rotation_integration = penalty_rotation * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + + // Assembly + if (CalculateStiffnessMatrixFlag) { + noalias(rLeftHandSideMatrix) += prod(trans(H), H) * penalty_integration; + } + if (CalculateResidualVectorFlag) { + + const array_1d& displacement = Has(DISPLACEMENT) + ? this->GetValue(DISPLACEMENT) + : ZeroVector(3); + + const array_1d& rotation = Has(ROTATION) + ? this->GetValue(ROTATION) + : ZeroVector(3); + + Vector u(mat_size); + for (IndexType i = 0; i < number_of_nodes; ++i) + { + const array_1d disp = r_geometry[i].FastGetSolutionStepValue(DISPLACEMENT); + const array_1d rot = r_geometry[i].FastGetSolutionStepValue(ROTATION); + + IndexType index = 6 * i; + u[index] = (disp[0] - displacement[0]); + u[index + 1] = (disp[1] - displacement[1]); + u[index + 2] = (disp[2] - displacement[2]); + u[index + 3] = (rot[0] - rotation[0]); + u[index + 4] = (rot[1] - rotation[1]); + u[index + 5] = (rot[2] - rotation[2]); + } + + noalias(rRightHandSideVector) -= prod(prod(trans(H), H), u) * penalty_integration; + } + } + KRATOS_CATCH("") + } + + void SupportPenalty6pCondition::DeterminantOfJacobianInitial( + const GeometryType& rGeometry, + Vector& rDeterminantOfJacobian) + { + const IndexType nb_integration_points = rGeometry.IntegrationPointsNumber(); + if (rDeterminantOfJacobian.size() != nb_integration_points) { + rDeterminantOfJacobian.resize(nb_integration_points, false); + } + + const SizeType working_space_dimension = rGeometry.WorkingSpaceDimension(); + const SizeType local_space_dimension = rGeometry.LocalSpaceDimension(); + const SizeType number_of_nodes = rGeometry.PointsNumber(); + + Matrix J = ZeroMatrix(working_space_dimension, local_space_dimension); + for (IndexType point_number = 0; point_number < nb_integration_points; ++point_number) + { + const Matrix& r_DN_De = rGeometry.ShapeFunctionsLocalGradients()[point_number]; + J.clear(); + for (IndexType i = 0; i < number_of_nodes; ++i) { + const array_1d& r_coordinates = rGeometry[i].GetInitialPosition(); + for (IndexType k = 0; k < working_space_dimension; ++k) { + for (IndexType m = 0; m < local_space_dimension; ++m) { + J(k, m) += r_coordinates[k] * r_DN_De(i, m); + } + } + } + + //Compute the tangent and the normal to the boundary vector + array_1d local_tangent; + GetGeometry().Calculate(LOCAL_TANGENT, local_tangent); + + array_1d a_1 = column(J, 0); + array_1d a_2 = column(J, 1); + + rDeterminantOfJacobian[point_number] = norm_2(a_1 * local_tangent[0] + a_2 * local_tangent[1]); + } + } + + int SupportPenalty6pCondition::Check(const ProcessInfo& rCurrentProcessInfo) const + { + KRATOS_ERROR_IF_NOT(GetProperties().Has(PENALTY_FACTOR)) + << "No penalty factor (PENALTY_FACTOR) defined in property of SupportPenalty6pCondition" << std::endl; + return 0; + } + + void SupportPenalty6pCondition::EquationIdVector( + EquationIdVectorType& rResult, + const ProcessInfo& rCurrentProcessInfo + ) const + { + const auto& r_geometry = GetGeometry(); + const SizeType number_of_nodes = r_geometry.size(); + + if (rResult.size() != 6 * number_of_nodes) + rResult.resize(6 * number_of_nodes, false); + + for (IndexType i = 0; i < number_of_nodes; ++i) { + const IndexType index = i * 6; + const auto& r_node = r_geometry[i]; + rResult[index] = r_node.GetDof(DISPLACEMENT_X).EquationId(); + rResult[index + 1] = r_node.GetDof(DISPLACEMENT_Y).EquationId(); + rResult[index + 2] = r_node.GetDof(DISPLACEMENT_Z).EquationId(); + rResult[index + 3] = r_node.GetDof(ROTATION_X).EquationId(); + rResult[index + 4] = r_node.GetDof(ROTATION_Y).EquationId(); + rResult[index + 5] = r_node.GetDof(ROTATION_Z).EquationId(); + } + } + + void SupportPenalty6pCondition::GetDofList( + DofsVectorType& rElementalDofList, + const ProcessInfo& rCurrentProcessInfo + ) const + { + const auto& r_geometry = GetGeometry(); + const SizeType number_of_nodes = r_geometry.size(); + + rElementalDofList.resize(0); + rElementalDofList.reserve(6 * number_of_nodes); + + for (IndexType i = 0; i < number_of_nodes; ++i) { + const auto& r_node = r_geometry[i]; + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_X)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Y)); + rElementalDofList.push_back(r_node.pGetDof(DISPLACEMENT_Z)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_X)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Y)); + rElementalDofList.push_back(r_node.pGetDof(ROTATION_Z)); + } + }; + +} // Namespace Kratos diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h new file mode 100644 index 000000000000..ebdfffa41f18 --- /dev/null +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h @@ -0,0 +1,253 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// + +#pragma once + +// System includes +#include "includes/define.h" +#include "includes/condition.h" + +// External includes + +// Project includes +#include "iga_application_variables.h" + +namespace Kratos +{ + /// Condition for penalty support condition + class SupportPenalty6pCondition + : public Condition + { + public: + ///@name Type Definitions + ///@{ + + /// Counted pointer definition of SupportPenalty6pCondition + KRATOS_CLASS_INTRUSIVE_POINTER_DEFINITION(SupportPenalty6pCondition); + + /// Size types + typedef std::size_t SizeType; + typedef std::size_t IndexType; + + ///@} + ///@name Life Cycle + ///@{ + + /// Constructor with Id and geometry + SupportPenalty6pCondition( + IndexType NewId, + GeometryType::Pointer pGeometry) + : Condition(NewId, pGeometry) + {}; + + /// Constructor with Id, geometry and property + SupportPenalty6pCondition( + IndexType NewId, + GeometryType::Pointer pGeometry, + PropertiesType::Pointer pProperties) + : Condition(NewId, pGeometry, pProperties) + {}; + + /// Default constructor + SupportPenalty6pCondition() : Condition() + {}; + + /// Destructor + virtual ~SupportPenalty6pCondition() override + {}; + + ///@} + ///@name Life Cycle + ///@{ + + /// Create with Id, pointer to geometry and pointer to property + Condition::Pointer Create( + IndexType NewId, + GeometryType::Pointer pGeom, + PropertiesType::Pointer pProperties + ) const override + { + return Kratos::make_intrusive( + NewId, pGeom, pProperties); + }; + + /// Create with Id, pointer to geometry and pointer to property + Condition::Pointer Create( + IndexType NewId, + NodesArrayType const& ThisNodes, + PropertiesType::Pointer pProperties + ) const override + { + return Kratos::make_intrusive( + NewId, GetGeometry().Create(ThisNodes), pProperties); + }; + + ///@} + ///@name Operations + ///@{ + + /** + * @brief This is called during the assembling process in order + * to calculate the condition right hand side matrix + * @param rLeftHandSideMatrix the condition right hand side matrix + * @param rCurrentProcessInfo the current process info + */ + void CalculateRightHandSide( + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo) override + { + const SizeType mat_size = GetGeometry().size() * 3; + + if (rRightHandSideVector.size() != mat_size) + rRightHandSideVector.resize(mat_size); + noalias(rRightHandSideVector) = ZeroVector(mat_size); + + MatrixType left_hand_side_matrix; + + CalculateAll(left_hand_side_matrix, rRightHandSideVector, + rCurrentProcessInfo, false, true); + } + + /** + * @brief This is called during the assembling process in order + * to calculate the condition left hand side matrix + * @param rLeftHandSideMatrix the condition left hand side matrix + * @param rCurrentProcessInfo the current process info + */ + void CalculateLeftHandSide( + MatrixType& rLeftHandSideMatrix, + const ProcessInfo& rCurrentProcessInfo) override + { + const SizeType mat_size = GetGeometry().size() * 3; + + VectorType right_hand_side_vector; + + if (rLeftHandSideMatrix.size1() != mat_size && rLeftHandSideMatrix.size2()) + rLeftHandSideMatrix.resize(mat_size, mat_size); + noalias(rLeftHandSideMatrix) = ZeroMatrix(mat_size, mat_size); + + CalculateAll(rLeftHandSideMatrix, right_hand_side_vector, + rCurrentProcessInfo, true, false); + } + + /** + * @brief This function provides a more general interface to the element. + * @details It is designed so that rLHSvariables and rRHSvariables are + * passed to the element thus telling what is the desired output + * @param rLeftHandSideMatrix container with the output Left Hand Side matrix + * @param rRightHandSideVector container for the desired RHS output + * @param rCurrentProcessInfo the current process info instance + */ + void CalculateLocalSystem( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo) override + { + const SizeType mat_size = GetGeometry().size() * 3; + + if (rRightHandSideVector.size() != mat_size) + rRightHandSideVector.resize(mat_size); + noalias(rRightHandSideVector) = ZeroVector(mat_size); + + if (rLeftHandSideMatrix.size1() != mat_size) + rLeftHandSideMatrix.resize(mat_size, mat_size); + noalias(rLeftHandSideMatrix) = ZeroMatrix(mat_size, mat_size); + + CalculateAll(rLeftHandSideMatrix, rRightHandSideVector, + rCurrentProcessInfo, true, true); + } + + /** + * @brief Sets on rResult the ID's of the element degrees of freedom + * @param rResult The vector containing the equation id + * @param rCurrentProcessInfo The current process info instance + */ + void EquationIdVector( + EquationIdVectorType& rResult, + const ProcessInfo& rCurrentProcessInfo + ) const override; + + /** + * @brief Sets on rConditionDofList the degrees of freedom of the considered element geometry + * @param rElementalDofList The vector containing the dof of the element + * @param rCurrentProcessInfo The current process info instance + */ + void GetDofList( + DofsVectorType& rElementalDofList, + const ProcessInfo& rCurrentProcessInfo + ) const override; + + /// Calculates left (K) and right (u) hand sides, according to the flags + void CalculateAll( + MatrixType& rLeftHandSideMatrix, + VectorType& rRightHandSideVector, + const ProcessInfo& rCurrentProcessInfo, + const bool CalculateStiffnessMatrixFlag, + const bool CalculateResidualVectorFlag + ); + + void DeterminantOfJacobianInitial( + const GeometryType& rGeometry, + Vector& rDeterminantOfJacobian); + + ///@} + ///@name Check + ///@{ + + /// Performs check if Penalty factor is provided. + int Check(const ProcessInfo& rCurrentProcessInfo) const override; + + ///@} + ///@name Input and output + ///@{ + + /// Turn back information as a string. + std::string Info() const override + { + std::stringstream buffer; + buffer << "\"SupportPenalty6pCondition\" #" << Id(); + return buffer.str(); + } + + /// Print information about this object. + void PrintInfo(std::ostream& rOStream) const override + { + rOStream << "\"SupportPenalty6pCondition\" #" << Id(); + } + + /// Print object's data. + void PrintData(std::ostream& rOStream) const override + { + pGetGeometry()->PrintData(rOStream); + } + + ///@} + + private: + ///@name Serialization + ///@{ + + friend class Serializer; + + virtual void save(Serializer& rSerializer) const override + { + KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, Condition); + } + + virtual void load(Serializer& rSerializer) override + { + KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, Condition); + } + + ///@} + + }; // Class SupportPenalty6pCondition + +} // namespace Kratos. diff --git a/applications/IgaApplication/iga_application.cpp b/applications/IgaApplication/iga_application.cpp index 6ef75192f997..d6649ed58443 100644 --- a/applications/IgaApplication/iga_application.cpp +++ b/applications/IgaApplication/iga_application.cpp @@ -50,12 +50,16 @@ KratosIgaApplication::KratosIgaApplication() new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mCouplingPenaltyCondition(0, Condition::GeometryType::Pointer( new Geometry(Condition::GeometryType::PointsArrayType(1)))) + , mCouplingPenalty6pCondition(0, Condition::GeometryType::Pointer( + new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mCouplingLagrangeCondition(0, Condition::GeometryType::Pointer( new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mCouplingNitscheCondition(0, Condition::GeometryType::Pointer( new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mSupportPenaltyCondition(0, Condition::GeometryType::Pointer( new Geometry(Condition::GeometryType::PointsArrayType(1)))) + , mSupportPenalty6pCondition(0, Condition::GeometryType::Pointer( + new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mSupportLagrangeCondition(0, Condition::GeometryType::Pointer( new Geometry(Condition::GeometryType::PointsArrayType(1)))) , mSupportNitscheCondition(0, Condition::GeometryType::Pointer( @@ -109,9 +113,11 @@ KRATOS_INFO("") << " KRATOS _____ _____\n" KRATOS_REGISTER_CONDITION("LoadCondition", mLoadCondition) KRATOS_REGISTER_CONDITION("LoadMomentDirector5pCondition", mLoadMomentDirector5pCondition) KRATOS_REGISTER_CONDITION("CouplingPenaltyCondition", mCouplingPenaltyCondition) + KRATOS_REGISTER_CONDITION("CouplingPenalty6pCondition", mCouplingPenalty6pCondition) KRATOS_REGISTER_CONDITION("CouplingLagrangeCondition", mCouplingLagrangeCondition) KRATOS_REGISTER_CONDITION("CouplingNitscheCondition", mCouplingNitscheCondition) KRATOS_REGISTER_CONDITION("SupportPenaltyCondition", mSupportPenaltyCondition) + KRATOS_REGISTER_CONDITION("SupportPenalty6pCondition", mSupportPenalty6pCondition) KRATOS_REGISTER_CONDITION("SupportLagrangeCondition", mSupportLagrangeCondition) KRATOS_REGISTER_CONDITION("SupportNitscheCondition", mSupportNitscheCondition) KRATOS_REGISTER_CONDITION("SupportLaplacianCondition", mSupportLaplacianCondition) diff --git a/applications/IgaApplication/iga_application.h b/applications/IgaApplication/iga_application.h index f8cdf3ac6a46..3971128c2590 100644 --- a/applications/IgaApplication/iga_application.h +++ b/applications/IgaApplication/iga_application.h @@ -36,9 +36,11 @@ #include "custom_conditions/load_condition.h" #include "custom_conditions/load_moment_director_5p_condition.h" #include "custom_conditions/coupling_penalty_condition.h" +#include "custom_conditions/coupling_penalty_6p_condition.h" #include "custom_conditions/coupling_lagrange_condition.h" #include "custom_conditions/coupling_nitsche_condition.h" #include "custom_conditions/support_penalty_condition.h" +#include "custom_conditions/support_penalty_6p_condition.h" #include "custom_conditions/support_lagrange_condition.h" #include "custom_conditions/support_nitsche_condition.h" #include "custom_conditions/support_laplacian_condition.h" @@ -153,9 +155,11 @@ class KRATOS_API(IGA_APPLICATION) KratosIgaApplication : public KratosApplicatio const LoadCondition mLoadCondition; const LoadMomentDirector5pCondition mLoadMomentDirector5pCondition; const CouplingPenaltyCondition mCouplingPenaltyCondition; + const CouplingPenalty6pCondition mCouplingPenalty6pCondition; const CouplingLagrangeCondition mCouplingLagrangeCondition; const CouplingNitscheCondition mCouplingNitscheCondition; const SupportPenaltyCondition mSupportPenaltyCondition; + const SupportPenalty6pCondition mSupportPenalty6pCondition; const SupportLagrangeCondition mSupportLagrangeCondition; const SupportNitscheCondition mSupportNitscheCondition; const SupportLaplacianCondition mSupportLaplacianCondition; From 9b048c31c4917c6df107422452389f83afc6f7c7 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Wed, 3 Jun 2026 14:24:13 +0200 Subject: [PATCH 25/50] add penalty rotation factor variable --- .../IgaApplication/custom_python/iga_python_application.cpp | 1 + applications/IgaApplication/iga_application.cpp | 1 + applications/IgaApplication/iga_application_variables.cpp | 1 + applications/IgaApplication/iga_application_variables.h | 1 + 4 files changed, 4 insertions(+) diff --git a/applications/IgaApplication/custom_python/iga_python_application.cpp b/applications/IgaApplication/custom_python/iga_python_application.cpp index 028609714310..bce24fba8277 100644 --- a/applications/IgaApplication/custom_python/iga_python_application.cpp +++ b/applications/IgaApplication/custom_python/iga_python_application.cpp @@ -91,6 +91,7 @@ PYBIND11_MODULE(KratosIgaApplication, m) KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, INTEGRATE_CONSERVATIVE) KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, PENALTY_FACTOR) + KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, PENALTY_ROTATION_FACTOR) KRATOS_REGISTER_IN_PYTHON_3D_VARIABLE_WITH_COMPONENTS(m, VECTOR_LAGRANGE_MULTIPLIER_REACTION) KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, NITSCHE_STABILIZATION_FACTOR) diff --git a/applications/IgaApplication/iga_application.cpp b/applications/IgaApplication/iga_application.cpp index d6649ed58443..baae891ab5e7 100644 --- a/applications/IgaApplication/iga_application.cpp +++ b/applications/IgaApplication/iga_application.cpp @@ -203,6 +203,7 @@ KRATOS_INFO("") << " KRATOS _____ _____\n" KRATOS_REGISTER_VARIABLE(INTEGRATE_CONSERVATIVE) KRATOS_REGISTER_VARIABLE(PENALTY_FACTOR) + KRATOS_REGISTER_VARIABLE(PENALTY_ROTATION_FACTOR) KRATOS_REGISTER_3D_VARIABLE_WITH_COMPONENTS(VECTOR_LAGRANGE_MULTIPLIER_REACTION) KRATOS_REGISTER_VARIABLE(NITSCHE_STABILIZATION_FACTOR) diff --git a/applications/IgaApplication/iga_application_variables.cpp b/applications/IgaApplication/iga_application_variables.cpp index bc1617856d42..54f9eafeddb5 100644 --- a/applications/IgaApplication/iga_application_variables.cpp +++ b/applications/IgaApplication/iga_application_variables.cpp @@ -78,6 +78,7 @@ KRATOS_CREATE_VARIABLE(bool, INTEGRATE_CONSERVATIVE) //Penalty Variables KRATOS_CREATE_VARIABLE(double, PENALTY_FACTOR) +KRATOS_CREATE_VARIABLE(double, PENALTY_ROTATION_FACTOR) KRATOS_CREATE_3D_VARIABLE_WITH_COMPONENTS(VECTOR_LAGRANGE_MULTIPLIER_REACTION) //Nitsche Variables diff --git a/applications/IgaApplication/iga_application_variables.h b/applications/IgaApplication/iga_application_variables.h index 52295d352503..5f19cd6bf71f 100644 --- a/applications/IgaApplication/iga_application_variables.h +++ b/applications/IgaApplication/iga_application_variables.h @@ -87,6 +87,7 @@ KRATOS_DEFINE_APPLICATION_VARIABLE(IGA_APPLICATION, bool, INTEGRATE_CONSERVATIVE //Penalty Variables KRATOS_DEFINE_APPLICATION_VARIABLE(IGA_APPLICATION, double, PENALTY_FACTOR) +KRATOS_DEFINE_APPLICATION_VARIABLE(IGA_APPLICATION, double, PENALTY_ROTATION_FACTOR) KRATOS_DEFINE_3D_APPLICATION_VARIABLE_WITH_COMPONENTS(IGA_APPLICATION, VECTOR_LAGRANGE_MULTIPLIER_REACTION) //Nitsche Variables From 7d3d0f6ea61332e7a67a75f525a19db11b2c51f9 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Wed, 3 Jun 2026 17:13:11 +0200 Subject: [PATCH 26/50] refactor the conditions to support penalty rotation --- .../coupling_penalty_6p_condition.cpp | 121 +++++++++++------- .../coupling_penalty_6p_condition.h | 3 +- .../support_penalty_6p_condition.cpp | 83 ++++++++---- .../support_penalty_6p_condition.h | 9 +- 4 files changed, 136 insertions(+), 80 deletions(-) diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp index 948777de998d..fd1912147503 100644 --- a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp @@ -34,10 +34,12 @@ namespace Kratos const auto& r_geometry_slave = GetGeometry().GetGeometryPart(1); // Size definitions - const SizeType number_of_nodes_master = r_geometry_master.size(); - const SizeType number_of_nodes_slave = r_geometry_slave.size(); + const IndexType number_of_nodes_master = r_geometry_master.size(); + const IndexType number_of_nodes_slave = r_geometry_slave.size(); + const IndexType number_of_nodes_total = number_of_nodes_master + number_of_nodes_slave; - const SizeType mat_size = 6 * (number_of_nodes_master + number_of_nodes_slave); + const IndexType mat_size = 6 * number_of_nodes_total; + const IndexType disp_size = 3 * number_of_nodes_total; // Memory allocation if (CalculateStiffnessMatrixFlag) { @@ -73,81 +75,110 @@ namespace Kratos Matrix N_master = r_geometry_master.ShapeFunctionsValues(); Matrix N_slave = r_geometry_slave.ShapeFunctionsValues(); - //FOR DISPLACEMENTS - Matrix H = ZeroMatrix(6, mat_size); + // Shape function matrix for displacements and rotations + Matrix H_disp = ZeroMatrix(3, disp_size); + Matrix H_rot = ZeroMatrix(3, disp_size); + for (IndexType i = 0; i < number_of_nodes_master; ++i) { - IndexType index = 6 * i; + IndexType index = 3 * i; if (Is(IgaFlags::FIX_DISPLACEMENT_X)) - H(0, index) = N_master(point_number, i); + H_disp(0, index) = N_master(point_number, i); if (Is(IgaFlags::FIX_DISPLACEMENT_Y)) - H(1, index + 1) = N_master(point_number, i); + H_disp(1, index + 1) = N_master(point_number, i); if (Is(IgaFlags::FIX_DISPLACEMENT_Z)) - H(2, index + 2) = N_master(point_number, i); + H_disp(2, index + 2) = N_master(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_X)) - H(3, index + 3) = N_master(point_number, i); + H_rot(0, index + 3) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H(4, index + 4) = N_master(point_number, i); + H_rot(1, index + 4) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H(5, index + 5) = N_master(point_number, i); + H_rot(2, index + 5) = N_master(point_number, i); } for (IndexType i = 0; i < number_of_nodes_slave; ++i) { - IndexType index = 6 * (i + number_of_nodes_master); + IndexType index = 3 * (i + number_of_nodes_master); if (Is(IgaFlags::FIX_DISPLACEMENT_X)) - H(0, index) = -N_slave(point_number, i); + H_disp(0, index) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_DISPLACEMENT_Y)) - H(1, index + 1) = -N_slave(point_number, i); + H_disp(1, index + 1) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_DISPLACEMENT_Z)) - H(2, index + 2) = -N_slave(point_number, i); + H_disp(2, index + 2) = -N_slave(point_number, i); + if (Is(IgaFlags::FIX_ROTATION_X)) - H(3, index + 3) = -N_slave(point_number, i); + H_rot(0, index + 3) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H(4, index + 4) = -N_slave(point_number, i); + H_rot(1, index + 4) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H(5, index + 5) = -N_slave(point_number, i); + H_rot(2, index + 5) = -N_slave(point_number, i); } // Differential area const double penalty_integration = penalty * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; const double penalty_rotation_integration = penalty_rotation * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + // Matrix multiplication blocks + const Matrix HtH_disp = prod(trans(H_disp), H_disp); + const Matrix HtH_rot = prod(trans(H_rot), H_rot); + // Assembly if (CalculateStiffnessMatrixFlag) { - noalias(rLeftHandSideMatrix) += prod(trans(H), H) * penalty_integration; + for (IndexType i = 0; i < number_of_nodes_total; ++i) { + for (IndexType j = 0; j < number_of_nodes_total; ++j) { + for (IndexType ii = 0; ii < 3; ++ii) { + for (IndexType jj = 0; jj < 3; ++jj) { + rLeftHandSideMatrix(6 * i + ii, 6 * j + jj) += HtH_disp(3 * i + ii, 3 * j + jj) * penalty_integration; + rLeftHandSideMatrix(6 * i + 3 + ii, 6 * j + 3 + jj) += HtH_rot(3 * i + ii, 3 * j + jj) * penalty_rotation_integration; + } + } + } + } } if (CalculateResidualVectorFlag) { - Vector u(mat_size); + Vector u_disp(disp_size); + Vector u_rot(disp_size); + for (IndexType i = 0; i < number_of_nodes_master; ++i) { const array_1d disp = r_geometry_master[i].FastGetSolutionStepValue(DISPLACEMENT); - IndexType index = 6 * i; - u[index] = disp[0]; - u[index + 1] = disp[1]; - u[index + 2] = disp[2]; - const array_1d rot = r_geometry_master[i].FastGetSolutionStepValue(ROTATION); - u[index + 3] = rot[0]; - u[index + 4] = rot[1]; - u[index + 5] = rot[2]; + + IndexType index = 3 * i; + u_disp[index] = disp[0]; + u_disp[index + 1] = disp[1]; + u_disp[index + 2] = disp[2]; + + u_rot[index] = rot[0]; + u_rot[index + 1] = rot[1]; + u_rot[index + 2] = rot[2]; } for (IndexType i = 0; i < number_of_nodes_slave; ++i) { const array_1d disp = r_geometry_slave[i].FastGetSolutionStepValue(DISPLACEMENT); - IndexType index = 6 * (i + number_of_nodes_master); - u[index] = disp[0]; - u[index + 1] = disp[1]; - u[index + 2] = disp[2]; - const array_1d rot = r_geometry_slave[i].FastGetSolutionStepValue(ROTATION); - u[index + 3] = rot[0]; - u[index + 4] = rot[1]; - u[index + 5] = rot[2]; + + IndexType index = 3 * (i + number_of_nodes_master); + u_disp[index] = disp[0]; + u_disp[index + 1] = disp[1]; + u_disp[index + 2] = disp[2]; + + u_rot[index] = rot[0]; + u_rot[index + 1] = rot[1]; + u_rot[index + 2] = rot[2]; } - noalias(rRightHandSideVector) -= prod(prod(trans(H), H), u) * penalty_integration; + const Vector rhs_disp = prod(HtH_disp, u_disp) * penalty_integration; + const Vector rhs_rot = prod(HtH_rot, u_rot) * penalty_rotation_integration; + + for (IndexType i = 0; i < number_of_nodes_total; ++i) { + for (IndexType ii = 0; ii < 3; ++ii) { + rRightHandSideVector(6 * i + ii) -= rhs_disp(3 * i + ii); + rRightHandSideVector(6 * i + 3 + ii) -= rhs_rot(3 * i + ii); + } + } } } @@ -163,9 +194,9 @@ namespace Kratos rDeterminantOfJacobian.resize(nb_integration_points, false); } - const SizeType working_space_dimension = rGeometry.WorkingSpaceDimension(); - const SizeType local_space_dimension = rGeometry.LocalSpaceDimension(); - const SizeType nb_nodes = rGeometry.PointsNumber(); + const IndexType working_space_dimension = rGeometry.WorkingSpaceDimension(); + const IndexType local_space_dimension = rGeometry.LocalSpaceDimension(); + const IndexType nb_nodes = rGeometry.PointsNumber(); Matrix J = ZeroMatrix(working_space_dimension, local_space_dimension); for (IndexType pnt = 0; pnt < nb_integration_points; pnt++) @@ -209,8 +240,8 @@ namespace Kratos const auto& r_geometry_master = GetGeometry().GetGeometryPart(0); const auto& r_geometry_slave = GetGeometry().GetGeometryPart(1); - const SizeType number_of_nodes_master = r_geometry_master.size(); - const SizeType number_of_nodes_slave = r_geometry_slave.size(); + const IndexType number_of_nodes_master = r_geometry_master.size(); + const IndexType number_of_nodes_slave = r_geometry_slave.size(); if (rResult.size() != 6 * (number_of_nodes_master + number_of_nodes_slave)) rResult.resize(6 * (number_of_nodes_master + number_of_nodes_slave), false); @@ -249,8 +280,8 @@ namespace Kratos const auto r_geometry_master = GetGeometry().GetGeometryPart(0); const auto r_geometry_slave = GetGeometry().GetGeometryPart(1); - const SizeType number_of_nodes_master = r_geometry_master.size(); - const SizeType number_of_nodes_slave = r_geometry_slave.size(); + const IndexType number_of_nodes_master = r_geometry_master.size(); + const IndexType number_of_nodes_slave = r_geometry_slave.size(); rElementalDofList.resize(0); rElementalDofList.reserve(6 * (number_of_nodes_master + number_of_nodes_slave)); diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h index 56ae604541cc..2c190f5a7265 100644 --- a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.h @@ -50,8 +50,7 @@ class CouplingPenalty6pCondition /// Counted pointer of CouplingPenalty6pCondition KRATOS_CLASS_POINTER_DEFINITION(CouplingPenalty6pCondition); - /// Size types - typedef std::size_t SizeType; + /// Index type typedef std::size_t IndexType; ///@} diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp index 4004e491fb92..e1f7737d66ea 100644 --- a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp @@ -8,7 +8,6 @@ // Kratos default license: kratos/license.txt // // Main authors: Ricky Aristio -// Tobias Teschemacher // // System includes @@ -33,8 +32,9 @@ namespace Kratos const double penalty_rotation = GetProperties()[PENALTY_ROTATION_FACTOR]; const auto& r_geometry = GetGeometry(); - const SizeType number_of_nodes = r_geometry.size(); - const SizeType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes; + const IndexType number_of_nodes = r_geometry.size(); + const IndexType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes; + const IndexType disp_size = 3 * number_of_nodes; // Integration const GeometryType::IntegrationPointsArrayType& integration_points = r_geometry.IntegrationPoints(); @@ -54,53 +54,80 @@ namespace Kratos { const Matrix& N = r_geometry.ShapeFunctionsValues(); - //FOR DISPLACEMENTS - Matrix H = ZeroMatrix(6, mat_size); + // Shape function matrix for displacements and rotations + Matrix H_disp = ZeroMatrix(3, disp_size); + Matrix H_rot = ZeroMatrix(3, disp_size); + for (IndexType i = 0; i < number_of_nodes; ++i) { - IndexType index = 6 * i; - H(0, index) = N(point_number, i); - H(1, index + 1) = N(point_number, i); - H(2, index + 2) = N(point_number, i); - H(3, index + 3) = N(point_number, i); - H(4, index + 4) = N(point_number, i); - H(5, index + 5) = N(point_number, i); + IndexType index = 3 * i; + + H_disp(0, index) = N(point_number, i); + H_disp(1, index + 1) = N(point_number, i); + H_disp(2, index + 2) = N(point_number, i); + + H_rot(0, index) = N(point_number, i); + H_rot(1, index + 1) = N(point_number, i); + H_rot(2, index + 2) = N(point_number, i); } // Differential area const double penalty_integration = penalty * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; const double penalty_rotation_integration = penalty_rotation * integration_points[point_number].Weight() * determinant_jacobian_vector[point_number]; + // Matrix multiplication blocks + const Matrix HtH_disp = prod(trans(H_disp), H_disp); + const Matrix HtH_rot = prod(trans(H_rot), H_rot); + // Assembly if (CalculateStiffnessMatrixFlag) { - noalias(rLeftHandSideMatrix) += prod(trans(H), H) * penalty_integration; + for (IndexType i = 0; i < number_of_nodes; ++i) { + for (IndexType j = 0; j < number_of_nodes; ++j) { + for (IndexType ii = 0; ii < 3; ++ii) { + for (IndexType jj = 0; jj < 3; ++jj) { + rLeftHandSideMatrix(6 * i + ii, 6 * j + jj) += HtH_disp(3 * i + ii, 3 * j + jj) * penalty_integration; + rLeftHandSideMatrix(6 * i + 3 + ii, 6 * j + 3 + jj) += HtH_rot(3 * i + ii, 3 * j + jj) * penalty_rotation_integration; + } + } + } + } } if (CalculateResidualVectorFlag) { const array_1d& displacement = Has(DISPLACEMENT) ? this->GetValue(DISPLACEMENT) : ZeroVector(3); - const array_1d& rotation = Has(ROTATION) ? this->GetValue(ROTATION) : ZeroVector(3); - Vector u(mat_size); + Vector u_disp(disp_size); + Vector u_rot(disp_size); + for (IndexType i = 0; i < number_of_nodes; ++i) { const array_1d disp = r_geometry[i].FastGetSolutionStepValue(DISPLACEMENT); const array_1d rot = r_geometry[i].FastGetSolutionStepValue(ROTATION); - IndexType index = 6 * i; - u[index] = (disp[0] - displacement[0]); - u[index + 1] = (disp[1] - displacement[1]); - u[index + 2] = (disp[2] - displacement[2]); - u[index + 3] = (rot[0] - rotation[0]); - u[index + 4] = (rot[1] - rotation[1]); - u[index + 5] = (rot[2] - rotation[2]); + IndexType index = 3 * i; + u_disp[index] = (disp[0] - displacement[0]); + u_disp[index + 1] = (disp[1] - displacement[1]); + u_disp[index + 2] = (disp[2] - displacement[2]); + + u_rot[index] = (rot[0] - rotation[0]); + u_rot[index + 1] = (rot[1] - rotation[1]); + u_rot[index + 2] = (rot[2] - rotation[2]); } - noalias(rRightHandSideVector) -= prod(prod(trans(H), H), u) * penalty_integration; + const Vector rhs_disp = prod(HtH_disp, u_disp) * penalty_integration; + const Vector rhs_rot = prod(HtH_rot, u_rot) * penalty_rotation_integration; + + for (IndexType i = 0; i < number_of_nodes; ++i) { + for (IndexType ii = 0; ii < 3; ++ii) { + rRightHandSideVector(6 * i + ii) -= rhs_disp(3 * i + ii); + rRightHandSideVector(6 * i + 3 + ii) -= rhs_rot(3 * i + ii); + } + } } } KRATOS_CATCH("") @@ -115,9 +142,9 @@ namespace Kratos rDeterminantOfJacobian.resize(nb_integration_points, false); } - const SizeType working_space_dimension = rGeometry.WorkingSpaceDimension(); - const SizeType local_space_dimension = rGeometry.LocalSpaceDimension(); - const SizeType number_of_nodes = rGeometry.PointsNumber(); + const IndexType working_space_dimension = rGeometry.WorkingSpaceDimension(); + const IndexType local_space_dimension = rGeometry.LocalSpaceDimension(); + const IndexType number_of_nodes = rGeometry.PointsNumber(); Matrix J = ZeroMatrix(working_space_dimension, local_space_dimension); for (IndexType point_number = 0; point_number < nb_integration_points; ++point_number) @@ -157,7 +184,7 @@ namespace Kratos ) const { const auto& r_geometry = GetGeometry(); - const SizeType number_of_nodes = r_geometry.size(); + const IndexType number_of_nodes = r_geometry.size(); if (rResult.size() != 6 * number_of_nodes) rResult.resize(6 * number_of_nodes, false); @@ -180,7 +207,7 @@ namespace Kratos ) const { const auto& r_geometry = GetGeometry(); - const SizeType number_of_nodes = r_geometry.size(); + const IndexType number_of_nodes = r_geometry.size(); rElementalDofList.resize(0); rElementalDofList.reserve(6 * number_of_nodes); diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h index ebdfffa41f18..efed14a12861 100644 --- a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h @@ -32,8 +32,7 @@ namespace Kratos /// Counted pointer definition of SupportPenalty6pCondition KRATOS_CLASS_INTRUSIVE_POINTER_DEFINITION(SupportPenalty6pCondition); - /// Size types - typedef std::size_t SizeType; + /// Index type typedef std::size_t IndexType; ///@} @@ -103,7 +102,7 @@ namespace Kratos VectorType& rRightHandSideVector, const ProcessInfo& rCurrentProcessInfo) override { - const SizeType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 3; if (rRightHandSideVector.size() != mat_size) rRightHandSideVector.resize(mat_size); @@ -125,7 +124,7 @@ namespace Kratos MatrixType& rLeftHandSideMatrix, const ProcessInfo& rCurrentProcessInfo) override { - const SizeType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 3; VectorType right_hand_side_vector; @@ -150,7 +149,7 @@ namespace Kratos VectorType& rRightHandSideVector, const ProcessInfo& rCurrentProcessInfo) override { - const SizeType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 3; if (rRightHandSideVector.size() != mat_size) rRightHandSideVector.resize(mat_size); From be94b40c4fbdd534f85ebd8e08a7e3534702953e Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Wed, 3 Jun 2026 17:48:58 +0200 Subject: [PATCH 27/50] fix bug on material size --- .../custom_conditions/support_penalty_6p_condition.cpp | 2 +- .../custom_conditions/support_penalty_6p_condition.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp index e1f7737d66ea..abd741de13fe 100644 --- a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp @@ -33,7 +33,7 @@ namespace Kratos const auto& r_geometry = GetGeometry(); const IndexType number_of_nodes = r_geometry.size(); - const IndexType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes; + const IndexType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes * 2; const IndexType disp_size = 3 * number_of_nodes; // Integration diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h index efed14a12861..b666fbff8ef2 100644 --- a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.h @@ -102,7 +102,7 @@ namespace Kratos VectorType& rRightHandSideVector, const ProcessInfo& rCurrentProcessInfo) override { - const IndexType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 6; if (rRightHandSideVector.size() != mat_size) rRightHandSideVector.resize(mat_size); @@ -124,7 +124,7 @@ namespace Kratos MatrixType& rLeftHandSideMatrix, const ProcessInfo& rCurrentProcessInfo) override { - const IndexType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 6; VectorType right_hand_side_vector; @@ -149,7 +149,7 @@ namespace Kratos VectorType& rRightHandSideVector, const ProcessInfo& rCurrentProcessInfo) override { - const IndexType mat_size = GetGeometry().size() * 3; + const IndexType mat_size = GetGeometry().size() * 6; if (rRightHandSideVector.size() != mat_size) rRightHandSideVector.resize(mat_size); From e98335d04d9cac1e56b2b95534c03177d3936d85 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Wed, 3 Jun 2026 18:31:18 +0200 Subject: [PATCH 28/50] fix bug on indexing --- .../coupling_penalty_6p_condition.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp index fd1912147503..24ec4f2f8478 100644 --- a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp @@ -90,11 +90,11 @@ namespace Kratos H_disp(2, index + 2) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_X)) - H_rot(0, index + 3) = N_master(point_number, i); + H_rot(0, index) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H_rot(1, index + 4) = N_master(point_number, i); + H_rot(1, index + 2) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H_rot(2, index + 5) = N_master(point_number, i); + H_rot(2, index + 3) = N_master(point_number, i); } for (IndexType i = 0; i < number_of_nodes_slave; ++i) @@ -108,11 +108,11 @@ namespace Kratos H_disp(2, index + 2) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_X)) - H_rot(0, index + 3) = -N_slave(point_number, i); + H_rot(0, index) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H_rot(1, index + 4) = -N_slave(point_number, i); + H_rot(1, index + 2) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H_rot(2, index + 5) = -N_slave(point_number, i); + H_rot(2, index + 3) = -N_slave(point_number, i); } // Differential area From c7757fdb0f1137dbe7f83527566c8d4d6746df14 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Fri, 5 Jun 2026 10:24:46 +0200 Subject: [PATCH 29/50] fix indexing problem --- .../custom_conditions/coupling_penalty_6p_condition.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp index 24ec4f2f8478..537a67b7ff14 100644 --- a/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/coupling_penalty_6p_condition.cpp @@ -92,9 +92,9 @@ namespace Kratos if (Is(IgaFlags::FIX_ROTATION_X)) H_rot(0, index) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H_rot(1, index + 2) = N_master(point_number, i); + H_rot(1, index + 1) = N_master(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H_rot(2, index + 3) = N_master(point_number, i); + H_rot(2, index + 2) = N_master(point_number, i); } for (IndexType i = 0; i < number_of_nodes_slave; ++i) @@ -110,9 +110,9 @@ namespace Kratos if (Is(IgaFlags::FIX_ROTATION_X)) H_rot(0, index) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Y)) - H_rot(1, index + 2) = -N_slave(point_number, i); + H_rot(1, index + 1) = -N_slave(point_number, i); if (Is(IgaFlags::FIX_ROTATION_Z)) - H_rot(2, index + 3) = -N_slave(point_number, i); + H_rot(2, index + 2) = -N_slave(point_number, i); } // Differential area From ad40e65699a60d5e87145e1b80faf010c744ad97 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Fri, 5 Jun 2026 13:58:12 +0200 Subject: [PATCH 30/50] add support penalty test --- .../tests/shell_6p_element_tests.py | 212 +++++++++++++++++- 1 file changed, 208 insertions(+), 4 deletions(-) diff --git a/applications/IgaApplication/tests/shell_6p_element_tests.py b/applications/IgaApplication/tests/shell_6p_element_tests.py index 047efbb3266d..1cee6d853110 100644 --- a/applications/IgaApplication/tests/shell_6p_element_tests.py +++ b/applications/IgaApplication/tests/shell_6p_element_tests.py @@ -130,6 +130,104 @@ def solve_cantilever(create_geometry, iterations): return surface + def solve_cantilever_weak_support(create_geometry, iterations): + model = KM.Model() + model_part = model.CreateModelPart('Model') + + model_part.AddNodalSolutionStepVariable(KM.DISPLACEMENT) + model_part.AddNodalSolutionStepVariable(KM.ROTATION) + model_part.AddNodalSolutionStepVariable(KM.REACTION) + model_part.AddNodalSolutionStepVariable(KM.REACTION_MOMENT) + model_part.AddNodalSolutionStepVariable(SMA.POINT_LOAD) + + # create property for shell elements and penalty conditions + shell_properties = model_part.GetProperties()[1] + shell_properties.SetValue(KM.THICKNESS, 0.1) + shell_properties.SetValue(KM.YOUNG_MODULUS, 200000000) + shell_properties.SetValue(KM.POISSON_RATIO, 0) + shell_properties.SetValue(KM.CONSTITUTIVE_LAW, SMA.LinearElastic3DLaw()) + + penalty_properties = model_part.GetProperties()[2] + penalty_properties.SetValue(IGA.PENALTY_FACTOR, 1000000000.0) + penalty_properties.SetValue(IGA.PENALTY_ROTATION_FACTOR, 2000000000.0) + penalty_properties.SetValue(IGA.INTEGRATE_CONSERVATIVE, True) + + # create a brep surface + brep_surface, brep_curve_on_surface_left = create_geometry(model_part) + + # create quadrature_point_geometries + quadrature_point_geometries = KM.GeometriesVector() + quadrature_point_curve_on_surface_geometries = KM.GeometriesVector() + + brep_surface.CreateQuadraturePointGeometries(quadrature_point_geometries, 3) + surface = brep_surface.GetGeometryPart(KM.Geometry.BACKGROUND_GEOMETRY_INDEX) + + brep_curve_on_surface_left.CreateQuadraturePointGeometries(quadrature_point_curve_on_surface_geometries, 3) + + element_id = 1 + for i in range(0, len(quadrature_point_geometries)): + model_part.CreateNewElement('Shell6pElement', element_id, quadrature_point_geometries[i], shell_properties) + element_id += 1 + + condition_id = element_id + 1 + for i in range(0, len(quadrature_point_curve_on_surface_geometries)): + model_part.CreateNewCondition('SupportPenalty6pCondition', condition_id, quadrature_point_curve_on_surface_geometries[i], penalty_properties) + condition_id += 1 + + # add dofs + KM.VariableUtils().AddDof(KM.DISPLACEMENT_X, KM.REACTION_X, model_part) + KM.VariableUtils().AddDof(KM.DISPLACEMENT_Y, KM.REACTION_Y, model_part) + KM.VariableUtils().AddDof(KM.DISPLACEMENT_Z, KM.REACTION_Z, model_part) + KM.VariableUtils().AddDof(KM.ROTATION_X, KM.REACTION_MOMENT_X, model_part) + KM.VariableUtils().AddDof(KM.ROTATION_Y, KM.REACTION_MOMENT_Y, model_part) + KM.VariableUtils().AddDof(KM.ROTATION_Z, KM.REACTION_MOMENT_Z, model_part) + + # apply neumann conditions + prop = model_part.GetProperties()[2] + + model_part.CreateNewCondition('PointLoadCondition3D1N', 1, [3], prop) + surface[2].SetSolutionStepValue(SMA.POINT_LOAD_Z, -50) + + model_part.CreateNewCondition('PointLoadCondition3D1N', 2, [6], prop) + surface[5].SetSolutionStepValue(SMA.POINT_LOAD_Z, -100) + + model_part.CreateNewCondition('PointLoadCondition3D1N', 3, [9], prop) + surface[8].SetSolutionStepValue(SMA.POINT_LOAD_Z, -50) + + # setup solver + model_part.SetBufferSize(1) + time_scheme = KM.ResidualBasedIncrementalUpdateStaticScheme() + linear_solver = linear_solver_factory.ConstructSolver( + KM.Parameters(r'{"solver_type": "LinearSolversApplication.sparse_lu"}')) + + relative_tolerance = 1e-8 + absolute_tolerance = 1e-7 + + conv_criteria = KM.ResidualCriteria(relative_tolerance, absolute_tolerance) + conv_criteria.SetEchoLevel(0) + + maximum_iterations = iterations + compute_reactions = False + reform_dofs_at_each_iteration = False + move_mesh_flag = True + + solver = KM.ResidualBasedNewtonRaphsonStrategy( + model_part, + time_scheme, + linear_solver, + conv_criteria, + maximum_iterations, + compute_reactions, + reform_dofs_at_each_iteration, + move_mesh_flag + ) + + solver.SetEchoLevel(0) + model_part.CloneTimeStep(1) + solver.Solve() + + return brep_surface + def solve_cantilever_modal_analysis(create_geometry): model = KM.Model() model_part = model.CreateModelPart('Model') @@ -456,7 +554,113 @@ def create_geometry(model_part): # modal analysis surface, eigenvalues = Shell6pElementTests.solve_cantilever_modal_analysis(create_geometry) - self.assertAlmostEqual(eigenvalues[0], 0.677190440290159) - self.assertAlmostEqual(eigenvalues[1], 55.81155501418916) - self.assertAlmostEqual(eigenvalues[2], 116.9743177874331) - self.assertAlmostEqual(eigenvalues[3], 2274.463699330766) \ No newline at end of file + + # test nonlinear analysis with the same geometry and weak penalty support + def testCantileverOneQuadraticSpanWithWeakPenaltySupport(self): + + def CreateLinearParametricCurveOnUnitSquare(p0, p1): + knot_vector_curve = KM.Vector(2) + knot_vector_curve[0] = 0.0 + knot_vector_curve[1] = 1.0 + + degree_curve = 1 + points_curve = MakePointsList2D(p0, p1) + + return KM.NurbsCurveGeometry2DPoint( + points_curve, + degree_curve, + knot_vector_curve + ) + + def MakeBoundaryBrepCurve(surface, p0, p1, same_curve_direction=True): + curve_2d = CreateLinearParametricCurveOnUnitSquare(p0, p1) + brep_curve = KM.BrepCurveOnSurface(surface, curve_2d, same_curve_direction) + # brep_curve._curve_2d = curve_2d + return brep_curve + + def MakePointsList2D(p0, p1): + return [ + KM.Point(float(p0[0]), float(p0[1]), 0.0), + KM.Point(float(p1[0]), float(p1[1]), 0.0) + ] + + def create_geometry(model_part): + node1 = model_part.CreateNewNode(1, 0.0, 0.0, 0) + node2 = model_part.CreateNewNode(2, 2.5, 0.0, 0) + node3 = model_part.CreateNewNode(3, 5.0, 0.0, 0) + + node4 = model_part.CreateNewNode(4, 0.0, 0.5, 0) + node5 = model_part.CreateNewNode(5, 2.5, 0.5, 0) + node6 = model_part.CreateNewNode(6, 5.0, 0.5, 0) + + node7 = model_part.CreateNewNode(7, 0.0, 1.0, 0) + node8 = model_part.CreateNewNode(8, 2.5, 1.0, 0) + node9 = model_part.CreateNewNode(9, 5.0, 1.0, 0) + + nodes = KM.NodesVector() + nodes.append(node1) + nodes.append(node2) + nodes.append(node3) + nodes.append(node4) + nodes.append(node5) + nodes.append(node6) + nodes.append(node7) + nodes.append(node8) + nodes.append(node9) + + knots_u = KM.Vector(4) + knots_u[0] = 0.0 + knots_u[1] = 0.0 + knots_u[2] = 5.0 + knots_u[3] = 5.0 + + knots_v = KM.Vector(4) + knots_v[0] = 0.0 + knots_v[1] = 0.0 + knots_v[2] = 1.0 + knots_v[3] = 1.0 + + surface = KM.NurbsSurfaceGeometry3D( + nodes, 2, 2, knots_u, knots_v) + surface.SetId(1001) + + u_min = float(knots_u[0]) + u_max = float(knots_u[len(knots_u) - 1]) + v_min = float(knots_v[0]) + v_max = float(knots_v[len(knots_v) - 1]) + + curve_bottom = MakeBoundaryBrepCurve(surface, (u_min, v_min), (u_max, v_min), True) + curve_right = MakeBoundaryBrepCurve(surface, (u_max, v_min), (u_max, v_max), True) + curve_top = MakeBoundaryBrepCurve(surface, (u_max, v_max), (u_min, v_max), True) + curve_left = MakeBoundaryBrepCurve(surface, (u_min, v_max), (u_min, v_min), True) + + outer_loops = [[curve_bottom, curve_right, curve_top, curve_left]] + inner_loops = [] + + brep_surface = KM.BrepSurface(surface, outer_loops, inner_loops) + brep_surface.SetId(1002) + + brep_curve_on_surface_left = MakeBoundaryBrepCurve(surface, (u_min, v_max), (u_min, v_min), True) + brep_curve_on_surface_left.SetId(1003) + + return brep_surface, brep_curve_on_surface_left + + # nonlinear analysis + brep_surface = Shell6pElementTests.solve_cantilever_weak_support(create_geometry, 100) + surface = brep_surface.GetGeometryPart(KM.Geometry.BACKGROUND_GEOMETRY_INDEX) + + for node in surface: + self.assertAlmostEqual(node.GetValue(KM.DISPLACEMENT_X), 0) + self.assertAlmostEqual(node.GetValue(KM.DISPLACEMENT_Y), 0) + + self.assertAlmostEqual(surface[0].Z, -1.22636367511e-07) + self.assertAlmostEqual(surface[3].Z, -3.54727264976e-07) + self.assertAlmostEqual(surface[6].Z, -1.22636367510e-07) + + self.assertAlmostEqual(surface[1].Z, -0.000556853191498) + self.assertAlmostEqual(surface[4].Z, -0.000448953526144) + self.assertAlmostEqual(surface[7].Z, -0.000556853191498) + + self.assertAlmostEqual(surface[2].Z, -0.224871260111161) + self.assertAlmostEqual(surface[5].Z, -0.225043464084019) + self.assertAlmostEqual(surface[8].Z, -0.224871260111161) \ No newline at end of file From d8de8e05c96528e8c4417ed662211ec38c471b52 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Fri, 5 Jun 2026 14:06:12 +0200 Subject: [PATCH 31/50] add missing import --- applications/IgaApplication/tests/shell_6p_element_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/IgaApplication/tests/shell_6p_element_tests.py b/applications/IgaApplication/tests/shell_6p_element_tests.py index 1cee6d853110..051526ef5ea9 100644 --- a/applications/IgaApplication/tests/shell_6p_element_tests.py +++ b/applications/IgaApplication/tests/shell_6p_element_tests.py @@ -5,6 +5,7 @@ # /___/\____/_/ |_| Application import KratosMultiphysics as KM +import KratosMultiphysics.IgaApplication as IGA import KratosMultiphysics.StructuralMechanicsApplication as SMA import KratosMultiphysics.LinearSolversApplication as LinearSolversApplication import KratosMultiphysics.python_linear_solver_factory as linear_solver_factory From 6c033769d5694ac24c93d6439298b18842df1ba8 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Fri, 5 Jun 2026 14:26:52 +0200 Subject: [PATCH 32/50] add coupling penalty test --- ..._cantilever_refined_test_6p_materials.json | 29 ++++ ...r_refined_test_penalty_6p_physics.iga.json | 38 ++++++ ...ed_test_penalty_6p_project_parameters.json | 124 ++++++++++++++++++ .../IgaApplication/tests/iga_test_factory.py | 3 + .../tests/shell_6p_element_tests.py | 4 + .../tests/test_IgaApplication.py | 2 + 6 files changed, 200 insertions(+) create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_6p_materials.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_physics.iga.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_project_parameters.json diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_6p_materials.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_6p_materials.json new file mode 100644 index 000000000000..f131af747426 --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_6p_materials.json @@ -0,0 +1,29 @@ +{ + "properties": [{ + "model_part_name": "IgaModelPart.StructuralAnalysis", + "properties_id": 2, + "Material": { + "name": "LIN_ELAST_ISOTROPIC", + "material_id": 11, + "constitutive_law": { + "name": "LinearElastic3DLaw" + }, + "Variables": { + "THICKNESS": 0.1, + "YOUNG_MODULUS": 1000000, + "POISSON_RATIO": 0 + }, + "Tables": {} + } + }, { + "model_part_name": "IgaModelPart.Coupling_5", + "properties_id": 5, + "Material": { + "Variables": { + "PENALTY_FACTOR": 10000000, + "PENALTY_ROTATION_FACTOR": 20000000 + }, + "Tables": {} + } + }] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_physics.iga.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_physics.iga.json new file mode 100644 index 000000000000..6f55950a612c --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_physics.iga.json @@ -0,0 +1,38 @@ +{ + "element_condition_list": [{ + "brep_ids": [1, 2], + "geometry_type": "GeometrySurface", + "iga_model_part": "StructuralAnalysis", + "parameters": { + "type": "element", + "name": "Shell6pElement", + "shape_function_derivatives_order": 3 + } + }, { + "brep_ids": [1], + "geometry_type": "GeometrySurfaceNodes", + "iga_model_part": "Support_3", + "parameters": { + "local_parameters": [0, -1] + } + }, { + "brep_ids": [6], + "geometry_type": "SurfaceEdgeSurfaceEdge", + "iga_model_part": "Coupling_5", + "parameters": { + "type": "condition", + "name": "CouplingPenalty6pCondition", + "shape_function_derivatives_order": 2, + "variables": [] + } + }, { + "brep_ids": [3], + "geometry_type": "SurfaceEdge", + "iga_model_part": "Load_4", + "parameters": { + "type": "condition", + "name": "LoadCondition", + "shape_function_derivatives_order": 2 + } + }] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_project_parameters.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_project_parameters.json new file mode 100644 index 000000000000..d86afe9356ec --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_project_parameters.json @@ -0,0 +1,124 @@ +{ + "problem_data": { + "problem_name": "cantilever_refined_two_patch_model", + "echo_level": 0, + "parallel_type": "OpenMP", + "start_time": 0, + "end_time": 0.1 + }, + "solver_settings": { + "model_part_name": "IgaModelPart", + "domain_size": 3, + "echo_level": 0, + "buffer_size": 2, + "analysis_type": "linear", + "model_import_settings": { + "input_type": "use_input_model_part" + }, + "material_import_settings": { + "materials_filename": "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_6p_materials.json" + }, + "time_stepping": { + "time_step": 1 + }, + "rotation_dofs": true, + "reform_dofs_at_each_step": false, + "line_search": false, + "compute_reactions": true, + "block_builder": true, + "clear_storage": false, + "move_mesh_flag": true, + "convergence_criterion": "residual_criterion", + "displacement_relative_tolerance": 0.0001, + "displacement_absolute_tolerance": 1E-09, + "residual_relative_tolerance": 0.0001, + "residual_absolute_tolerance": 1E-09, + "max_iteration": 1, + "solver_type": "static", + "linear_solver_settings": { + "solver_type": "amgcl", + "max_iteration": 500, + "tolerance": 1E-09, + "scaling": false, + "verbosity": 1 + }, + "auxiliary_variables_list": [], + "auxiliary_dofs_list": [], + "auxiliary_reaction_list": [] + }, + "modelers": [{ + "modeler_name": "CadIoModeler", + "Parameters": { + "echo_level": 0, + "cad_model_part_name": "IgaModelPart", + "geometry_file_name": "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_geometry.cad.json" + } + }, { + "modeler_name": "IgaModeler", + "Parameters": { + "echo_level": 0, + "cad_model_part_name": "IgaModelPart", + "analysis_model_part_name": "IgaModelPart", + "physics_file_name": "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p_physics.iga.json" + } + }], + "processes": { + "dirichlet_process_list": [{ + "kratos_module": "KratosMultiphysics", + "python_module": "assign_vector_variable_process", + "Parameters": { + "model_part_name": "IgaModelPart.Support_3", + "variable_name": "DISPLACEMENT", + "value": [0, 0, 0], + "interval": [0, "End"] + } + }, { + "kratos_module": "KratosMultiphysics", + "python_module": "assign_vector_variable_process", + "Parameters": { + "model_part_name": "IgaModelPart.Support_3", + "variable_name": "ROTATION", + "value": [0, 0, 0], + "interval": [0, "End"] + } + }, { + "kratos_module": "IgaApplication", + "python_module": "assign_vector_variable_and_constraints_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Coupling_5", + "variable_name": "DISPLACEMENT", + "value": [0, 0, 0], + "interval": [0, "End"] + } + }, { + "kratos_module": "IgaApplication", + "python_module": "assign_vector_variable_and_constraints_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Coupling_5", + "variable_name": "ROTATION", + "value": [0, 0, 0], + "interval": [0, "End"] + } + }], + "neumann_process_list": [{ + "kratos_module": "KratosMultiphysics", + "python_module": "assign_vector_variable_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Load_4", + "variable_name": "DEAD_LOAD", + "value": [0, 0, -2], + "interval": [0, "End"] + } + }], + "json_check_process": [{ + "python_module": "from_json_check_result_process", + "kratos_module": "KratosMultiphysics", + "Parameters": { + "check_variables": ["DISPLACEMENT"], + "input_file_name": "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_result.json", + "model_part_name": "IgaModelPart.Load_4", + "time_frequency": 0.0 + } + }] + } +} diff --git a/applications/IgaApplication/tests/iga_test_factory.py b/applications/IgaApplication/tests/iga_test_factory.py index 5d6fed2dd33e..f733f8393e43 100644 --- a/applications/IgaApplication/tests/iga_test_factory.py +++ b/applications/IgaApplication/tests/iga_test_factory.py @@ -116,5 +116,8 @@ class TwoPatchCantileverCouplingPenaltyTest(IgaTestFactory): class TwoPatchCantileverRefinedCouplingPenaltyTest(IgaTestFactory): file_name = "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty" +class TwoPatchCantileverRefinedCouplingPenalty6pTest(IgaTestFactory): + file_name = "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p" + if __name__ == '__main__': KratosUnittest.main() diff --git a/applications/IgaApplication/tests/shell_6p_element_tests.py b/applications/IgaApplication/tests/shell_6p_element_tests.py index 051526ef5ea9..cc88aef98cae 100644 --- a/applications/IgaApplication/tests/shell_6p_element_tests.py +++ b/applications/IgaApplication/tests/shell_6p_element_tests.py @@ -555,6 +555,10 @@ def create_geometry(model_part): # modal analysis surface, eigenvalues = Shell6pElementTests.solve_cantilever_modal_analysis(create_geometry) + self.assertAlmostEqual(eigenvalues[0], 0.677190440290159) + self.assertAlmostEqual(eigenvalues[1], 55.81155501418916) + self.assertAlmostEqual(eigenvalues[2], 116.9743177874331) + self.assertAlmostEqual(eigenvalues[3], 2274.463699330766) # test nonlinear analysis with the same geometry and weak penalty support def testCantileverOneQuadraticSpanWithWeakPenaltySupport(self): diff --git a/applications/IgaApplication/tests/test_IgaApplication.py b/applications/IgaApplication/tests/test_IgaApplication.py index 5d3c37cc9e3e..b8185d6b42e8 100644 --- a/applications/IgaApplication/tests/test_IgaApplication.py +++ b/applications/IgaApplication/tests/test_IgaApplication.py @@ -51,6 +51,7 @@ # Rotation/G_1 coupling tests from iga_test_factory import TwoPatchCantileverCouplingPenaltyTest as TwoPatchCantileverCouplingPenaltyTest from iga_test_factory import TwoPatchCantileverRefinedCouplingPenaltyTest as TwoPatchCantileverRefinedCouplingPenaltyTest +from iga_test_factory import TwoPatchCantileverRefinedCouplingPenalty6pTest as TwoPatchCantileverRefinedCouplingPenalty6pTest # Nurbs Volume tests from test_nurbs_volume_element import TestNurbsVolumeElement as TTestNurbsVolumeElements # Modelers tests @@ -117,6 +118,7 @@ def AssembleTestSuites(): # Rotation/G_1 coupling tests TwoPatchCantileverCouplingPenaltyTest, TwoPatchCantileverRefinedCouplingPenaltyTest, + TwoPatchCantileverRefinedCouplingPenalty6pTest, # Volumes TTestNurbsVolumeElements, # Modelers From 7d17034ca8d6f8a9626f8f3841724cb092230fcd Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Fri, 5 Jun 2026 17:15:18 +0200 Subject: [PATCH 33/50] remove unused variable --- .../custom_conditions/support_penalty_6p_condition.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp index abd741de13fe..274e94ef5c64 100644 --- a/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp +++ b/applications/IgaApplication/custom_conditions/support_penalty_6p_condition.cpp @@ -33,7 +33,6 @@ namespace Kratos const auto& r_geometry = GetGeometry(); const IndexType number_of_nodes = r_geometry.size(); - const IndexType mat_size = r_geometry.WorkingSpaceDimension() * number_of_nodes * 2; const IndexType disp_size = 3 * number_of_nodes; // Integration From 262b49b0a2a3ad21e53975824ce32363bc547364 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Mon, 8 Jun 2026 15:08:35 +0200 Subject: [PATCH 34/50] add two patch scordelis test --- ...atch_scordelis_roof_test_geometry.cad.json | 504 +++++ ...o_patch_scordelis_roof_test_materials.json | 29 + ...patch_scordelis_roof_test_physics.iga.json | 47 + ...cordelis_roof_test_project_parameters.json | 125 ++ ...h_scordelis_roof_test_refinements.iga.json | 26 + .../two_patch_scordelis_roof_test_result.json | 1809 +++++++++++++++++ .../IgaApplication/tests/iga_test_factory.py | 3 + .../tests/test_IgaApplication.py | 2 + 8 files changed, 2545 insertions(+) create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_geometry.cad.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_materials.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_physics.iga.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_project_parameters.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_refinements.iga.json create mode 100644 applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_geometry.cad.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_geometry.cad.json new file mode 100644 index 000000000000..d635564f628f --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_geometry.cad.json @@ -0,0 +1,504 @@ +{ + "tolerances": { "model_tolerance": 0.001 }, + "version_number": 1, + "breps": [ + { + "brep_id": 1, + "faces": [ + { + "brep_id": 2, + "swapped_surface_normal": false, + "surface": { + "is_trimmed": true, + "is_rational": true, + "degrees": [ 2, 2 ], + "knot_vectors": [ + [ 0, 0, 0, 34.906585039886394, 34.906585039886394, 34.906585039886394 ], + [ 0, 0, 0, 25, 25, 25 ] + ], + "control_points": [ + [ + 1, + [ 0, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 2, + [ 0, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 3, + [ 0, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 4, + [ 12.500000000000004, 16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 5, + [ 12.5, -1.4492932291302077E-16, 32.635182233306786, 0.76604444311897879 ] + ], + [ + 6, + [ 12.500000000000004, -16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 7, + [ 25, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 8, + [ 24.999999999999979, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 9, + [ 25, -16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "boundary_loops": [ + { + "loop_type": "outer", + "trimming_curves": [ + { + "trim_index": 0, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 34.906585039886394, 34.906585039886394 ], + "active_range": [ 0, 34.906585039886394 ], + "control_points": [ + [ + 10, + [ 0, 0, 0, 1 ] + ], + [ + 11, + [ 34.906585039886394, 0, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 1, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 12, + [ 34.906585039886394, 0, 0, 1 ] + ], + [ + 13, + [ 34.906585039886394, 25, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 2, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 34.906585039886394, 34.906585039886394 ], + "active_range": [ 0, 34.906585039886394 ], + "control_points": [ + [ + 14, + [ 34.906585039886394, 25, 0, 1 ] + ], + [ + 15, + [ 0, 25, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 3, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 16, + [ 0, 25, 0, 1 ] + ], + [ + 17, + [ 0, 0, 0, 1 ] + ] + ] + } + } + ] + } + ], + "embedded_loops": [], + "embedded_edges": [], + "embedded_points": [] + }, + { + "brep_id": 3, + "swapped_surface_normal": false, + "surface": { + "is_trimmed": true, + "is_rational": true, + "degrees": [ 2, 2 ], + "knot_vectors": [ + [ 0, 0, 0, 34.906585039886394, 34.906585039886394, 34.906585039886394 ], + [ 0, 0, 0, 25, 25, 25 ] + ], + "control_points": [ + [ + 18, + [ 25, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 19, + [ 24.999999999999989, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 20, + [ 25, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 21, + [ 37.5, 16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 22, + [ 37.5, -1.5942225520432285E-15, 32.635182233306786, 0.76604444311897879 ] + ], + [ + 23, + [ 37.5, -16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 24, + [ 50, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 25, + [ 49.999999999999979, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 26, + [ 50, -16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "boundary_loops": [ + { + "loop_type": "outer", + "trimming_curves": [ + { + "trim_index": 4, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 34.906585039886394, 34.906585039886394 ], + "active_range": [ 0, 34.906585039886394 ], + "control_points": [ + [ + 27, + [ 0, 0, 0, 1 ] + ], + [ + 28, + [ 34.906585039886394, 0, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 5, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 29, + [ 34.906585039886394, 0, 0, 1 ] + ], + [ + 30, + [ 34.906585039886394, 25, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 6, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 34.906585039886394, 34.906585039886394 ], + "active_range": [ 0, 34.906585039886394 ], + "control_points": [ + [ + 31, + [ 34.906585039886394, 25, 0, 1 ] + ], + [ + 32, + [ 0, 25, 0, 1 ] + ] + ] + } + }, + { + "trim_index": 7, + "curve_direction": true, + "parameter_curve": { + "is_rational": false, + "degree": 1, + "knot_vector": [ 0, 0, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 33, + [ 0, 25, 0, 1 ] + ], + [ + 34, + [ 0, 0, 0, 1 ] + ] + ] + } + } + ] + } + ], + "embedded_loops": [], + "embedded_edges": [], + "embedded_points": [] + } + ], + "edges": [ + { + "brep_id": 4, + "3d_curve": { + "degree": 2, + "knot_vector": [ 0, 0, 0, 34.906585039886394, 34.906585039886394, 34.906585039886394 ], + "active_range": [ 0, 34.906585039886394 ], + "control_points": [ + [ + 35, + [ 0, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 36, + [ 0, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 37, + [ 0, -16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 2, + "trim_index": 0, + "relative_direction": true + } + ] + }, + { + "brep_id": 5, + "3d_curve": { + "degree": 2, + "knot_vector": [ 0, 0, 0, 25, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 38, + [ 0, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 39, + [ 12.500000000000004, -16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 40, + [ 25, -16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 2, + "trim_index": 1, + "relative_direction": true + } + ] + }, + { + "brep_id": 6, + "3d_curve": { + "degree": 2, + "knot_vector": [ -34.906585039886394, -34.906585039886394, -34.906585039886394, 0, 0, 0 ], + "active_range": [ -34.906585039886394, 0 ], + "control_points": [ + [ + 41, + [ 25, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 42, + [ 24.999999999999979, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 43, + [ 25, 16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 2, + "trim_index": 2, + "relative_direction": true + }, + { + "brep_id": 3, + "trim_index": 4, + "relative_direction": false + } + ] + }, + { + "brep_id": 7, + "3d_curve": { + "degree": 2, + "knot_vector": [ -25, -25, -25, 0, 0, 0 ], + "active_range": [ -25, 0 ], + "control_points": [ + [ + 44, + [ 25, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 45, + [ 12.500000000000004, 16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 46, + [ 0, 16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 2, + "trim_index": 3, + "relative_direction": true + } + ] + }, + { + "brep_id": 8, + "3d_curve": { + "degree": 2, + "knot_vector": [ 0, 0, 0, 25, 25, 25 ], + "active_range": [ 0, 25 ], + "control_points": [ + [ + 47, + [ 25, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 48, + [ 37.5, -16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 49, + [ 50, -16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 3, + "trim_index": 5, + "relative_direction": true + } + ] + }, + { + "brep_id": 9, + "3d_curve": { + "degree": 2, + "knot_vector": [ -34.906585039886394, -34.906585039886394, -34.906585039886394, 0, 0, 0 ], + "active_range": [ -34.906585039886394, 0 ], + "control_points": [ + [ + 50, + [ 50, -16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 51, + [ 49.999999999999979, -2.3188691666083323E-15, 32.635182233306807, 0.76604444311897879 ] + ], + [ + 52, + [ 50, 16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 3, + "trim_index": 6, + "relative_direction": true + } + ] + }, + { + "brep_id": 10, + "3d_curve": { + "degree": 2, + "knot_vector": [ -25, -25, -25, 0, 0, 0 ], + "active_range": [ -25, 0 ], + "control_points": [ + [ + 53, + [ 50, 16.0696902421634, 19.1511110779744, 1 ] + ], + [ + 54, + [ 37.5, 16.069690242163404, 19.151111077974413, 1 ] + ], + [ + 55, + [ 25, 16.0696902421634, 19.1511110779744, 1 ] + ] + ] + }, + "topology": [ + { + "brep_id": 3, + "trim_index": 7, + "relative_direction": true + } + ] + } + ], + "vertices": [] + } + ] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_materials.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_materials.json new file mode 100644 index 000000000000..4cf794c1f45d --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_materials.json @@ -0,0 +1,29 @@ +{ + "properties": [ + { + "model_part_name": "IgaModelPart.StructuralAnalysis_1", + "properties_id": 1, + "Material": { + "name": "Steel", + "constitutive_law": { "name": "LinearElastic3DLaw" }, + "Variables": { + "THICKNESS": 0.25, + "YOUNG_MODULUS": 432000000, + "POISSON_RATIO": 0.0 + }, + "Tables": {} + } + }, + { + "model_part_name": "IgaModelPart.Coupling_4", + "properties_id": 4, + "Material": { + "Variables": { + "PENALTY_FACTOR": 10000000000.001, + "PENALTY_ROTATION_FACTOR": 100000000000.001 + }, + "Tables": {} + } + } + ] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_physics.iga.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_physics.iga.json new file mode 100644 index 000000000000..7cb0f236748b --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_physics.iga.json @@ -0,0 +1,47 @@ +{ + "element_condition_list": [ + { + "brep_ids": [ 2, 3 ], + "geometry_type": "GeometrySurface", + "iga_model_part": "StructuralAnalysis_1", + "parameters": { + "type": "element", + "name": "Shell6pElement", + "shape_function_derivatives_order": 3 + } + }, + { + "brep_id": 2, + "geometry_type": "GeometrySurfaceNodes", + "iga_model_part": "Support_2", + "parameters": { "local_parameters": [ -1, 0 ] } + }, + { + "brep_id": 3, + "geometry_type": "GeometrySurfaceNodes", + "iga_model_part": "Support_2", + "parameters": { "local_parameters": [ -1, 1 ] } + }, + { + "brep_ids": [ 2, 3 ], + "geometry_type": "GeometrySurface", + "iga_model_part": "Load_3", + "parameters": { + "type": "condition", + "name": "LoadCondition", + "shape_function_derivatives_order": 2 + } + }, + { + "brep_ids": [ 6 ], + "geometry_type": "SurfaceEdgeSurfaceEdge", + "iga_model_part": "Coupling_4", + "parameters": { + "type": "condition", + "name": "CouplingPenalty6pCondition", + "shape_function_derivatives_order": 2, + "variables": [] + } + } + ] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_project_parameters.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_project_parameters.json new file mode 100644 index 000000000000..1e0921a75452 --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_project_parameters.json @@ -0,0 +1,125 @@ +{ + "problem_data": { + "problem_name": "two_patch_scordelis_roof_test_kratos", + "echo_level": 0, + "parallel_type": "OpenMP", + "start_time": 0, + "end_time": 0.1 + }, + "solver_settings": { + "model_part_name": "IgaModelPart", + "domain_size": 1, + "echo_level": 1, + "buffer_size": 2, + "analysis_type": "linear", + "model_import_settings": { "input_type": "use_input_model_part" }, + "material_import_settings": { "materials_filename": "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_materials.json" }, + "time_stepping": { "time_step": 1 }, + "rotation_dofs": true, + "reform_dofs_at_each_step": false, + "line_search": false, + "compute_reactions": true, + "block_builder": true, + "clear_storage": false, + "move_mesh_flag": true, + "convergence_criterion": "residual_criterion", + "displacement_relative_tolerance": 0.0001, + "displacement_absolute_tolerance": 1E-09, + "residual_relative_tolerance": 0.0001, + "residual_absolute_tolerance": 1E-09, + "max_iteration": 1, + "solver_type": "static", + "linear_solver_settings": { + "solver_type": "LinearSolversApplication.sparse_lu", + "max_iteration": 500, + "tolerance": 1E-09, + "scaling": false, + "verbosity": 1 + }, + "auxiliary_variables_list": [], + "auxiliary_dofs_list": [], + "auxiliary_reaction_list": [] + }, + "modelers": [ + { + "modeler_name": "CadIoModeler", + "Parameters": { + "echo_level": 0, + "cad_model_part_name": "IgaModelPart", + "geometry_file_name": "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_geometry.cad.json" + } + }, + { + "modeler_name": "RefinementModeler", + "Parameters": { + "echo_level": 0, + "refinements_file_name": "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_refinements.iga.json" + } + }, + { + "modeler_name": "IgaModeler", + "Parameters": { + "echo_level": 0, + "cad_model_part_name": "IgaModelPart", + "analysis_model_part_name": "IgaModelPart", + "physics_file_name": "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_physics.iga.json" + } + } + ], + "processes": { + "dirichlet_process_list": [ + { + "kratos_module": "KratosMultiphysics", + "python_module": "assign_vector_variable_process", + "Parameters": { + "model_part_name": "IgaModelPart.Support_2", + "variable_name": "DISPLACEMENT", + "value": [ null, 0, 0 ], + "interval": [ 0, "End" ] + } + }, + { + "kratos_module": "IgaApplication", + "python_module": "assign_vector_variable_and_constraints_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Coupling_4", + "variable_name": "DISPLACEMENT", + "value": [ 0, 0, 0 ], + "interval": [ 0, "End" ] + } + }, + { + "kratos_module": "IgaApplication", + "python_module": "assign_vector_variable_and_constraints_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Coupling_4", + "variable_name": "ROTATION", + "value": [ 0, 0, 0 ], + "interval": [ 0, "End" ] + } + } + ], + "neumann_process_list": [ + { + "kratos_module": "KratosMultiphysics", + "python_module": "assign_vector_variable_to_conditions_process", + "Parameters": { + "model_part_name": "IgaModelPart.Load_3", + "variable_name": "SURFACE_LOAD", + "value": [ 0, 0, -90 ], + "interval": [ 0, "End" ] + } + } + ], + "json_check_process": [{ + "python_module": "from_json_check_result_process", + "kratos_module": "KratosMultiphysics", + "Parameters": { + "check_variables": ["DISPLACEMENT"], + "input_file_name": "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json", + "model_part_name": "IgaModelPart.StructuralAnalysis_1", + "time_frequency": 0.0 + } + }] + } +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_refinements.iga.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_refinements.iga.json new file mode 100644 index 000000000000..0819cf30f897 --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_refinements.iga.json @@ -0,0 +1,26 @@ +{ + "refinements": [ + { + "brep_ids": [ 2 ], + "geometry_type": "NurbsSurface", + "model_part_name": "IgaModelPart", + "parameters": { + "insert_nb_per_span_u": 5, + "insert_nb_per_span_v": 5, + "increase_degree_u": 0, + "increase_degree_v": 0 + } + }, + { + "brep_ids": [ 3 ], + "geometry_type": "NurbsSurface", + "model_part_name": "IgaModelPart", + "parameters": { + "insert_nb_per_span_u": 7, + "insert_nb_per_span_v": 7, + "increase_degree_u": 0, + "increase_degree_v": 0 + } + } + ] +} diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json new file mode 100644 index 000000000000..bd69e43c97b4 --- /dev/null +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json @@ -0,0 +1,1809 @@ +{ + "TIME": [ + 1.0 + ], + "NODE_1": { + "DISPLACEMENT_X": [ + -0.008116772037716194 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_2": { + "DISPLACEMENT_X": [ + -0.0021428880999496964 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_3": { + "DISPLACEMENT_X": [ + 0.0011801133227186283 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_4": { + "DISPLACEMENT_X": [ + 0.001641242663353423 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_5": { + "DISPLACEMENT_X": [ + 0.0016412426633559184 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_6": { + "DISPLACEMENT_X": [ + 0.0011801133227174521 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_7": { + "DISPLACEMENT_X": [ + -0.002142888099959927 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_8": { + "DISPLACEMENT_X": [ + -0.008116772037714087 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_9": { + "DISPLACEMENT_X": [ + -0.008085622804874666 + ], + "DISPLACEMENT_Y": [ + -0.008854017755427285 + ], + "DISPLACEMENT_Z": [ + -0.018240096608291092 + ] + }, + "NODE_10": { + "DISPLACEMENT_X": [ + -0.0021646544784756547 + ], + "DISPLACEMENT_Y": [ + -0.005095505379183279 + ], + "DISPLACEMENT_Z": [ + -0.013702262287059072 + ] + }, + "NODE_11": { + "DISPLACEMENT_X": [ + 0.001185333242007246 + ], + "DISPLACEMENT_Y": [ + -0.0010335300061959348 + ], + "DISPLACEMENT_Z": [ + -0.005859974993741838 + ] + }, + "NODE_12": { + "DISPLACEMENT_X": [ + 0.001640532148351556 + ], + "DISPLACEMENT_Y": [ + 6.118059031846483e-05 + ], + "DISPLACEMENT_Z": [ + -0.0011715548205127487 + ] + }, + "NODE_13": { + "DISPLACEMENT_X": [ + 0.0016405321483539898 + ], + "DISPLACEMENT_Y": [ + -6.118059031889394e-05 + ], + "DISPLACEMENT_Z": [ + -0.0011715548205213772 + ] + }, + "NODE_14": { + "DISPLACEMENT_X": [ + 0.0011853332420062245 + ], + "DISPLACEMENT_Y": [ + 0.0010335300061949972 + ], + "DISPLACEMENT_Z": [ + -0.005859974993745694 + ] + }, + "NODE_15": { + "DISPLACEMENT_X": [ + -0.00216465447848624 + ], + "DISPLACEMENT_Y": [ + 0.005095505379164377 + ], + "DISPLACEMENT_Z": [ + -0.013702262287022106 + ] + }, + "NODE_16": { + "DISPLACEMENT_X": [ + -0.008085622804872251 + ], + "DISPLACEMENT_Y": [ + 0.008854017755378977 + ], + "DISPLACEMENT_Z": [ + -0.01824009660821716 + ] + }, + "NODE_17": { + "DISPLACEMENT_X": [ + -0.00720268520909695 + ], + "DISPLACEMENT_Y": [ + -0.02237184254982237 + ], + "DISPLACEMENT_Z": [ + -0.047946005228742844 + ] + }, + "NODE_18": { + "DISPLACEMENT_X": [ + -0.002208158529889477 + ], + "DISPLACEMENT_Y": [ + -0.012871807540322635 + ], + "DISPLACEMENT_Z": [ + -0.03641383306565895 + ] + }, + "NODE_19": { + "DISPLACEMENT_X": [ + 0.0010239444208608092 + ], + "DISPLACEMENT_Y": [ + -0.0025807864481494154 + ], + "DISPLACEMENT_Z": [ + -0.015950773405835308 + ] + }, + "NODE_20": { + "DISPLACEMENT_X": [ + 0.0015519393339176071 + ], + "DISPLACEMENT_Y": [ + 0.0001988704988381371 + ], + "DISPLACEMENT_Z": [ + -0.0034211835121474394 + ] + }, + "NODE_21": { + "DISPLACEMENT_X": [ + 0.0015519393339202068 + ], + "DISPLACEMENT_Y": [ + -0.00019887049883827852 + ], + "DISPLACEMENT_Z": [ + -0.0034211835121822427 + ] + }, + "NODE_22": { + "DISPLACEMENT_X": [ + 0.001023944420861411 + ], + "DISPLACEMENT_Y": [ + 0.002580786448151241 + ], + "DISPLACEMENT_Z": [ + -0.01595077340585867 + ] + }, + "NODE_23": { + "DISPLACEMENT_X": [ + -0.00220815852990013 + ], + "DISPLACEMENT_Y": [ + 0.012871807540246149 + ], + "DISPLACEMENT_Z": [ + -0.03641383306551688 + ] + }, + "NODE_24": { + "DISPLACEMENT_X": [ + -0.007202685209096323 + ], + "DISPLACEMENT_Y": [ + 0.022371842549641068 + ], + "DISPLACEMENT_Z": [ + -0.047946005228470985 + ] + }, + "NODE_25": { + "DISPLACEMENT_X": [ + -0.005827536494513729 + ], + "DISPLACEMENT_Y": [ + -0.031497649890623834 + ], + "DISPLACEMENT_Z": [ + -0.06941452634450976 + ] + }, + "NODE_26": { + "DISPLACEMENT_X": [ + -0.0021236185245310985 + ], + "DISPLACEMENT_Y": [ + -0.018200682222050103 + ], + "DISPLACEMENT_Z": [ + -0.05329299015630036 + ] + }, + "NODE_27": { + "DISPLACEMENT_X": [ + 0.0007329714399240684 + ], + "DISPLACEMENT_Y": [ + -0.0035999724435776454 + ], + "DISPLACEMENT_Z": [ + -0.024176001782220884 + ] + }, + "NODE_28": { + "DISPLACEMENT_X": [ + 0.0013554509318631435 + ], + "DISPLACEMENT_Y": [ + 0.00032696222290179563 + ], + "DISPLACEMENT_Z": [ + -0.005971664950788215 + ] + }, + "NODE_29": { + "DISPLACEMENT_X": [ + 0.0013554509318655754 + ], + "DISPLACEMENT_Y": [ + -0.00032696222289968605 + ], + "DISPLACEMENT_Z": [ + -0.005971664950850127 + ] + }, + "NODE_30": { + "DISPLACEMENT_X": [ + 0.0007329714399264803 + ], + "DISPLACEMENT_Y": [ + 0.0035999724435842625 + ], + "DISPLACEMENT_Z": [ + -0.024176001782271198 + ] + }, + "NODE_31": { + "DISPLACEMENT_X": [ + -0.0021236185245383874 + ], + "DISPLACEMENT_Y": [ + 0.01820068222192766 + ], + "DISPLACEMENT_Z": [ + -0.053292990156079176 + ] + }, + "NODE_32": { + "DISPLACEMENT_X": [ + -0.005827536494519831 + ], + "DISPLACEMENT_Y": [ + 0.031497649890310106 + ], + "DISPLACEMENT_Z": [ + -0.069414526344053 + ] + }, + "NODE_33": { + "DISPLACEMENT_X": [ + -0.004230233508002531 + ], + "DISPLACEMENT_Y": [ + -0.03616486507353125 + ], + "DISPLACEMENT_Z": [ + -0.0821859313506309 + ] + }, + "NODE_34": { + "DISPLACEMENT_X": [ + -0.001851859730108594 + ], + "DISPLACEMENT_Y": [ + -0.020866298004893515 + ], + "DISPLACEMENT_Z": [ + -0.06367279209436134 + ] + }, + "NODE_35": { + "DISPLACEMENT_X": [ + 0.0003761852026747771 + ], + "DISPLACEMENT_Y": [ + -0.004122745671559391 + ], + "DISPLACEMENT_Z": [ + -0.03018361189076381 + ] + }, + "NODE_36": { + "DISPLACEMENT_X": [ + 0.0010350519065680994 + ], + "DISPLACEMENT_Y": [ + 0.00040585530755534935 + ], + "DISPLACEMENT_Z": [ + -0.009037461298063007 + ] + }, + "NODE_37": { + "DISPLACEMENT_X": [ + 0.0010350519065702233 + ], + "DISPLACEMENT_Y": [ + -0.00040585530754994525 + ], + "DISPLACEMENT_Z": [ + -0.009037461298138616 + ] + }, + "NODE_38": { + "DISPLACEMENT_X": [ + 0.000376185202677934 + ], + "DISPLACEMENT_Y": [ + 0.0041227456715761815 + ], + "DISPLACEMENT_Z": [ + -0.030183611890849945 + ] + }, + "NODE_39": { + "DISPLACEMENT_X": [ + -0.0018518597301092857 + ], + "DISPLACEMENT_Y": [ + 0.020866298004777416 + ], + "DISPLACEMENT_Z": [ + -0.06367279209416704 + ] + }, + "NODE_40": { + "DISPLACEMENT_X": [ + -0.0042302335080182515 + ], + "DISPLACEMENT_Y": [ + 0.036164865073189716 + ], + "DISPLACEMENT_Z": [ + -0.0821859313501522 + ] + }, + "NODE_41": { + "DISPLACEMENT_X": [ + -0.002569952919030571 + ], + "DISPLACEMENT_Y": [ + -0.0372667991946015 + ], + "DISPLACEMENT_Z": [ + -0.08752158168887031 + ] + }, + "NODE_42": { + "DISPLACEMENT_X": [ + -0.0014286135177186538 + ], + "DISPLACEMENT_Y": [ + -0.021359480256260034 + ], + "DISPLACEMENT_Z": [ + -0.06814596048405247 + ] + }, + "NODE_43": { + "DISPLACEMENT_X": [ + 5.693246313566713e-05 + ], + "DISPLACEMENT_Y": [ + -0.00417070857064339 + ], + "DISPLACEMENT_Z": [ + -0.033801780122692145 + ] + }, + "NODE_44": { + "DISPLACEMENT_X": [ + 0.0005621654544732462 + ], + "DISPLACEMENT_Y": [ + 0.0003702823361215244 + ], + "DISPLACEMENT_Z": [ + -0.01258130568578747 + ] + }, + "NODE_45": { + "DISPLACEMENT_X": [ + 0.0005621654544761004 + ], + "DISPLACEMENT_Y": [ + -0.0003702823361122573 + ], + "DISPLACEMENT_Z": [ + -0.012581305685860817 + ] + }, + "NODE_46": { + "DISPLACEMENT_X": [ + 5.6932463137465075e-05 + ], + "DISPLACEMENT_Y": [ + 0.004170708570675286 + ], + "DISPLACEMENT_Z": [ + -0.03380178012283121 + ] + }, + "NODE_47": { + "DISPLACEMENT_X": [ + -0.001428613517715779 + ], + "DISPLACEMENT_Y": [ + 0.02135948025620389 + ], + "DISPLACEMENT_Z": [ + -0.06814596048398425 + ] + }, + "NODE_48": { + "DISPLACEMENT_X": [ + -0.0025699529190460076 + ], + "DISPLACEMENT_Y": [ + 0.03726679919437205 + ], + "DISPLACEMENT_Z": [ + -0.08752158168859056 + ] + }, + "NODE_49": { + "DISPLACEMENT_X": [ + -0.001218814352115321 + ], + "DISPLACEMENT_Y": [ + -0.03689288779182425 + ], + "DISPLACEMENT_Z": [ + -0.08846073411984402 + ] + }, + "NODE_50": { + "DISPLACEMENT_X": [ + -0.0005935537505122679 + ], + "DISPLACEMENT_Y": [ + -0.02071341172030042 + ], + "DISPLACEMENT_Z": [ + -0.06905523650616088 + ] + }, + "NODE_51": { + "DISPLACEMENT_X": [ + -0.00032655557741837285 + ], + "DISPLACEMENT_Y": [ + -0.004103559702589127 + ], + "DISPLACEMENT_Z": [ + -0.035378495366413694 + ] + }, + "NODE_52": { + "DISPLACEMENT_X": [ + -1.4473167447475577e-05 + ], + "DISPLACEMENT_Y": [ + 0.0002883993709171826 + ], + "DISPLACEMENT_Z": [ + -0.01571255665371407 + ] + }, + "NODE_53": { + "DISPLACEMENT_X": [ + -1.4473167445211109e-05 + ], + "DISPLACEMENT_Y": [ + -0.00028839937089975476 + ], + "DISPLACEMENT_Z": [ + -0.01571255665382775 + ] + }, + "NODE_54": { + "DISPLACEMENT_X": [ + -0.00032655557741693997 + ], + "DISPLACEMENT_Y": [ + 0.004103559702622363 + ], + "DISPLACEMENT_Z": [ + -0.03537849536656052 + ] + }, + "NODE_55": { + "DISPLACEMENT_X": [ + -0.00059355375051768 + ], + "DISPLACEMENT_Y": [ + 0.020713411720281554 + ], + "DISPLACEMENT_Z": [ + -0.06905523650617496 + ] + }, + "NODE_56": { + "DISPLACEMENT_X": [ + -0.0012188143521117615 + ], + "DISPLACEMENT_Y": [ + 0.03689288779164805 + ], + "DISPLACEMENT_Z": [ + -0.08846073411964829 + ] + }, + "NODE_57": { + "DISPLACEMENT_X": [ + -0.0004854943968198135 + ], + "DISPLACEMENT_Y": [ + -0.036548922710051154 + ], + "DISPLACEMENT_Z": [ + -0.0892130253147277 + ] + }, + "NODE_58": { + "DISPLACEMENT_X": [ + -0.0003334991859421141 + ], + "DISPLACEMENT_Y": [ + -0.021033908931736976 + ], + "DISPLACEMENT_Z": [ + -0.06888267510664144 + ] + }, + "NODE_59": { + "DISPLACEMENT_X": [ + -0.00031985651756040933 + ], + "DISPLACEMENT_Y": [ + -0.004417581337323782 + ], + "DISPLACEMENT_Z": [ + -0.03555164488678266 + ] + }, + "NODE_60": { + "DISPLACEMENT_X": [ + -0.00041363532500377127 + ], + "DISPLACEMENT_Y": [ + 0.0009085279349960485 + ], + "DISPLACEMENT_Z": [ + -0.015887522198681267 + ] + }, + "NODE_61": { + "DISPLACEMENT_X": [ + -0.00041363532500281837 + ], + "DISPLACEMENT_Y": [ + -0.0009085279349725742 + ], + "DISPLACEMENT_Z": [ + -0.01588752219881185 + ] + }, + "NODE_62": { + "DISPLACEMENT_X": [ + -0.0003198565175620334 + ], + "DISPLACEMENT_Y": [ + 0.004417581337348813 + ], + "DISPLACEMENT_Z": [ + -0.03555164488691727 + ] + }, + "NODE_63": { + "DISPLACEMENT_X": [ + -0.0003334991859441039 + ], + "DISPLACEMENT_Y": [ + 0.021033908931644266 + ], + "DISPLACEMENT_Z": [ + -0.06888267510652923 + ] + }, + "NODE_64": { + "DISPLACEMENT_X": [ + -0.00048549439681403557 + ], + "DISPLACEMENT_Y": [ + 0.03654892270978166 + ], + "DISPLACEMENT_Z": [ + -0.08921302531437882 + ] + }, + "NODE_65": { + "DISPLACEMENT_X": [ + -0.0004823555319962405 + ], + "DISPLACEMENT_Y": [ + -0.03659061101189537 + ], + "DISPLACEMENT_Z": [ + -0.0891835694615852 + ] + }, + "NODE_66": { + "DISPLACEMENT_X": [ + -0.0003681929870192589 + ], + "DISPLACEMENT_Y": [ + -0.02493750420102757 + ], + "DISPLACEMENT_Z": [ + -0.0741829722973834 + ] + }, + "NODE_67": { + "DISPLACEMENT_X": [ + -0.00031115092234206216 + ], + "DISPLACEMENT_Y": [ + -0.009946325541871772 + ], + "DISPLACEMENT_Z": [ + -0.04763490357641317 + ] + }, + "NODE_68": { + "DISPLACEMENT_X": [ + -0.0003556075296829162 + ], + "DISPLACEMENT_Y": [ + -0.0018487029198830415 + ], + "DISPLACEMENT_Z": [ + -0.02716215740745041 + ] + }, + "NODE_69": { + "DISPLACEMENT_X": [ + -0.00041698533408145025 + ], + "DISPLACEMENT_Y": [ + 0.0006037632281914193 + ], + "DISPLACEMENT_Z": [ + -0.015872185397511188 + ] + }, + "NODE_70": { + "DISPLACEMENT_X": [ + -0.00041698533408069673 + ], + "DISPLACEMENT_Y": [ + -0.0006037632281686357 + ], + "DISPLACEMENT_Z": [ + -0.015872185397608894 + ] + }, + "NODE_71": { + "DISPLACEMENT_X": [ + -0.0003556075296834513 + ], + "DISPLACEMENT_Y": [ + 0.0018487029199106774 + ], + "DISPLACEMENT_Z": [ + -0.027162157407599846 + ] + }, + "NODE_72": { + "DISPLACEMENT_X": [ + -0.0003111509223443279 + ], + "DISPLACEMENT_Y": [ + 0.009946325541863347 + ], + "DISPLACEMENT_Z": [ + -0.04763490357646855 + ] + }, + "NODE_73": { + "DISPLACEMENT_X": [ + -0.0003681929870195622 + ], + "DISPLACEMENT_Y": [ + 0.02493750420089175 + ], + "DISPLACEMENT_Z": [ + -0.07418297229721052 + ] + }, + "NODE_74": { + "DISPLACEMENT_X": [ + -0.0004823555319903019 + ], + "DISPLACEMENT_Y": [ + 0.03659061101162481 + ], + "DISPLACEMENT_Z": [ + -0.08918356946123618 + ] + }, + "NODE_75": { + "DISPLACEMENT_X": [ + 6.45774088501195e-05 + ], + "DISPLACEMENT_Y": [ + -0.037253380187917844 + ], + "DISPLACEMENT_Z": [ + -0.0892826007435178 + ] + }, + "NODE_76": { + "DISPLACEMENT_X": [ + -0.0001005705379135903 + ], + "DISPLACEMENT_Y": [ + -0.025099927037616848 + ], + "DISPLACEMENT_Z": [ + -0.07481802096467259 + ] + }, + "NODE_77": { + "DISPLACEMENT_X": [ + -0.00023694489680404964 + ], + "DISPLACEMENT_Y": [ + -0.009782781533454913 + ], + "DISPLACEMENT_Z": [ + -0.04795349443115524 + ] + }, + "NODE_78": { + "DISPLACEMENT_X": [ + -0.00044240261329474024 + ], + "DISPLACEMENT_Y": [ + -0.0019255078332263292 + ], + "DISPLACEMENT_Z": [ + -0.02703617437352415 + ] + }, + "NODE_79": { + "DISPLACEMENT_X": [ + -0.0007363099533286849 + ], + "DISPLACEMENT_Y": [ + 0.00012106843550697891 + ], + "DISPLACEMENT_Z": [ + -0.015732732521809987 + ] + }, + "NODE_80": { + "DISPLACEMENT_X": [ + -0.0007363099533298651 + ], + "DISPLACEMENT_Y": [ + -0.00012106843548830652 + ], + "DISPLACEMENT_Z": [ + -0.015732732521911433 + ] + }, + "NODE_81": { + "DISPLACEMENT_X": [ + -0.00044240261329701864 + ], + "DISPLACEMENT_Y": [ + 0.001925507833256333 + ], + "DISPLACEMENT_Z": [ + -0.02703617437368092 + ] + }, + "NODE_82": { + "DISPLACEMENT_X": [ + -0.00023694489680568356 + ], + "DISPLACEMENT_Y": [ + 0.009782781533435843 + ], + "DISPLACEMENT_Z": [ + -0.04795349443118047 + ] + }, + "NODE_83": { + "DISPLACEMENT_X": [ + -0.00010057053791226636 + ], + "DISPLACEMENT_Y": [ + 0.02509992703743435 + ], + "DISPLACEMENT_Z": [ + -0.07481802096441242 + ] + }, + "NODE_84": { + "DISPLACEMENT_X": [ + 6.457740885659813e-05 + ], + "DISPLACEMENT_Y": [ + 0.0372533801875721 + ], + "DISPLACEMENT_Z": [ + -0.08928260074306249 + ] + }, + "NODE_85": { + "DISPLACEMENT_X": [ + 0.0009828767575108233 + ], + "DISPLACEMENT_Y": [ + -0.03923729956120669 + ], + "DISPLACEMENT_Z": [ + -0.09168332045512873 + ] + }, + "NODE_86": { + "DISPLACEMENT_X": [ + 0.0007193466914709632 + ], + "DISPLACEMENT_Y": [ + -0.02701064614562444 + ], + "DISPLACEMENT_Z": [ + -0.0769429537267166 + ] + }, + "NODE_87": { + "DISPLACEMENT_X": [ + -0.00021986772602733157 + ], + "DISPLACEMENT_Y": [ + -0.010398195043250508 + ], + "DISPLACEMENT_Z": [ + -0.04851144355062453 + ] + }, + "NODE_88": { + "DISPLACEMENT_X": [ + -0.0008060737449922464 + ], + "DISPLACEMENT_Y": [ + -0.0019715402161442955 + ], + "DISPLACEMENT_Z": [ + -0.025420498207214263 + ] + }, + "NODE_89": { + "DISPLACEMENT_X": [ + -0.0011865933431016108 + ], + "DISPLACEMENT_Y": [ + 0.0001266572702399986 + ], + "DISPLACEMENT_Z": [ + -0.012752056911685844 + ] + }, + "NODE_90": { + "DISPLACEMENT_X": [ + -0.0011865933431039436 + ], + "DISPLACEMENT_Y": [ + -0.0001266572702263008 + ], + "DISPLACEMENT_Z": [ + -0.012752056911763633 + ] + }, + "NODE_91": { + "DISPLACEMENT_X": [ + -0.0008060737449955535 + ], + "DISPLACEMENT_Y": [ + 0.0019715402161768814 + ], + "DISPLACEMENT_Z": [ + -0.025420498207374288 + ] + }, + "NODE_92": { + "DISPLACEMENT_X": [ + -0.00021986772602715382 + ], + "DISPLACEMENT_Y": [ + 0.010398195043250057 + ], + "DISPLACEMENT_Z": [ + -0.04851144355067707 + ] + }, + "NODE_93": { + "DISPLACEMENT_X": [ + 0.0007193466914764108 + ], + "DISPLACEMENT_Y": [ + 0.027010646145469337 + ], + "DISPLACEMENT_Z": [ + -0.07694295372649712 + ] + }, + "NODE_94": { + "DISPLACEMENT_X": [ + 0.0009828767575121332 + ], + "DISPLACEMENT_Y": [ + 0.039237299560867654 + ], + "DISPLACEMENT_Z": [ + -0.09168332045467985 + ] + }, + "NODE_95": { + "DISPLACEMENT_X": [ + 0.0022443622706479 + ], + "DISPLACEMENT_Y": [ + -0.04082855640295997 + ], + "DISPLACEMENT_Z": [ + -0.09236055629048387 + ] + }, + "NODE_96": { + "DISPLACEMENT_X": [ + 0.0012973390878004414 + ], + "DISPLACEMENT_Y": [ + -0.028246659541956896 + ], + "DISPLACEMENT_Z": [ + -0.07726842247336672 + ] + }, + "NODE_97": { + "DISPLACEMENT_X": [ + -0.00025991755467178005 + ], + "DISPLACEMENT_Y": [ + -0.011027835960445407 + ], + "DISPLACEMENT_Z": [ + -0.047761436548873104 + ] + }, + "NODE_98": { + "DISPLACEMENT_X": [ + -0.0011513629363123278 + ], + "DISPLACEMENT_Y": [ + -0.0020371669874400243 + ], + "DISPLACEMENT_Z": [ + -0.023264794325667398 + ] + }, + "NODE_99": { + "DISPLACEMENT_X": [ + -0.001554082263243393 + ], + "DISPLACEMENT_Y": [ + 0.00018087809204491586 + ], + "DISPLACEMENT_Z": [ + -0.009331460599411815 + ] + }, + "NODE_100": { + "DISPLACEMENT_X": [ + -0.0015540822632457727 + ], + "DISPLACEMENT_Y": [ + -0.00018087809203410146 + ], + "DISPLACEMENT_Z": [ + -0.009331460599472843 + ] + }, + "NODE_101": { + "DISPLACEMENT_X": [ + -0.0011513629363161864 + ], + "DISPLACEMENT_Y": [ + 0.0020371669874662685 + ], + "DISPLACEMENT_Z": [ + -0.02326479432579623 + ] + }, + "NODE_102": { + "DISPLACEMENT_X": [ + -0.00025991755467113473 + ], + "DISPLACEMENT_Y": [ + 0.011027835960454199 + ], + "DISPLACEMENT_Z": [ + -0.047761436548938496 + ] + }, + "NODE_103": { + "DISPLACEMENT_X": [ + 0.0012973390878074627 + ], + "DISPLACEMENT_Y": [ + 0.028246659541843397 + ], + "DISPLACEMENT_Z": [ + -0.07726842247321036 + ] + }, + "NODE_104": { + "DISPLACEMENT_X": [ + 0.0022443622706490836 + ], + "DISPLACEMENT_Y": [ + 0.04082855640271015 + ], + "DISPLACEMENT_Z": [ + -0.092360556290163 + ] + }, + "NODE_105": { + "DISPLACEMENT_X": [ + 0.00360233936293459 + ], + "DISPLACEMENT_Y": [ + -0.040277087083103076 + ], + "DISPLACEMENT_Z": [ + -0.08856479078036833 + ] + }, + "NODE_106": { + "DISPLACEMENT_X": [ + 0.0017980722978526461 + ], + "DISPLACEMENT_Y": [ + -0.02795066678405187 + ], + "DISPLACEMENT_Z": [ + -0.0737549685874008 + ] + }, + "NODE_107": { + "DISPLACEMENT_X": [ + -0.0004108120618114765 + ], + "DISPLACEMENT_Y": [ + -0.010968146231761927 + ], + "DISPLACEMENT_Z": [ + -0.04471088467232497 + ] + }, + "NODE_108": { + "DISPLACEMENT_X": [ + -0.0014613355077872842 + ], + "DISPLACEMENT_Y": [ + -0.0020479517194150173 + ], + "DISPLACEMENT_Z": [ + -0.02044317288251172 + ] + }, + "NODE_109": { + "DISPLACEMENT_X": [ + -0.0018316441219689958 + ], + "DISPLACEMENT_Y": [ + 0.00018604849216430125 + ], + "DISPLACEMENT_Z": [ + -0.006529425530141734 + ] + }, + "NODE_110": { + "DISPLACEMENT_X": [ + -0.0018316441219713158 + ], + "DISPLACEMENT_Y": [ + -0.00018604849215661182 + ], + "DISPLACEMENT_Z": [ + -0.006529425530186752 + ] + }, + "NODE_111": { + "DISPLACEMENT_X": [ + -0.0014613355077910837 + ], + "DISPLACEMENT_Y": [ + 0.002047951719433884 + ], + "DISPLACEMENT_Z": [ + -0.020443172882605904 + ] + }, + "NODE_112": { + "DISPLACEMENT_X": [ + -0.0004108120618106516 + ], + "DISPLACEMENT_Y": [ + 0.010968146231766307 + ], + "DISPLACEMENT_Z": [ + -0.044710884672370235 + ] + }, + "NODE_113": { + "DISPLACEMENT_X": [ + 0.0017980722978597837 + ], + "DISPLACEMENT_Y": [ + 0.02795066678397601 + ], + "DISPLACEMENT_Z": [ + -0.0737549685873042 + ] + }, + "NODE_114": { + "DISPLACEMENT_X": [ + 0.0036023393629377597 + ], + "DISPLACEMENT_Y": [ + 0.04027708708294993 + ], + "DISPLACEMENT_Z": [ + -0.08856479078017727 + ] + }, + "NODE_115": { + "DISPLACEMENT_X": [ + 0.004945541704605817 + ], + "DISPLACEMENT_Y": [ + -0.036748347298742684 + ], + "DISPLACEMENT_Z": [ + -0.07894003870553848 + ] + }, + "NODE_116": { + "DISPLACEMENT_X": [ + 0.002198591238685082 + ], + "DISPLACEMENT_Y": [ + -0.02551283358985804 + ], + "DISPLACEMENT_Z": [ + -0.06545035377933446 + ] + }, + "NODE_117": { + "DISPLACEMENT_X": [ + -0.0006128423039718125 + ], + "DISPLACEMENT_Y": [ + -0.010007879548693581 + ], + "DISPLACEMENT_Z": [ + -0.038923011095897395 + ] + }, + "NODE_118": { + "DISPLACEMENT_X": [ + -0.0017342624259731884 + ], + "DISPLACEMENT_Y": [ + -0.0018769137195942776 + ], + "DISPLACEMENT_Z": [ + -0.016851048784274864 + ] + }, + "NODE_119": { + "DISPLACEMENT_X": [ + -0.0020297546922030917 + ], + "DISPLACEMENT_Y": [ + 0.00015379521847464506 + ], + "DISPLACEMENT_Z": [ + -0.004320925500573621 + ] + }, + "NODE_120": { + "DISPLACEMENT_X": [ + -0.0020297546922052167 + ], + "DISPLACEMENT_Y": [ + -0.00015379521846958333 + ], + "DISPLACEMENT_Z": [ + -0.004320925500605245 + ] + }, + "NODE_121": { + "DISPLACEMENT_X": [ + -0.0017342624259766494 + ], + "DISPLACEMENT_Y": [ + 0.0018769137196064049 + ], + "DISPLACEMENT_Z": [ + -0.01685104878433799 + ] + }, + "NODE_122": { + "DISPLACEMENT_X": [ + -0.0006128423039708445 + ], + "DISPLACEMENT_Y": [ + 0.010007879548694644 + ], + "DISPLACEMENT_Z": [ + -0.03892301109592696 + ] + }, + "NODE_123": { + "DISPLACEMENT_X": [ + 0.0021985912386919344 + ], + "DISPLACEMENT_Y": [ + 0.025512833589812184 + ], + "DISPLACEMENT_Z": [ + -0.06545035377928154 + ] + }, + "NODE_124": { + "DISPLACEMENT_X": [ + 0.0049455417046107494 + ], + "DISPLACEMENT_Y": [ + 0.036748347298650536 + ], + "DISPLACEMENT_Z": [ + -0.0789400387054294 + ] + }, + "NODE_125": { + "DISPLACEMENT_X": [ + 0.006145280851604458 + ], + "DISPLACEMENT_Y": [ + -0.029987034278762592 + ], + "DISPLACEMENT_Z": [ + -0.06317148315572249 + ] + }, + "NODE_126": { + "DISPLACEMENT_X": [ + 0.002503898951855521 + ], + "DISPLACEMENT_Y": [ + -0.020789288618385544 + ], + "DISPLACEMENT_Z": [ + -0.05212367432340285 + ] + }, + "NODE_127": { + "DISPLACEMENT_X": [ + -0.0008289882901826383 + ], + "DISPLACEMENT_Y": [ + -0.008127629748569972 + ], + "DISPLACEMENT_Z": [ + -0.03047707876127639 + ] + }, + "NODE_128": { + "DISPLACEMENT_X": [ + -0.0019558585351573798 + ], + "DISPLACEMENT_Y": [ + -0.0015367566443589536 + ], + "DISPLACEMENT_Z": [ + -0.012641717978498102 + ] + }, + "NODE_129": { + "DISPLACEMENT_X": [ + -0.0021617296409131236 + ], + "DISPLACEMENT_Y": [ + 0.00010928529228736657 + ], + "DISPLACEMENT_Z": [ + -0.002650154145303281 + ] + }, + "NODE_130": { + "DISPLACEMENT_X": [ + -0.002161729640915036 + ], + "DISPLACEMENT_Y": [ + -0.00010928529228436821 + ], + "DISPLACEMENT_Z": [ + -0.0026501541453229907 + ] + }, + "NODE_131": { + "DISPLACEMENT_X": [ + -0.001955858535160405 + ], + "DISPLACEMENT_Y": [ + 0.001536756644366348 + ], + "DISPLACEMENT_Z": [ + -0.012641717978538409 + ] + }, + "NODE_132": { + "DISPLACEMENT_X": [ + -0.0008289882901815646 + ], + "DISPLACEMENT_Y": [ + 0.00812762974857193 + ], + "DISPLACEMENT_Z": [ + -0.030477078761299303 + ] + }, + "NODE_133": { + "DISPLACEMENT_X": [ + 0.002503898951861967 + ], + "DISPLACEMENT_Y": [ + 0.020789288618358777 + ], + "DISPLACEMENT_Z": [ + -0.05212367432337524 + ] + }, + "NODE_134": { + "DISPLACEMENT_X": [ + 0.0061452808516107614 + ], + "DISPLACEMENT_Y": [ + 0.029987034278707553 + ], + "DISPLACEMENT_Z": [ + -0.06317148315566048 + ] + }, + "NODE_135": { + "DISPLACEMENT_X": [ + 0.007097642102820181 + ], + "DISPLACEMENT_Y": [ + -0.020098889898041466 + ], + "DISPLACEMENT_Z": [ + -0.04160190579002582 + ] + }, + "NODE_136": { + "DISPLACEMENT_X": [ + 0.0026912910296609358 + ], + "DISPLACEMENT_Y": [ + -0.013913210937292284 + ], + "DISPLACEMENT_Z": [ + -0.03416565743458193 + ] + }, + "NODE_137": { + "DISPLACEMENT_X": [ + -0.001012357842683538 + ], + "DISPLACEMENT_Y": [ + -0.005432874811099291 + ], + "DISPLACEMENT_Z": [ + -0.019714997195087326 + ] + }, + "NODE_138": { + "DISPLACEMENT_X": [ + -0.0021130598319754807 + ], + "DISPLACEMENT_Y": [ + -0.0010495036888845187 + ], + "DISPLACEMENT_Z": [ + -0.007980526258859354 + ] + }, + "NODE_139": { + "DISPLACEMENT_X": [ + -0.0022393002552472856 + ], + "DISPLACEMENT_Y": [ + 5.3406317800048874e-05 + ], + "DISPLACEMENT_Z": [ + -0.001500014843291177 + ] + }, + "NODE_140": { + "DISPLACEMENT_X": [ + -0.00223930025524899 + ], + "DISPLACEMENT_Y": [ + -5.340631779849761e-05 + ], + "DISPLACEMENT_Z": [ + -0.001500014843301839 + ] + }, + "NODE_141": { + "DISPLACEMENT_X": [ + -0.002113059831978118 + ], + "DISPLACEMENT_Y": [ + 0.001049503688888832 + ], + "DISPLACEMENT_Z": [ + -0.007980526258882894 + ] + }, + "NODE_142": { + "DISPLACEMENT_X": [ + -0.0010123578426825147 + ], + "DISPLACEMENT_Y": [ + 0.005432874811101227 + ], + "DISPLACEMENT_Z": [ + -0.019714997195102495 + ] + }, + "NODE_143": { + "DISPLACEMENT_X": [ + 0.0026912910296672567 + ], + "DISPLACEMENT_Y": [ + 0.013913210937278599 + ], + "DISPLACEMENT_Z": [ + -0.03416565743456935 + ] + }, + "NODE_144": { + "DISPLACEMENT_X": [ + 0.007097642102827238 + ], + "DISPLACEMENT_Y": [ + 0.020098889898012583 + ], + "DISPLACEMENT_Z": [ + -0.04160190578999486 + ] + }, + "NODE_145": { + "DISPLACEMENT_X": [ + 0.007671515202057538 + ], + "DISPLACEMENT_Y": [ + -0.0074866724398142325 + ], + "DISPLACEMENT_Z": [ + -0.015106913304797723 + ] + }, + "NODE_146": { + "DISPLACEMENT_X": [ + 0.002752861548917303 + ], + "DISPLACEMENT_Y": [ + -0.00518960525367837 + ], + "DISPLACEMENT_Z": [ + -0.012356457380181055 + ] + }, + "NODE_147": { + "DISPLACEMENT_X": [ + -0.0011153834313549372 + ], + "DISPLACEMENT_Y": [ + -0.002024330734097124 + ], + "DISPLACEMENT_Z": [ + -0.007072769843467417 + ] + }, + "NODE_148": { + "DISPLACEMENT_X": [ + -0.0021948103635887344 + ], + "DISPLACEMENT_Y": [ + -0.0004053052808978637 + ], + "DISPLACEMENT_Z": [ + -0.002854624213084006 + ] + }, + "NODE_149": { + "DISPLACEMENT_X": [ + -0.0022737601845310047 + ], + "DISPLACEMENT_Y": [ + 7.869739873405007e-06 + ], + "DISPLACEMENT_Z": [ + -0.0005668328486710144 + ] + }, + "NODE_150": { + "DISPLACEMENT_X": [ + -0.002273760184532569 + ], + "DISPLACEMENT_Y": [ + -7.869739872896521e-06 + ], + "DISPLACEMENT_Z": [ + -0.0005668328486748065 + ] + }, + "NODE_151": { + "DISPLACEMENT_X": [ + -0.002194810363591205 + ], + "DISPLACEMENT_Y": [ + 0.00040530528089933326 + ], + "DISPLACEMENT_Z": [ + -0.002854624213091874 + ] + }, + "NODE_152": { + "DISPLACEMENT_X": [ + -0.0011153834313539256 + ], + "DISPLACEMENT_Y": [ + 0.002024330734097839 + ], + "DISPLACEMENT_Z": [ + -0.007072769843472577 + ] + }, + "NODE_153": { + "DISPLACEMENT_X": [ + 0.00275286154892349 + ], + "DISPLACEMENT_Y": [ + 0.0051896052536745734 + ], + "DISPLACEMENT_Z": [ + -0.01235645738017814 + ] + }, + "NODE_154": { + "DISPLACEMENT_X": [ + 0.007671515202065031 + ], + "DISPLACEMENT_Y": [ + 0.007486672439806044 + ], + "DISPLACEMENT_Z": [ + -0.015106913304789412 + ] + }, + "NODE_155": { + "DISPLACEMENT_X": [ + 0.0076869317894150595 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_156": { + "DISPLACEMENT_X": [ + 0.0027431174027037447 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_157": { + "DISPLACEMENT_X": [ + -0.001113298080290252 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_158": { + "DISPLACEMENT_X": [ + -0.0021957157039287937 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_159": { + "DISPLACEMENT_X": [ + -0.0022733047907345224 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_160": { + "DISPLACEMENT_X": [ + -0.0022733047907360963 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_161": { + "DISPLACEMENT_X": [ + -0.0021957157039312527 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_162": { + "DISPLACEMENT_X": [ + -0.0011132980802892407 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_163": { + "DISPLACEMENT_X": [ + 0.0027431174027099377 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + }, + "NODE_164": { + "DISPLACEMENT_X": [ + 0.007686931789422528 + ], + "DISPLACEMENT_Y": [ + 0.0 + ], + "DISPLACEMENT_Z": [ + 0.0 + ] + } +} \ No newline at end of file diff --git a/applications/IgaApplication/tests/iga_test_factory.py b/applications/IgaApplication/tests/iga_test_factory.py index f733f8393e43..c5f34703a342 100644 --- a/applications/IgaApplication/tests/iga_test_factory.py +++ b/applications/IgaApplication/tests/iga_test_factory.py @@ -119,5 +119,8 @@ class TwoPatchCantileverRefinedCouplingPenaltyTest(IgaTestFactory): class TwoPatchCantileverRefinedCouplingPenalty6pTest(IgaTestFactory): file_name = "coupling_condition_tests/two_patch_cantilever_refined_test/two_patch_cantilever_refined_test_penalty_6p" +class TwoPatchScordelisRoofTest(IgaTestFactory): + file_name = "coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test" + if __name__ == '__main__': KratosUnittest.main() diff --git a/applications/IgaApplication/tests/test_IgaApplication.py b/applications/IgaApplication/tests/test_IgaApplication.py index b8185d6b42e8..8e5e2affe6af 100644 --- a/applications/IgaApplication/tests/test_IgaApplication.py +++ b/applications/IgaApplication/tests/test_IgaApplication.py @@ -52,6 +52,7 @@ from iga_test_factory import TwoPatchCantileverCouplingPenaltyTest as TwoPatchCantileverCouplingPenaltyTest from iga_test_factory import TwoPatchCantileverRefinedCouplingPenaltyTest as TwoPatchCantileverRefinedCouplingPenaltyTest from iga_test_factory import TwoPatchCantileverRefinedCouplingPenalty6pTest as TwoPatchCantileverRefinedCouplingPenalty6pTest +from iga_test_factory import TwoPatchScordelisRoofTest as TwoPatchScordelisRoofTest # Nurbs Volume tests from test_nurbs_volume_element import TestNurbsVolumeElement as TTestNurbsVolumeElements # Modelers tests @@ -119,6 +120,7 @@ def AssembleTestSuites(): TwoPatchCantileverCouplingPenaltyTest, TwoPatchCantileverRefinedCouplingPenaltyTest, TwoPatchCantileverRefinedCouplingPenalty6pTest, + TwoPatchScordelisRoofTest, # Volumes TTestNurbsVolumeElements, # Modelers From 09cb4872f6c99eab00f5e6fb67669a9481d1fea3 Mon Sep 17 00:00:00 2001 From: Ricky Aristio Date: Mon, 8 Jun 2026 15:50:00 +0200 Subject: [PATCH 35/50] fix small bug in the test result --- .../two_patch_scordelis_roof_test_result.json | 912 +++++++++--------- 1 file changed, 456 insertions(+), 456 deletions(-) diff --git a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json index bd69e43c97b4..452a433f0a87 100644 --- a/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json +++ b/applications/IgaApplication/tests/coupling_condition_tests/two_patch_scordelis_roof_test/two_patch_scordelis_roof_test_result.json @@ -4,7 +4,7 @@ ], "NODE_1": { "DISPLACEMENT_X": [ - -0.008116772037716194 + -0.007071768671534784 ], "DISPLACEMENT_Y": [ 0.0 @@ -15,7 +15,7 @@ }, "NODE_2": { "DISPLACEMENT_X": [ - -0.0021428880999496964 + -0.0010978847336636456 ], "DISPLACEMENT_Y": [ 0.0 @@ -26,7 +26,7 @@ }, "NODE_3": { "DISPLACEMENT_X": [ - 0.0011801133227186283 + 0.0022251166890668935 ], "DISPLACEMENT_Y": [ 0.0 @@ -37,7 +37,7 @@ }, "NODE_4": { "DISPLACEMENT_X": [ - 0.001641242663353423 + 0.0026862460296680954 ], "DISPLACEMENT_Y": [ 0.0 @@ -48,7 +48,7 @@ }, "NODE_5": { "DISPLACEMENT_X": [ - 0.0016412426633559184 + 0.002686246029590859 ], "DISPLACEMENT_Y": [ 0.0 @@ -59,7 +59,7 @@ }, "NODE_6": { "DISPLACEMENT_X": [ - 0.0011801133227174521 + 0.0022251166889089183 ], "DISPLACEMENT_Y": [ 0.0 @@ -70,7 +70,7 @@ }, "NODE_7": { "DISPLACEMENT_X": [ - -0.002142888099959927 + -0.0010978847336585377 ], "DISPLACEMENT_Y": [ 0.0 @@ -81,7 +81,7 @@ }, "NODE_8": { "DISPLACEMENT_X": [ - -0.008116772037714087 + -0.0070717686712168035 ], "DISPLACEMENT_Y": [ 0.0 @@ -92,1613 +92,1613 @@ }, "NODE_9": { "DISPLACEMENT_X": [ - -0.008085622804874666 + -0.00704061943869317 ], "DISPLACEMENT_Y": [ - -0.008854017755427285 + -0.008854017755537414 ], "DISPLACEMENT_Z": [ - -0.018240096608291092 + -0.01824009660854945 ] }, "NODE_10": { "DISPLACEMENT_X": [ - -0.0021646544784756547 + -0.0011196511121896286 ], "DISPLACEMENT_Y": [ - -0.005095505379183279 + -0.0050955053792755434 ], "DISPLACEMENT_Z": [ - -0.013702262287059072 + -0.013702262287296438 ] }, "NODE_11": { "DISPLACEMENT_X": [ - 0.001185333242007246 + 0.002230336608355489 ], "DISPLACEMENT_Y": [ - -0.0010335300061959348 + -0.0010335300062537598 ], "DISPLACEMENT_Z": [ - -0.005859974993741838 + -0.00585997499391544 ] }, "NODE_12": { "DISPLACEMENT_X": [ - 0.001640532148351556 + 0.0026855355146662265 ], "DISPLACEMENT_Y": [ - 6.118059031846483e-05 + 6.118059028776162e-05 ], "DISPLACEMENT_Z": [ - -0.0011715548205127487 + -0.0011715548205850678 ] }, "NODE_13": { "DISPLACEMENT_X": [ - 0.0016405321483539898 + 0.0026855355145889524 ], "DISPLACEMENT_Y": [ - -6.118059031889394e-05 + -6.11805903483527e-05 ], "DISPLACEMENT_Z": [ - -0.0011715548205213772 + -0.0011715548204507134 ] }, "NODE_14": { "DISPLACEMENT_X": [ - 0.0011853332420062245 + 0.0022303366081976774 ], "DISPLACEMENT_Y": [ - 0.0010335300061949972 + 0.0010335300061232195 ], "DISPLACEMENT_Z": [ - -0.005859974993745694 + -0.005859974993498447 ] }, "NODE_15": { "DISPLACEMENT_X": [ - -0.00216465447848624 + -0.0011196511121848171 ], "DISPLACEMENT_Y": [ - 0.005095505379164377 + 0.005095505378996805 ], "DISPLACEMENT_Z": [ - -0.013702262287022106 + -0.01370226228658637 ] }, "NODE_16": { "DISPLACEMENT_X": [ - -0.008085622804872251 + -0.007040619438375023 ], "DISPLACEMENT_Y": [ - 0.008854017755378977 + 0.008854017755135396 ], "DISPLACEMENT_Z": [ - -0.01824009660821716 + -0.018240096607689913 ] }, "NODE_17": { "DISPLACEMENT_X": [ - -0.00720268520909695 + -0.0061576818429062655 ], "DISPLACEMENT_Y": [ - -0.02237184254982237 + -0.022371842550146126 ], "DISPLACEMENT_Z": [ - -0.047946005228742844 + -0.04794600522949838 ] }, "NODE_18": { "DISPLACEMENT_X": [ - -0.002208158529889477 + -0.001163155163604184 ], "DISPLACEMENT_Y": [ - -0.012871807540322635 + -0.012871807540588519 ], "DISPLACEMENT_Z": [ - -0.03641383306565895 + -0.03641383306634605 ] }, "NODE_19": { "DISPLACEMENT_X": [ - 0.0010239444208608092 + 0.0020689477872034867 ], "DISPLACEMENT_Y": [ - -0.0025807864481494154 + -0.002580786448312697 ], "DISPLACEMENT_Z": [ - -0.015950773405835308 + -0.015950773406328375 ] }, "NODE_20": { "DISPLACEMENT_X": [ - 0.0015519393339176071 + 0.002596942700231149 ], "DISPLACEMENT_Y": [ - 0.0001988704988381371 + 0.00019887049874797353 ], "DISPLACEMENT_Z": [ - -0.0034211835121474394 + -0.0034211835123591212 ] }, "NODE_21": { "DISPLACEMENT_X": [ - 0.0015519393339202068 + 0.0025969427001594045 ], "DISPLACEMENT_Y": [ - -0.00019887049883827852 + -0.00019887049892399996 ], "DISPLACEMENT_Z": [ - -0.0034211835121822427 + -0.0034211835119860273 ] }, "NODE_22": { "DISPLACEMENT_X": [ - 0.001023944420861411 + 0.002068947787057706 ], "DISPLACEMENT_Y": [ - 0.002580786448151241 + 0.002580786447940291 ], "DISPLACEMENT_Z": [ - -0.01595077340585867 + -0.015950773405132616 ] }, "NODE_23": { "DISPLACEMENT_X": [ - -0.00220815852990013 + -0.001163155163601711 ], "DISPLACEMENT_Y": [ - 0.012871807540246149 + 0.012871807539745055 ], "DISPLACEMENT_Z": [ - -0.03641383306551688 + -0.03641383306421856 ] }, "NODE_24": { "DISPLACEMENT_X": [ - -0.007202685209096323 + -0.006157681842608374 ], "DISPLACEMENT_Y": [ - 0.022371842549641068 + 0.022371842548914323 ], "DISPLACEMENT_Z": [ - -0.047946005228470985 + -0.04794600522690168 ] }, "NODE_25": { "DISPLACEMENT_X": [ - -0.005827536494513729 + -0.004782533128305026 ], "DISPLACEMENT_Y": [ - -0.031497649890623834 + -0.03149764989113748 ], "DISPLACEMENT_Z": [ - -0.06941452634450976 + -0.06941452634569968 ] }, "NODE_26": { "DISPLACEMENT_X": [ - -0.0021236185245310985 + -0.0010786151582479501 ], "DISPLACEMENT_Y": [ - -0.018200682222050103 + -0.01820068222245872 ], "DISPLACEMENT_Z": [ - -0.05329299015630036 + -0.05329299015736512 ] }, "NODE_27": { "DISPLACEMENT_X": [ - 0.0007329714399240684 + 0.0017779748062567333 ], "DISPLACEMENT_Y": [ - -0.0035999724435776454 + -0.0035999724438309172 ], "DISPLACEMENT_Z": [ - -0.024176001782220884 + -0.024176001782988378 ] }, "NODE_28": { "DISPLACEMENT_X": [ - 0.0013554509318631435 + 0.0024004542981741943 ], "DISPLACEMENT_Y": [ - 0.00032696222290179563 + 0.0003269622227572536 ], "DISPLACEMENT_Z": [ - -0.005971664950788215 + -0.005971664951142349 ] }, "NODE_29": { "DISPLACEMENT_X": [ - 0.0013554509318655754 + 0.002400454298112515 ], "DISPLACEMENT_Y": [ - -0.00032696222289968605 + -0.00032696222303555826 ], "DISPLACEMENT_Z": [ - -0.005971664950850127 + -0.0059716649505579785 ] }, "NODE_30": { "DISPLACEMENT_X": [ - 0.0007329714399264803 + 0.0017779748061327498 ], "DISPLACEMENT_Y": [ - 0.0035999724435842625 + 0.0035999724432419283 ], "DISPLACEMENT_Z": [ - -0.024176001782271198 + -0.024176001781099608 ] }, "NODE_31": { "DISPLACEMENT_X": [ - -0.0021236185245383874 + -0.0010786151582453953 ], "DISPLACEMENT_Y": [ - 0.01820068222192766 + 0.018200682221097473 ], "DISPLACEMENT_Z": [ - -0.053292990156079176 + -0.05329299015394546 ] }, "NODE_32": { "DISPLACEMENT_X": [ - -0.005827536494519831 + -0.004782533128051175 ], "DISPLACEMENT_Y": [ - 0.031497649890310106 + 0.0314976498890996 ], "DISPLACEMENT_Z": [ - -0.069414526344053 + -0.0694145263414622 ] }, "NODE_33": { "DISPLACEMENT_X": [ - -0.004230233508002531 + -0.0031852301417672414 ], "DISPLACEMENT_Y": [ - -0.03616486507353125 + -0.03616486507414385 ], "DISPLACEMENT_Z": [ - -0.0821859313506309 + -0.08218593135208418 ] }, "NODE_34": { "DISPLACEMENT_X": [ - -0.001851859730108594 + -0.000806856363830054 ], "DISPLACEMENT_Y": [ - -0.020866298004893515 + -0.020866298005385565 ], "DISPLACEMENT_Z": [ - -0.06367279209436134 + -0.06367279209566823 ] }, "NODE_35": { "DISPLACEMENT_X": [ - 0.0003761852026747771 + 0.001421188568994703 ], "DISPLACEMENT_Y": [ - -0.004122745671559391 + -0.004122745671883916 ], "DISPLACEMENT_Z": [ - -0.03018361189076381 + -0.03018361189175279 ] }, "NODE_36": { "DISPLACEMENT_X": [ - 0.0010350519065680994 + 0.0020800552728746547 ], "DISPLACEMENT_Y": [ - 0.00040585530755534935 + 0.00040585530736352113 ], "DISPLACEMENT_Z": [ - -0.009037461298063007 + -0.009037461298559847 ] }, "NODE_37": { "DISPLACEMENT_X": [ - 0.0010350519065702233 + 0.002080055272827167 ], "DISPLACEMENT_Y": [ - -0.00040585530754994525 + -0.00040585530772638853 ], "DISPLACEMENT_Z": [ - -0.009037461298138616 + -0.00903746129778935 ] }, "NODE_38": { "DISPLACEMENT_X": [ - 0.000376185202677934 + 0.0014211885689004954 ], "DISPLACEMENT_Y": [ - 0.0041227456715761815 + 0.004122745671118594 ], "DISPLACEMENT_Z": [ - -0.030183611890849945 + -0.030183611889296125 ] }, "NODE_39": { "DISPLACEMENT_X": [ - -0.0018518597301092857 + -0.0008068563638236107 ], "DISPLACEMENT_Y": [ - 0.020866298004777416 + 0.0208662980036351 ], "DISPLACEMENT_Z": [ - -0.06367279209416704 + -0.06367279209125865 ] }, "NODE_40": { "DISPLACEMENT_X": [ - -0.0042302335080182515 + -0.003185230141580744 ], "DISPLACEMENT_Y": [ - 0.036164865073189716 + 0.036164865071498 ], "DISPLACEMENT_Z": [ - -0.0821859313501522 + -0.08218593134658321 ] }, "NODE_41": { "DISPLACEMENT_X": [ - -0.002569952919030571 + -0.0015249495527648177 ], "DISPLACEMENT_Y": [ - -0.0372667991946015 + -0.03726679919514159 ], "DISPLACEMENT_Z": [ - -0.08752158168887031 + -0.08752158169028985 ] }, "NODE_42": { "DISPLACEMENT_X": [ - -0.0014286135177186538 + -0.00038361015144466523 ], "DISPLACEMENT_Y": [ - -0.021359480256260034 + -0.02135948025676633 ], "DISPLACEMENT_Z": [ - -0.06814596048405247 + -0.06814596048543718 ] }, "NODE_43": { "DISPLACEMENT_X": [ - 5.693246313566713e-05 + 0.0011019358294403888 ], "DISPLACEMENT_Y": [ - -0.00417070857064339 + -0.004170708571017386 ], "DISPLACEMENT_Z": [ - -0.033801780122692145 + -0.033801780123840476 ] }, "NODE_44": { "DISPLACEMENT_X": [ - 0.0005621654544732462 + 0.0016071688207734026 ], "DISPLACEMENT_Y": [ - 0.0003702823361215244 + 0.00037028233589636616 ], "DISPLACEMENT_Z": [ - -0.01258130568578747 + -0.01258130568639916 ] }, "NODE_45": { "DISPLACEMENT_X": [ - 0.0005621654544761004 + 0.0016071688207446935 ], "DISPLACEMENT_Y": [ - -0.0003702823361122573 + -0.0003702823363193766 ], "DISPLACEMENT_Z": [ - -0.012581305685860817 + -0.012581305685477813 ] }, "NODE_46": { "DISPLACEMENT_X": [ - 5.6932463137465075e-05 + 0.0011019358293814356 ], "DISPLACEMENT_Y": [ - 0.004170708570675286 + 0.004170708570126529 ], "DISPLACEMENT_Z": [ - -0.03380178012283121 + -0.03380178012098464 ] }, "NODE_47": { "DISPLACEMENT_X": [ - -0.001428613517715779 + -0.000383610151434941 ], "DISPLACEMENT_Y": [ - 0.02135948025620389 + 0.021359480254783965 ], "DISPLACEMENT_Z": [ - -0.06814596048398425 + -0.06814596048041642 ] }, "NODE_48": { "DISPLACEMENT_X": [ - -0.0025699529190460076 + -0.0015249495526556002 ], "DISPLACEMENT_Y": [ - 0.03726679919437205 + 0.03726679919224196 ], "DISPLACEMENT_Z": [ - -0.08752158168859056 + -0.08752158168416502 ] }, "NODE_49": { "DISPLACEMENT_X": [ - -0.001218814352115321 + -0.00017381098581643984 ], "DISPLACEMENT_Y": [ - -0.03689288779182425 + -0.03689288779213783 ], "DISPLACEMENT_Z": [ - -0.08846073411984402 + -0.08846073412095296 ] }, "NODE_50": { "DISPLACEMENT_X": [ - -0.0005935537505122679 + 0.00045144961575357994 ], "DISPLACEMENT_Y": [ - -0.02071341172030042 + -0.02071341172074142 ], "DISPLACEMENT_Z": [ - -0.06905523650616088 + -0.06905523650743332 ] }, "NODE_51": { "DISPLACEMENT_X": [ - -0.00032655557741837285 + 0.000718447788873739 ], "DISPLACEMENT_Y": [ - -0.004103559702589127 + -0.00410355970298118 ], "DISPLACEMENT_Z": [ - -0.035378495366413694 + -0.03537849536764265 ] }, "NODE_52": { "DISPLACEMENT_X": [ - -1.4473167447475577e-05 + 0.001030530198842752 ], "DISPLACEMENT_Y": [ - 0.0002883993709171826 + 0.00028839937067201386 ], "DISPLACEMENT_Z": [ - -0.01571255665371407 + -0.015712556654399617 ] }, "NODE_53": { "DISPLACEMENT_X": [ - -1.4473167445211109e-05 + 0.0010305301988335414 ], "DISPLACEMENT_Y": [ - -0.00028839937089975476 + -0.00028839937112266293 ], "DISPLACEMENT_Z": [ - -0.01571255665382775 + -0.015712556653422825 ] }, "NODE_54": { "DISPLACEMENT_X": [ - -0.00032655557741693997 + 0.0007184477888569148 ], "DISPLACEMENT_Y": [ - 0.004103559702622363 + 0.0041035597020053945 ], "DISPLACEMENT_Z": [ - -0.03537849536656052 + -0.0353784953645127 ] }, "NODE_55": { "DISPLACEMENT_X": [ - -0.00059355375051768 + 0.0004514496157580921 ], "DISPLACEMENT_Y": [ - 0.020713411720281554 + 0.020713411718670225 ], "DISPLACEMENT_Z": [ - -0.06905523650617496 + -0.06905523650216812 ] }, "NODE_56": { "DISPLACEMENT_X": [ - -0.0012188143521117615 + -0.00017381098578404087 ], "DISPLACEMENT_Y": [ - 0.03689288779164805 + 0.03689288778920995 ], "DISPLACEMENT_Z": [ - -0.08846073411964829 + -0.08846073411465127 ] }, "NODE_57": { "DISPLACEMENT_X": [ - -0.0004854943968198135 + 0.00055950896948096 ], "DISPLACEMENT_Y": [ - -0.036548922710051154 + -0.036548922710220144 ], "DISPLACEMENT_Z": [ - -0.0892130253147277 + -0.08921302531557927 ] }, "NODE_58": { "DISPLACEMENT_X": [ - -0.0003334991859421141 + 0.0007115041803358172 ], "DISPLACEMENT_Y": [ - -0.021033908931736976 + -0.02103390893207782 ], "DISPLACEMENT_Z": [ - -0.06888267510664144 + -0.06888267510775499 ] }, "NODE_59": { "DISPLACEMENT_X": [ - -0.00031985651756040933 + 0.0007251468487169177 ], "DISPLACEMENT_Y": [ - -0.004417581337323782 + -0.004417581337702555 ], "DISPLACEMENT_Z": [ - -0.03555164488678266 + -0.03555164488799629 ] }, "NODE_60": { "DISPLACEMENT_X": [ - -0.00041363532500377127 + 0.0006313680412839449 ], "DISPLACEMENT_Y": [ - 0.0009085279349960485 + 0.0009085279347269153 ], "DISPLACEMENT_Z": [ - -0.015887522198681267 + -0.01588752219941548 ] }, "NODE_61": { "DISPLACEMENT_X": [ - -0.00041363532500281837 + 0.0006313680412832755 ], "DISPLACEMENT_Y": [ - -0.0009085279349725742 + -0.000908527935173462 ], "DISPLACEMENT_Z": [ - -0.01588752219881185 + -0.015887522198408607 ] }, "NODE_62": { "DISPLACEMENT_X": [ - -0.0003198565175620334 + 0.0007251468487219114 ], "DISPLACEMENT_Y": [ - 0.004417581337348813 + 0.004417581336715184 ], "DISPLACEMENT_Z": [ - -0.03555164488691727 + -0.03555164488484282 ] }, "NODE_63": { "DISPLACEMENT_X": [ - -0.0003334991859441039 + 0.0007115041803389727 ], "DISPLACEMENT_Y": [ - 0.021033908931644266 + 0.021033908930002752 ], "DISPLACEMENT_Z": [ - -0.06888267510652923 + -0.06888267510249708 ] }, "NODE_64": { "DISPLACEMENT_X": [ - -0.00048549439681403557 + 0.0005595089694715411 ], "DISPLACEMENT_Y": [ - 0.03654892270978166 + 0.03654892270732914 ], "DISPLACEMENT_Z": [ - -0.08921302531437882 + -0.08921302530932589 ] }, "NODE_65": { "DISPLACEMENT_X": [ - -0.0004823555319962405 + 0.0005626478343049025 ], "DISPLACEMENT_Y": [ - -0.03659061101189537 + -0.036590611012062936 ], "DISPLACEMENT_Z": [ - -0.0891835694615852 + -0.08918356946243747 ] }, "NODE_66": { "DISPLACEMENT_X": [ - -0.0003681929870192589 + 0.0006768103792638416 ], "DISPLACEMENT_Y": [ - -0.02493750420102757 + -0.02493750420132735 ], "DISPLACEMENT_Z": [ - -0.0741829722973834 + -0.07418297229842788 ] }, "NODE_67": { "DISPLACEMENT_X": [ - -0.00031115092234206216 + 0.0007338524439337848 ], "DISPLACEMENT_Y": [ - -0.009946325541871772 + -0.009946325542250757 ], "DISPLACEMENT_Z": [ - -0.04763490357641317 + -0.04763490357762022 ] }, "NODE_68": { "DISPLACEMENT_X": [ - -0.0003556075296829162 + 0.0006893958365984044 ], "DISPLACEMENT_Y": [ - -0.0018487029198830415 + -0.0018487029202243982 ], "DISPLACEMENT_Z": [ - -0.02716215740745041 + -0.027162157408526014 ] }, "NODE_69": { "DISPLACEMENT_X": [ - -0.00041698533408145025 + 0.0006280180322062225 ], "DISPLACEMENT_Y": [ - 0.0006037632281914193 + 0.0006037632279333543 ], "DISPLACEMENT_Z": [ - -0.015872185397511188 + -0.015872185398103558 ] }, "NODE_70": { "DISPLACEMENT_X": [ - -0.00041698533408069673 + 0.0006280180322055726 ], "DISPLACEMENT_Y": [ - -0.0006037632281686357 + -0.00060376322838044 ], "DISPLACEMENT_Z": [ - -0.015872185397608894 + -0.015872185397348172 ] }, "NODE_71": { "DISPLACEMENT_X": [ - -0.0003556075296834513 + 0.0006893958366013742 ], "DISPLACEMENT_Y": [ - 0.0018487029199106774 + 0.0018487029194723449 ], "DISPLACEMENT_Z": [ - -0.027162157407599846 + -0.02716215740617304 ] }, "NODE_72": { "DISPLACEMENT_X": [ - -0.0003111509223443279 + 0.0007338524439391169 ], "DISPLACEMENT_Y": [ - 0.009946325541863347 + 0.009946325540882331 ], "DISPLACEMENT_Z": [ - -0.04763490357646855 + -0.04763490357365728 ] }, "NODE_73": { "DISPLACEMENT_X": [ - -0.0003681929870195622 + 0.0006768103792640674 ], "DISPLACEMENT_Y": [ - 0.02493750420089175 + 0.024937504199043982 ], "DISPLACEMENT_Z": [ - -0.07418297229721052 + -0.07418297229291373 ] }, "NODE_74": { "DISPLACEMENT_X": [ - -0.0004823555319903019 + 0.0005626478342950768 ], "DISPLACEMENT_Y": [ - 0.03659061101162481 + 0.03659061100917112 ], "DISPLACEMENT_Z": [ - -0.08918356946123618 + -0.08918356945618403 ] }, "NODE_75": { "DISPLACEMENT_X": [ - 6.45774088501195e-05 + 0.001109580775159145 ], "DISPLACEMENT_Y": [ - -0.037253380187917844 + -0.03725338018794782 ], "DISPLACEMENT_Z": [ - -0.0892826007435178 + -0.08928260074419167 ] }, "NODE_76": { "DISPLACEMENT_X": [ - -0.0001005705379135903 + 0.0009444328283709478 ], "DISPLACEMENT_Y": [ - -0.025099927037616848 + -0.025099927037835035 ], "DISPLACEMENT_Z": [ - -0.07481802096467259 + -0.07481802096557003 ] }, "NODE_77": { "DISPLACEMENT_X": [ - -0.00023694489680404964 + 0.0008080584694695583 ], "DISPLACEMENT_Y": [ - -0.009782781533454913 + -0.009782781533824012 ], "DISPLACEMENT_Z": [ - -0.04795349443115524 + -0.0479534944323198 ] }, "NODE_78": { "DISPLACEMENT_X": [ - -0.00044240261329474024 + 0.0006026007529782855 ], "DISPLACEMENT_Y": [ - -0.0019255078332263292 + -0.0019255078335661993 ], "DISPLACEMENT_Z": [ - -0.02703617437352415 + -0.027036174374614523 ] }, "NODE_79": { "DISPLACEMENT_X": [ - -0.0007363099533286849 + 0.0003086934129573198 ], "DISPLACEMENT_Y": [ - 0.00012106843550697891 + 0.00012106843526318865 ], "DISPLACEMENT_Z": [ - -0.015732732521809987 + -0.015732732522428742 ] }, "NODE_80": { "DISPLACEMENT_X": [ - -0.0007363099533298651 + 0.00030869341296199687 ], "DISPLACEMENT_Y": [ - -0.00012106843548830652 + -0.00012106843571464935 ], "DISPLACEMENT_Z": [ - -0.015732732521911433 + -0.01573273252166196 ] }, "NODE_81": { "DISPLACEMENT_X": [ - -0.00044240261329701864 + 0.000602600752994144 ], "DISPLACEMENT_Y": [ - 0.001925507833256333 + 0.001925507832815252 ], "DISPLACEMENT_Z": [ - -0.02703617437368092 + -0.02703617437225827 ] }, "NODE_82": { "DISPLACEMENT_X": [ - -0.00023694489680568356 + 0.0008080584694855814 ], "DISPLACEMENT_Y": [ - 0.009782781533435843 + 0.009782781532457372 ], "DISPLACEMENT_Z": [ - -0.04795349443118047 + -0.047953494428357335 ] }, "NODE_83": { "DISPLACEMENT_X": [ - -0.00010057053791226636 + 0.0009444328283695888 ], "DISPLACEMENT_Y": [ - 0.02509992703743435 + 0.02509992703557696 ], "DISPLACEMENT_Z": [ - -0.07481802096441242 + -0.0748180209600914 ] }, "NODE_84": { "DISPLACEMENT_X": [ - 6.457740885659813e-05 + 0.0011095807751095013 ], "DISPLACEMENT_Y": [ - 0.0372533801875721 + 0.03725338018509485 ], "DISPLACEMENT_Z": [ - -0.08928260074306249 + -0.08928260073800356 ] }, "NODE_85": { "DISPLACEMENT_X": [ - 0.0009828767575108233 + 0.0020278801238300987 ], "DISPLACEMENT_Y": [ - -0.03923729956120669 + -0.03923729956109808 ], "DISPLACEMENT_Z": [ - -0.09168332045512873 + -0.0916833204555576 ] }, "NODE_86": { "DISPLACEMENT_X": [ - 0.0007193466914709632 + 0.001764350057763693 ], "DISPLACEMENT_Y": [ - -0.02701064614562444 + -0.027010646145789453 ], "DISPLACEMENT_Z": [ - -0.0769429537267166 + -0.07694295372748607 ] }, "NODE_87": { "DISPLACEMENT_X": [ - -0.00021986772602733157 + 0.0008251356402397352 ], "DISPLACEMENT_Y": [ - -0.010398195043250508 + -0.010398195043609126 ], "DISPLACEMENT_Z": [ - -0.04851144355062453 + -0.04851144355174472 ] }, "NODE_88": { "DISPLACEMENT_X": [ - -0.0008060737449922464 + 0.00023892962127117703 ], "DISPLACEMENT_Y": [ - -0.0019715402161442955 + -0.0019715402164689963 ], "DISPLACEMENT_Z": [ - -0.025420498207214263 + -0.025420498208278765 ] }, "NODE_89": { "DISPLACEMENT_X": [ - -0.0011865933431016108 + -0.00014158997682298268 ], "DISPLACEMENT_Y": [ - 0.0001266572702399986 + 0.0001266572700131657 ], "DISPLACEMENT_Z": [ - -0.012752056911685844 + -0.012752056912283732 ] }, "NODE_90": { "DISPLACEMENT_X": [ - -0.0011865933431039436 + -0.0001415899768068052 ], "DISPLACEMENT_Y": [ - -0.0001266572702263008 + -0.0001266572704436782 ], "DISPLACEMENT_Z": [ - -0.012752056911763633 + -0.012752056911553787 ] }, "NODE_91": { "DISPLACEMENT_X": [ - -0.0008060737449955535 + 0.0002389296213136391 ], "DISPLACEMENT_Y": [ - 0.0019715402161768814 + 0.0019715402157651288 ], "DISPLACEMENT_Z": [ - -0.025420498207374288 + -0.025420498206061903 ] }, "NODE_92": { "DISPLACEMENT_X": [ - -0.00021986772602715382 + 0.0008251356402812864 ], "DISPLACEMENT_Y": [ - 0.010398195043250057 + 0.010398195042342809 ], "DISPLACEMENT_Z": [ - -0.04851144355067707 + -0.04851144354803138 ] }, "NODE_93": { "DISPLACEMENT_X": [ - 0.0007193466914764108 + 0.0017643500577446528 ], "DISPLACEMENT_Y": [ - 0.027010646145469337 + 0.027010646143736564 ], "DISPLACEMENT_Z": [ - -0.07694295372649712 + -0.0769429537224465 ] }, "NODE_94": { "DISPLACEMENT_X": [ - 0.0009828767575121332 + 0.0020278801237135387 ], "DISPLACEMENT_Y": [ - 0.039237299560867654 + 0.03923729955857557 ], "DISPLACEMENT_Z": [ - -0.09168332045467985 + -0.09168332044995788 ] }, "NODE_95": { "DISPLACEMENT_X": [ - 0.0022443622706479 + 0.0032893656369728645 ], "DISPLACEMENT_Y": [ - -0.04082855640295997 + -0.040828556402898314 ], "DISPLACEMENT_Z": [ - -0.09236055629048387 + -0.09236055629092162 ] }, "NODE_96": { "DISPLACEMENT_X": [ - 0.0012973390878004414 + 0.0023423424541015748 ], "DISPLACEMENT_Y": [ - -0.028246659541956896 + -0.02824665954211651 ], "DISPLACEMENT_Z": [ - -0.07726842247336672 + -0.0772684224740742 ] }, "NODE_97": { "DISPLACEMENT_X": [ - -0.00025991755467178005 + 0.0007850858115896949 ], "DISPLACEMENT_Y": [ - -0.011027835960445407 + -0.01102783596076559 ], "DISPLACEMENT_Z": [ - -0.047761436548873104 + -0.04776143654987576 ] }, "NODE_98": { "DISPLACEMENT_X": [ - -0.0011513629363123278 + -0.00010635957005815296 ], "DISPLACEMENT_Y": [ - -0.0020371669874400243 + -0.002037166987731637 ], "DISPLACEMENT_Z": [ - -0.023264794325667398 + -0.023264794326629815 ] }, "NODE_99": { "DISPLACEMENT_X": [ - -0.001554082263243393 + -0.0005090788969705353 ], "DISPLACEMENT_Y": [ - 0.00018087809204491586 + 0.00018087809183893342 ], "DISPLACEMENT_Z": [ - -0.009331460599411815 + -0.009331460599967631 ] }, "NODE_100": { "DISPLACEMENT_X": [ - -0.0015540822632457727 + -0.0005090788969438576 ], "DISPLACEMENT_Y": [ - -0.00018087809203410146 + -0.00018087809223032094 ], "DISPLACEMENT_Z": [ - -0.009331460599472843 + -0.009331460599294858 ] }, "NODE_101": { "DISPLACEMENT_X": [ - -0.0011513629363161864 + -0.00010635956999112974 ], "DISPLACEMENT_Y": [ - 0.0020371669874662685 + 0.0020371669870944517 ], "DISPLACEMENT_Z": [ - -0.02326479432579623 + -0.02326479432460895 ] }, "NODE_102": { "DISPLACEMENT_X": [ - -0.00025991755467113473 + 0.0007850858116508505 ], "DISPLACEMENT_Y": [ - 0.011027835960454199 + 0.011027835959644237 ], "DISPLACEMENT_Z": [ - -0.047761436548938496 + -0.04776143654656419 ] }, "NODE_103": { "DISPLACEMENT_X": [ - 0.0012973390878074627 + 0.00234234245406425 ], "DISPLACEMENT_Y": [ - 0.028246659541843397 + 0.028246659540323495 ], "DISPLACEMENT_Z": [ - -0.07726842247321036 + -0.07726842246962069 ] }, "NODE_104": { "DISPLACEMENT_X": [ - 0.0022443622706490836 + 0.003289365636807745 ], "DISPLACEMENT_Y": [ - 0.04082855640271015 + 0.04082855640071075 ], "DISPLACEMENT_Z": [ - -0.092360556290163 + -0.09236055628600023 ] }, "NODE_105": { "DISPLACEMENT_X": [ - 0.00360233936293459 + 0.004647342729269216 ], "DISPLACEMENT_Y": [ - -0.040277087083103076 + -0.04027708708314092 ], "DISPLACEMENT_Z": [ - -0.08856479078036833 + -0.08856479078086776 ] }, "NODE_106": { "DISPLACEMENT_X": [ - 0.0017980722978526461 + 0.0028430756641571954 ], "DISPLACEMENT_Y": [ - -0.02795066678405187 + -0.027950666784211303 ], "DISPLACEMENT_Z": [ - -0.0737549685874008 + -0.07375496858804925 ] }, "NODE_107": { "DISPLACEMENT_X": [ - -0.0004108120618114765 + 0.0006341913044462409 ], "DISPLACEMENT_Y": [ - -0.010968146231761927 + -0.010968146232027486 ], "DISPLACEMENT_Z": [ - -0.04471088467232497 + -0.044710884673165106 ] }, "NODE_108": { "DISPLACEMENT_X": [ - -0.0014613355077872842 + -0.00041633214154091993 ], "DISPLACEMENT_Y": [ - -0.0020479517194150173 + -0.0020479517196622483 ], "DISPLACEMENT_Z": [ - -0.02044317288251172 + -0.020443172883326304 ] }, "NODE_109": { "DISPLACEMENT_X": [ - -0.0018316441219689958 + -0.0007866407557008927 ], "DISPLACEMENT_Y": [ - 0.00018604849216430125 + 0.00018604849198653264 ], "DISPLACEMENT_Z": [ - -0.006529425530141734 + -0.0065294255306301684 ] }, "NODE_110": { "DISPLACEMENT_X": [ - -0.0018316441219713158 + -0.0007866407556649188 ], "DISPLACEMENT_Y": [ - -0.00018604849215661182 + -0.00018604849232544418 ], "DISPLACEMENT_Z": [ - -0.006529425530186752 + -0.006529425530032706 ] }, "NODE_111": { "DISPLACEMENT_X": [ - -0.0014613355077910837 + -0.00041633214145282173 ], "DISPLACEMENT_Y": [ - 0.002047951719433884 + 0.002047951719109498 ], "DISPLACEMENT_Z": [ - -0.020443172882605904 + -0.020443172881564636 ] }, "NODE_112": { "DISPLACEMENT_X": [ - -0.0004108120618106516 + 0.0006341913045221716 ], "DISPLACEMENT_Y": [ - 0.010968146231766307 + 0.010968146231070291 ], "DISPLACEMENT_Z": [ - -0.044710884672370235 + -0.044710884670325426 ] }, "NODE_113": { "DISPLACEMENT_X": [ - 0.0017980722978597837 + 0.002843075664104612 ], "DISPLACEMENT_Y": [ - 0.02795066678397601 + 0.02795066678269974 ], "DISPLACEMENT_Z": [ - -0.0737549685873042 + -0.07375496858426885 ] }, "NODE_114": { "DISPLACEMENT_X": [ - 0.0036023393629377597 + 0.00464734272906573 ], "DISPLACEMENT_Y": [ - 0.04027708708294993 + 0.040277087081290096 ], "DISPLACEMENT_Z": [ - -0.08856479078017727 + -0.08856479077668318 ] }, "NODE_115": { "DISPLACEMENT_X": [ - 0.004945541704605817 + 0.005990545070949267 ], "DISPLACEMENT_Y": [ - -0.036748347298742684 + -0.036748347298825736 ], "DISPLACEMENT_Z": [ - -0.07894003870553848 + -0.07894003870601758 ] }, "NODE_116": { "DISPLACEMENT_X": [ - 0.002198591238685082 + 0.003243594604991734 ], "DISPLACEMENT_Y": [ - -0.02551283358985804 + -0.0255128335900098 ], "DISPLACEMENT_Z": [ - -0.06545035377933446 + -0.06545035377989714 ] }, "NODE_117": { "DISPLACEMENT_X": [ - -0.0006128423039718125 + 0.00043216106228256807 ], "DISPLACEMENT_Y": [ - -0.010007879548693581 + -0.010007879548905245 ], "DISPLACEMENT_Z": [ - -0.038923011095897395 + -0.038923011096568504 ] }, "NODE_118": { "DISPLACEMENT_X": [ - -0.0017342624259731884 + -0.000689259059732822 ], "DISPLACEMENT_Y": [ - -0.0018769137195942776 + -0.0018769137197916267 ], "DISPLACEMENT_Z": [ - -0.016851048784274864 + -0.016851048784923363 ] }, "NODE_119": { "DISPLACEMENT_X": [ - -0.0020297546922030917 + -0.0009847513259386338 ], "DISPLACEMENT_Y": [ - 0.00015379521847464506 + 0.00015379521833103885 ], "DISPLACEMENT_Z": [ - -0.004320925500573621 + -0.0043209255009685 ] }, "NODE_120": { "DISPLACEMENT_X": [ - -0.0020297546922052167 + -0.0009847513258950137 ], "DISPLACEMENT_Y": [ - -0.00015379521846958333 + -0.00015379521860608877 ], "DISPLACEMENT_Z": [ - -0.004320925500605245 + -0.004320925500477985 ] }, "NODE_121": { "DISPLACEMENT_X": [ - -0.0017342624259766494 + -0.0006892590596277226 ], "DISPLACEMENT_Y": [ - 0.0018769137196064049 + 0.0018769137193420484 ], "DISPLACEMENT_Z": [ - -0.01685104878433799 + -0.016851048783485104 ] }, "NODE_122": { "DISPLACEMENT_X": [ - -0.0006128423039708445 + 0.00043216106236980997 ], "DISPLACEMENT_Y": [ - 0.010007879548694644 + 0.01000787954813146 ], "DISPLACEMENT_Z": [ - -0.03892301109592696 + -0.03892301109427114 ] }, "NODE_123": { "DISPLACEMENT_X": [ - 0.0021985912386919344 + 0.003243594604927231 ], "DISPLACEMENT_Y": [ - 0.025512833589812184 + 0.02551283358879689 ], "DISPLACEMENT_Z": [ - -0.06545035377928154 + -0.06545035377685607 ] }, "NODE_124": { "DISPLACEMENT_X": [ - 0.0049455417046107494 + 0.005990545070715444 ], "DISPLACEMENT_Y": [ - 0.036748347298650536 + 0.036748347297344545 ], "DISPLACEMENT_Z": [ - -0.0789400387054294 + -0.078940038702657 ] }, "NODE_125": { "DISPLACEMENT_X": [ - 0.006145280851604458 + 0.0071902842179557645 ], "DISPLACEMENT_Y": [ - -0.029987034278762592 + -0.029987034278843132 ], "DISPLACEMENT_Z": [ - -0.06317148315572249 + -0.06317148315610421 ] }, "NODE_126": { "DISPLACEMENT_X": [ - 0.002503898951855521 + 0.003548902318163097 ], "DISPLACEMENT_Y": [ - -0.020789288618385544 + -0.02078928861850854 ], "DISPLACEMENT_Z": [ - -0.05212367432340285 + -0.05212367432383644 ] }, "NODE_127": { "DISPLACEMENT_X": [ - -0.0008289882901826383 + 0.0002160150760689879 ], "DISPLACEMENT_Y": [ - -0.008127629748569972 + -0.008127629748728127 ], "DISPLACEMENT_Z": [ - -0.03047707876127639 + -0.03047707876177444 ] }, "NODE_128": { "DISPLACEMENT_X": [ - -0.0019558585351573798 + -0.0009108551689214061 ], "DISPLACEMENT_Y": [ - -0.0015367566443589536 + -0.0015367566445031768 ], "DISPLACEMENT_Z": [ - -0.012641717978498102 + -0.012641717978970422 ] }, "NODE_129": { "DISPLACEMENT_X": [ - -0.0021617296409131236 + -0.0011167262746511338 ], "DISPLACEMENT_Y": [ - 0.00010928529228736657 + 0.00010928529218216751 ], "DISPLACEMENT_Z": [ - -0.002650154145303281 + -0.002650154145590145 ] }, "NODE_130": { "DISPLACEMENT_X": [ - -0.002161729640915036 + -0.0011167262746018076 ], "DISPLACEMENT_Y": [ - -0.00010928529228436821 + -0.00010928529238453662 ], "DISPLACEMENT_Z": [ - -0.0026501541453229907 + -0.0026501541452284305 ] }, "NODE_131": { "DISPLACEMENT_X": [ - -0.001955858535160405 + -0.000910855168803644 ], "DISPLACEMENT_Y": [ - 0.001536756644366348 + 0.0015367566441723598 ], "DISPLACEMENT_Z": [ - -0.012641717978538409 + -0.012641717977910846 ] }, "NODE_132": { "DISPLACEMENT_X": [ - -0.0008289882901815646 + 0.0002160150761646897 ], "DISPLACEMENT_Y": [ - 0.00812762974857193 + 0.008127629748159337 ], "DISPLACEMENT_Z": [ - -0.030477078761299303 + -0.030477078760084566 ] }, "NODE_133": { "DISPLACEMENT_X": [ - 0.002503898951861967 + 0.00354890231809024 ], "DISPLACEMENT_Y": [ - 0.020789288618358777 + 0.020789288617619615 ], "DISPLACEMENT_Z": [ - -0.05212367432337524 + -0.05212367432160536 ] }, "NODE_134": { "DISPLACEMENT_X": [ - 0.0061452808516107614 + 0.007190284217698286 ], "DISPLACEMENT_Y": [ - 0.029987034278707553 + 0.02998703427776225 ], "DISPLACEMENT_Z": [ - -0.06317148315566048 + -0.06317148315364478 ] }, "NODE_135": { "DISPLACEMENT_X": [ - 0.007097642102820181 + 0.008142645469176946 ], "DISPLACEMENT_Y": [ - -0.020098889898041466 + -0.020098889898095953 ], "DISPLACEMENT_Z": [ - -0.04160190579002582 + -0.04160190579026804 ] }, "NODE_136": { "DISPLACEMENT_X": [ - 0.0026912910296609358 + 0.003736294395969414 ], "DISPLACEMENT_Y": [ - -0.013913210937292284 + -0.013913210937371679 ], "DISPLACEMENT_Z": [ - -0.03416565743458193 + -0.034165657434854474 ] }, "NODE_137": { "DISPLACEMENT_X": [ - -0.001012357842683538 + 3.2645523565756786e-05 ], "DISPLACEMENT_Y": [ - -0.005432874811099291 + -0.005432874811197975 ], "DISPLACEMENT_Z": [ - -0.019714997195087326 + -0.019714997195395777 ] }, "NODE_138": { "DISPLACEMENT_X": [ - -0.0021130598319754807 + -0.0010680564657423583 ], "DISPLACEMENT_Y": [ - -0.0010495036888845187 + -0.0010495036889728898 ], "DISPLACEMENT_Z": [ - -0.007980526258859354 + -0.00798052625914799 ] }, "NODE_139": { "DISPLACEMENT_X": [ - -0.0022393002552472856 + -0.0011942968889867157 ], "DISPLACEMENT_Y": [ - 5.3406317800048874e-05 + 5.340631773590373e-05 ], "DISPLACEMENT_Z": [ - -0.001500014843291177 + -0.0015000148434645083 ] }, "NODE_140": { "DISPLACEMENT_X": [ - -0.00223930025524899 + -0.0011942968889336622 ], "DISPLACEMENT_Y": [ - -5.340631779849761e-05 + -5.3406317859623845e-05 ], "DISPLACEMENT_Z": [ - -0.001500014843301839 + -0.001500014843243536 ] }, "NODE_141": { "DISPLACEMENT_X": [ - -0.002113059831978118 + -0.0010680564656162744 ], "DISPLACEMENT_Y": [ - 0.001049503688888832 + 0.0010495036887708024 ], "DISPLACEMENT_Z": [ - -0.007980526258882894 + -0.007980526258500455 ] }, "NODE_142": { "DISPLACEMENT_X": [ - -0.0010123578426825147 + 3.264552366729217e-05 ], "DISPLACEMENT_Y": [ - 0.005432874811101227 + 0.005432874810850134 ], "DISPLACEMENT_Z": [ - -0.019714997195102495 + -0.019714997194362285 ] }, "NODE_143": { "DISPLACEMENT_X": [ - 0.0026912910296672567 + 0.0037362943958910966 ], "DISPLACEMENT_Y": [ - 0.013913210937278599 + 0.013913210936828659 ], "DISPLACEMENT_Z": [ - -0.03416565743456935 + -0.034165657433491 ] }, "NODE_144": { "DISPLACEMENT_X": [ - 0.007097642102827238 + 0.008142645468903281 ], "DISPLACEMENT_Y": [ - 0.020098889898012583 + 0.020098889897436762 ], "DISPLACEMENT_Z": [ - -0.04160190578999486 + -0.04160190578876641 ] }, "NODE_145": { "DISPLACEMENT_X": [ - 0.007671515202057538 + 0.008716518568417216 ], "DISPLACEMENT_Y": [ - -0.0074866724398142325 + -0.00748667243983387 ], "DISPLACEMENT_Z": [ - -0.015106913304797723 + -0.015106913304881314 ] }, "NODE_146": { "DISPLACEMENT_X": [ - 0.002752861548917303 + 0.0037978649152262084 ], "DISPLACEMENT_Y": [ - -0.00518960525367837 + -0.005189605253706224 ], "DISPLACEMENT_Z": [ - -0.012356457380181055 + -0.012356457380274707 ] }, "NODE_147": { "DISPLACEMENT_X": [ - -0.0011153834313549372 + -7.038006510689117e-05 ], "DISPLACEMENT_Y": [ - -0.002024330734097124 + -0.002024330734130941 ], "DISPLACEMENT_Z": [ - -0.007072769843467417 + -0.007072769843572489 ] }, "NODE_148": { "DISPLACEMENT_X": [ - -0.0021948103635887344 + -0.0011498069973570767 ], "DISPLACEMENT_Y": [ - -0.0004053052808978637 + -0.00040530528092784664 ], "DISPLACEMENT_Z": [ - -0.002854624213084006 + -0.0028546242131818173 ] }, "NODE_149": { "DISPLACEMENT_X": [ - -0.0022737601845310047 + -0.0012287568182710472 ], "DISPLACEMENT_Y": [ - 7.869739873405007e-06 + 7.869739851835956e-06 ], "DISPLACEMENT_Z": [ - -0.0005668328486710144 + -0.0005668328487292659 ] }, "NODE_150": { "DISPLACEMENT_X": [ - -0.002273760184532569 + -0.0012287568182161525 ], "DISPLACEMENT_Y": [ - -7.869739872896521e-06 + -7.869739893463951e-06 ], "DISPLACEMENT_Z": [ - -0.0005668328486748065 + -0.0005668328486546927 ] }, "NODE_151": { "DISPLACEMENT_X": [ - -0.002194810363591205 + -0.0011498069972268787 ], "DISPLACEMENT_Y": [ - 0.00040530528089933326 + 0.00040530528085962474 ], "DISPLACEMENT_Z": [ - -0.002854624213091874 + -0.0028546242129631116 ] }, "NODE_152": { "DISPLACEMENT_X": [ - -0.0011153834313539256 + -7.038006500241313e-05 ], "DISPLACEMENT_Y": [ - 0.002024330734097839 + 0.0020243307340133965 ], "DISPLACEMENT_Z": [ - -0.007072769843472577 + -0.007072769843223626 ] }, "NODE_153": { "DISPLACEMENT_X": [ - 0.00275286154892349 + 0.0037978649151452523 ], "DISPLACEMENT_Y": [ - 0.0051896052536745734 + 0.005189605253522448 ], "DISPLACEMENT_Z": [ - -0.01235645738017814 + -0.01235645737981432 ] }, "NODE_154": { "DISPLACEMENT_X": [ - 0.007671515202065031 + 0.008716518568135262 ], "DISPLACEMENT_Y": [ - 0.007486672439806044 + 0.007486672439610621 ], "DISPLACEMENT_Z": [ - -0.015106913304789412 + -0.015106913304373968 ] }, "NODE_155": { "DISPLACEMENT_X": [ - 0.0076869317894150595 + 0.00873193515577477 ], "DISPLACEMENT_Y": [ 0.0 @@ -1709,7 +1709,7 @@ }, "NODE_156": { "DISPLACEMENT_X": [ - 0.0027431174027037447 + 0.003788120769012639 ], "DISPLACEMENT_Y": [ 0.0 @@ -1720,7 +1720,7 @@ }, "NODE_157": { "DISPLACEMENT_X": [ - -0.001113298080290252 + -6.829471404220749e-05 ], "DISPLACEMENT_Y": [ 0.0 @@ -1731,7 +1731,7 @@ }, "NODE_158": { "DISPLACEMENT_X": [ - -0.0021957157039287937 + -0.0011507123376971425 ], "DISPLACEMENT_Y": [ 0.0 @@ -1742,7 +1742,7 @@ }, "NODE_159": { "DISPLACEMENT_X": [ - -0.0022733047907345224 + -0.0012283014244745618 ], "DISPLACEMENT_Y": [ 0.0 @@ -1753,7 +1753,7 @@ }, "NODE_160": { "DISPLACEMENT_X": [ - -0.0022733047907360963 + -0.0012283014244196804 ], "DISPLACEMENT_Y": [ 0.0 @@ -1764,7 +1764,7 @@ }, "NODE_161": { "DISPLACEMENT_X": [ - -0.0021957157039312527 + -0.0011507123375669205 ], "DISPLACEMENT_Y": [ 0.0 @@ -1775,7 +1775,7 @@ }, "NODE_162": { "DISPLACEMENT_X": [ - -0.0011132980802892407 + -6.829471393774424e-05 ], "DISPLACEMENT_Y": [ 0.0 @@ -1786,7 +1786,7 @@ }, "NODE_163": { "DISPLACEMENT_X": [ - 0.0027431174027099377 + 0.00378812076893175 ], "DISPLACEMENT_Y": [ 0.0 @@ -1797,7 +1797,7 @@ }, "NODE_164": { "DISPLACEMENT_X": [ - 0.007686931789422528 + 0.008731935155492691 ], "DISPLACEMENT_Y": [ 0.0 From 982f87ca09887c10778917d70f1a477f17fcd223 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Mon, 8 Jun 2026 17:45:03 +0200 Subject: [PATCH 36/50] create the new projection algorithms for curve and surface --- .../projection_nurbs_geometry_utilities.h | 286 ++++++++++++++++++ 1 file changed, 286 insertions(+) diff --git a/kratos/utilities/nurbs_utilities/projection_nurbs_geometry_utilities.h b/kratos/utilities/nurbs_utilities/projection_nurbs_geometry_utilities.h index 00a31f691aae..99899b823ead 100644 --- a/kratos/utilities/nurbs_utilities/projection_nurbs_geometry_utilities.h +++ b/kratos/utilities/nurbs_utilities/projection_nurbs_geometry_utilities.h @@ -24,6 +24,13 @@ namespace Kratos { + + enum class ProjectionAlgorithm + { + NewtonRaphson, + LevenbergMarquardt + }; + template class NurbsSurfaceGeometry; class ProjectionNurbsGeometryUtilities { @@ -120,6 +127,143 @@ class ProjectionNurbsGeometryUtilities return false; } + /* + * @brief Returns the closest-point projection of a point onto a Nurbs curve + * geometry using a Levenberg-Marquardt iterative method. + * @param rProjectedPointLocalCoordinates Initial guess for the iterative + * algorithm. This is overwritten by the local coordinate of the + * projected point onto the Nurbs curve geometry. + * @param rPointGlobalCoordinates The global coordinates of the point to be + * projected onto the Nurbs curve geometry. + * @param rProjectedPointGlobalCoordinates The global coordinates of the + * projected point on the Nurbs curve geometry. This is overwritten + * in case the projection is successful. + * @param rGeometry The Nurbs curve geometry onto which the point is to be + * projected. + * @param MaxIterations Maximum number of iterations for the + * Levenberg-Marquardt algorithm. + * @param Accuracy Accuracy used for the distance, orthogonality, and step-size + * convergence checks. + */ + template + static bool LevenbergMarquardtCurve( + CoordinatesArrayType& rProjectedPointLocalCoordinates, + const CoordinatesArrayType& rPointGlobalCoordinates, + CoordinatesArrayType& rProjectedPointGlobalCoordinates, + const Geometry& rGeometry, + const int MaxIterations = 30, + const double Accuracy = 1e-6) + { + double lambda = 1e-8; + const double lambda_factor = 10.0; + const double max_lambda = 1e12; + + bool projection_reset_to_boundary = false; + + for (int i = 0; i < MaxIterations; ++i) { + + // Compute position and first derivative only + std::vector> derivatives(2); + + rGeometry.GlobalSpaceDerivatives(derivatives, rProjectedPointLocalCoordinates, 1); + + rProjectedPointGlobalCoordinates = derivatives[0]; + + const array_1d distance_vector = rProjectedPointGlobalCoordinates - rPointGlobalCoordinates; + + const double distance = norm_2(distance_vector); + + if (distance < Accuracy) { + return true; + } + + const double tangent_norm = norm_2(derivatives[1]); + + if (tangent_norm < Accuracy) { + return false; + } + + // Gradient of 1/2 ||C(t)-x||^2 + const double gradient = inner_prod(derivatives[1], distance_vector); + + const double tangent_cos = std::abs(gradient) / (tangent_norm * distance); + + // Orthogonality condition + if (tangent_cos < Accuracy) { + return true; + } + + // 1D Levenberg-Marquardt system: + // (C_t · C_t + lambda) delta_t = - C_t · (C - x) + const double a = inner_prod(derivatives[1], derivatives[1]); + + bool step_accepted = false; + + for (int lm_it = 0; lm_it < 10; ++lm_it) { + + const double denominator = a + lambda; + + if (std::abs(denominator) < Accuracy) { + lambda *= lambda_factor; + continue; + } + + const double delta_t = -gradient / denominator; + + if (norm_2(delta_t * derivatives[1]) < Accuracy) { + return tangent_cos < Accuracy; + } + + CoordinatesArrayType trial_local_coordinates = rProjectedPointLocalCoordinates; + + trial_local_coordinates[0] += delta_t; + + int check = rGeometry.ClosestPointLocalToLocalSpace( + trial_local_coordinates, + trial_local_coordinates); + + if (check == 0) { + if (projection_reset_to_boundary) { + return false; + } else { + projection_reset_to_boundary = true; + } + } + + std::vector> trial_derivatives(1); + + rGeometry.GlobalSpaceDerivatives(trial_derivatives, trial_local_coordinates, 0); + + const array_1d trial_distance_vector = trial_derivatives[0] - rPointGlobalCoordinates; + + const double trial_distance = norm_2(trial_distance_vector); + + if (trial_distance < distance) { + rProjectedPointLocalCoordinates = trial_local_coordinates; + rProjectedPointGlobalCoordinates = trial_derivatives[0]; + + lambda /= lambda_factor; + lambda = std::max(lambda, 1e-14); + + step_accepted = true; + break; + } else { + lambda *= lambda_factor; + + if (lambda > max_lambda) { + return false; + } + } + } + + if (!step_accepted) { + return false; + } + } + + return false; + } + /* * @brief Returns the projection of a point onto a Nurbs surface * geometry using the Newton-Rapshon iterative method @@ -251,6 +395,148 @@ class ProjectionNurbsGeometryUtilities return false; } + + /* + * @brief Returns the closest-point projection of a point onto a Nurbs surface + * geometry using a Levenberg-Marquardt iterative method. + * @param rProjectedPointLocalCoordinates Initial guess for the iterative algorithm. + * This is overwritten by the local coordinates of the projected point + * onto the Nurbs surface geometry. + * @param rPointGlobalCoordinates The global coordinates of the point to be + * projected onto the Nurbs surface geometry. + * @param rProjectedPointGlobalCoordinates The global coordinates of the + * projected point on the Nurbs surface geometry. This is overwritten + * in case the projection is successful. + * @param rNurbsSurface The Nurbs surface geometry onto which the point is + * to be projected. + * @param MaxIterations Maximum number of iterations for the + * Levenberg-Marquardt algorithm. + * @param Accuracy Accuracy used for the distance, orthogonality, and step-size + * convergence checks. + */ + template + static bool LevenbergMarquardtSurface( + CoordinatesArrayType& rProjectedPointLocalCoordinates, + const CoordinatesArrayType& rPointGlobalCoordinates, + CoordinatesArrayType& rProjectedPointGlobalCoordinates, + const NurbsSurfaceGeometry& rNurbsSurface, + const int MaxIterations = 30, + const double Accuracy = 1e-6) + { + double lambda = 1e-8; + const double lambda_factor = 10.0; + const double max_lambda = 1e12; + // Orthogonality condition + const double orthogonality_tolerance = 1e-4; + + for (int i = 0; i < MaxIterations; ++i) { + + // Compute position and first derivatives only + std::vector> s; + rNurbsSurface.GlobalSpaceDerivatives(s, rProjectedPointLocalCoordinates, 1); + + rProjectedPointGlobalCoordinates = s[0]; + + const array_1d distance_vector = s[0] - rPointGlobalCoordinates; + + const double distance = norm_2(distance_vector); + + if (distance < Accuracy) { + return true; + } + + const double norm_su = norm_2(s[1]); + const double norm_sv = norm_2(s[2]); + + if (norm_su < Accuracy || norm_sv < Accuracy) { + return false; + } + + // Gradient of 1/2 ||S(u,v)-x||^2 + const double g_u = inner_prod(s[1], distance_vector); + const double g_v = inner_prod(s[2], distance_vector); + + const double xi_cos = std::abs(g_u) / (norm_su * distance); + + const double eta_cos = std::abs(g_v) / (norm_sv * distance); + + if (xi_cos < orthogonality_tolerance && eta_cos < orthogonality_tolerance) { + return true; + } + + // Gauss-Newton matrix J^T J with LM damping + const double a_00 = inner_prod(s[1], s[1]); + const double a_01 = inner_prod(s[1], s[2]); + const double a_11 = inner_prod(s[2], s[2]); + + bool step_accepted = false; + + for (int lm_it = 0; lm_it < 10; ++lm_it) { + + const double j_00 = a_00 + lambda; + const double j_01 = a_01; + const double j_11 = a_11 + lambda; + + const double det_j = j_00 * j_11 - j_01 * j_01; + + if (std::abs(det_j) < Accuracy * (std::abs(j_00 * j_11) + std::abs(j_01 * j_01))) { + lambda *= lambda_factor; + continue; + } + + // Solve: + // (J^T J + lambda I) d = -g + const double d_u = + (-g_u * j_11 + g_v * j_01) / det_j; + + const double d_v = + ( g_u * j_01 - g_v * j_00) / det_j; + + if (norm_2(d_u * s[1] + d_v * s[2]) < Accuracy) { + return xi_cos < orthogonality_tolerance && eta_cos < orthogonality_tolerance; + } + + CoordinatesArrayType trial_local_coordinates = + rProjectedPointLocalCoordinates; + + trial_local_coordinates[0] += d_u; + trial_local_coordinates[1] += d_v; + + rNurbsSurface.DomainIntervalU().IsInside(trial_local_coordinates[0]); + rNurbsSurface.DomainIntervalV().IsInside(trial_local_coordinates[1]); + + std::vector> trial_s; + rNurbsSurface.GlobalSpaceDerivatives(trial_s, trial_local_coordinates, 0); + + const array_1d trial_distance_vector = trial_s[0] - rPointGlobalCoordinates; + + const double trial_distance = norm_2(trial_distance_vector); + + if (trial_distance < distance) { + rProjectedPointLocalCoordinates = trial_local_coordinates; + rProjectedPointGlobalCoordinates = trial_s[0]; + + lambda /= lambda_factor; + lambda = std::max(lambda, 1e-14); + + step_accepted = true; + break; + } else { + lambda *= lambda_factor; + + if (lambda > max_lambda) { + return false; + } + } + } + + if (!step_accepted) { + return false; + } + } + + return false; + } }; } // namespace Kratos From 4b3f69f7bf668d5cd8b6606759f0d8acdd3c7162 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Mon, 8 Jun 2026 17:45:35 +0200 Subject: [PATCH 37/50] test the new projection algorithms --- .../test_projection_nurbs_geometry.cpp | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/kratos/tests/cpp_tests/geometries/test_projection_nurbs_geometry.cpp b/kratos/tests/cpp_tests/geometries/test_projection_nurbs_geometry.cpp index 468a03a55181..32be701b0a67 100644 --- a/kratos/tests/cpp_tests/geometries/test_projection_nurbs_geometry.cpp +++ b/kratos/tests/cpp_tests/geometries/test_projection_nurbs_geometry.cpp @@ -117,6 +117,95 @@ typedef Node NodeType; points, p, q, knot_vector_u, knot_vector_v, weights); } + NurbsSurfaceGeometry<3, PointerVector> GenerateReferenceC0HemisphereGeometry(ModelPart& rModelPart) + { + PointerVector points; + + points.push_back(rModelPart.CreateNewNode(1, 0.0, 0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(2, 0.0, 0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(3, 0.0, 0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(4, 0.0, 0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(5, 0.0, 0.25, 0.0)); + + points.push_back(rModelPart.CreateNewNode(6, -0.25, 0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(7, -0.25, 0.25, 0.25)); + points.push_back(rModelPart.CreateNewNode(8, -1.5308084989341915e-17, 0.25, 0.25)); + points.push_back(rModelPart.CreateNewNode(9, 0.24999999999999994, 0.25, 0.25)); + points.push_back(rModelPart.CreateNewNode(10, 0.25, 0.25, 3.061616997868383e-17)); + + points.push_back(rModelPart.CreateNewNode(11, -0.25, 1.5308084989341915e-17, 0.0)); + points.push_back(rModelPart.CreateNewNode(12, -0.25, 1.5308084989341915e-17, 0.25)); + points.push_back(rModelPart.CreateNewNode(13, -1.5308084989341915e-17, 1.5308084989341915e-17, 0.25)); + points.push_back(rModelPart.CreateNewNode(14, 0.24999999999999994, 1.5308084989341915e-17, 0.25)); + points.push_back(rModelPart.CreateNewNode(15, 0.25, 1.5308084989341915e-17, 3.061616997868383e-17)); + + points.push_back(rModelPart.CreateNewNode(16, -0.25, -0.24999999999999994, 0.0)); + points.push_back(rModelPart.CreateNewNode(17, -0.25, -0.24999999999999994, 0.25)); + points.push_back(rModelPart.CreateNewNode(18, -1.5308084989341915e-17, -0.24999999999999994, 0.25)); + points.push_back(rModelPart.CreateNewNode(19, 0.24999999999999994, -0.24999999999999994, 0.25)); + points.push_back(rModelPart.CreateNewNode(20, 0.25, -0.24999999999999994, 3.061616997868383e-17)); + + points.push_back(rModelPart.CreateNewNode(21, 0.0, -0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(22, 0.0, -0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(23, 0.0, -0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(24, 0.0, -0.25, 0.0)); + points.push_back(rModelPart.CreateNewNode(25, 0.0, -0.25, 0.0)); + + Vector knot_vector_u = ZeroVector(8); + knot_vector_u[0] = 0.0; + knot_vector_u[1] = 0.0; + knot_vector_u[2] = 0.0; + knot_vector_u[3] = 0.39269908169872414; + knot_vector_u[4] = 0.39269908169872414; + knot_vector_u[5] = 0.78539816339744828; + knot_vector_u[6] = 0.78539816339744828; + knot_vector_u[7] = 0.78539816339744828; + + Vector knot_vector_v = knot_vector_u; + + const int p = 2; + const int q = 2; + + Vector weights = ZeroVector(25); + weights[0] = 1.0; + weights[1] = 0.70710678118654757; + weights[2] = 1.0; + weights[3] = 0.70710678118654757; + weights[4] = 1.0; + + weights[5] = 0.70710678118654757; + weights[6] = 0.50000000000000011; + weights[7] = 0.70710678118654757; + weights[8] = 0.50000000000000011; + weights[9] = 0.70710678118654757; + + weights[10] = 1.0; + weights[11] = 0.70710678118654757; + weights[12] = 1.0; + weights[13] = 0.70710678118654757; + weights[14] = 1.0; + + weights[15] = 0.70710678118654757; + weights[16] = 0.50000000000000011; + weights[17] = 0.70710678118654757; + weights[18] = 0.50000000000000011; + weights[19] = 0.70710678118654757; + + weights[20] = 1.0; + weights[21] = 0.70710678118654757; + weights[22] = 1.0; + weights[23] = 0.70710678118654757; + weights[24] = 1.0; + + return NurbsSurfaceGeometry<3, PointerVector>( + points, + p, + q, + knot_vector_u, + knot_vector_v, + weights); + } + /// Tests KRATOS_TEST_CASE_IN_SUITE(NurbsCurveGeometryProjection2d, KratosCoreNurbsGeometriesFastSuite) { auto curve = GenerateReferenceCurveForProjection2d(); @@ -174,6 +263,78 @@ typedef Node NodeType; KRATOS_EXPECT_VECTOR_NEAR(projected_point_extreme, projected_point_extreme1, TOLERANCE); } + KRATOS_TEST_CASE_IN_SUITE(NurbsCurveGeometryLevenbergMarquardtProjection2d, KratosCoreNurbsGeometriesFastSuite) + { + auto curve = GenerateReferenceCurveForProjection2d(); + + array_1d point; + point[0] = -2.0; + point[1] = 1.0; + point[2] = 0.0; + + array_1d projected_point = ZeroVector(3); + + // Test 1: Initial guess at the center of the parameter domain + array_1d parameter = ZeroVector(3); + + bool is_converged_1 = ProjectionNurbsGeometryUtilities::LevenbergMarquardtCurve(parameter, point, projected_point, curve, 50, 1e-7); + + KRATOS_EXPECT_EQ(is_converged_1, true); + + KRATOS_EXPECT_NEAR(parameter[0],0.099395977882318, TOLERANCE); + + std::vector projected_point_expected_1 = { + -0.129744540301921, + -0.044240249340891, + 0.0 + }; + + KRATOS_EXPECT_VECTOR_NEAR(projected_point, projected_point_expected_1, TOLERANCE); + + + // Test 2: Initial guess at the left boundary + parameter = ZeroVector(3); + parameter[0] = curve.DomainInterval().MinParameter(); + + bool is_converged_2 = ProjectionNurbsGeometryUtilities::LevenbergMarquardtCurve(parameter, point, projected_point, curve, 50, 1e-7); + + KRATOS_EXPECT_EQ(is_converged_2, true); + + KRATOS_EXPECT_NEAR(parameter[0], -0.788227217287371, TOLERANCE); + + std::vector projected_point_expected_2 = { + -4.694701201131293, + -3.571229085898834, + 0.0 + }; + + KRATOS_EXPECT_VECTOR_NEAR(projected_point, projected_point_expected_2, TOLERANCE); + + // Test 3: Projection of a point already located on the curve end + array_1d curve_extreme_point{ + -9.0, + -2.0, + 0.0 + }; + + array_1d projected_point_extreme = ZeroVector(3); + array_1d parameter_extreme = ZeroVector(3); + + bool is_converged_3 = ProjectionNurbsGeometryUtilities::LevenbergMarquardtCurve(parameter_extreme, curve_extreme_point, projected_point_extreme, curve, 50, 1e-7); + + KRATOS_EXPECT_EQ(is_converged_3, true); + + KRATOS_EXPECT_NEAR(parameter_extreme[0], -1.0, TOLERANCE); + + array_1d projected_point_expected_3{ + -9.0, + -2.0, + 0.0 + }; + + KRATOS_EXPECT_VECTOR_NEAR(projected_point_extreme, projected_point_expected_3, TOLERANCE); + } + KRATOS_TEST_CASE_IN_SUITE(NurbsSurfaceGeometryProjection3d, KratosCoreNurbsGeometriesFastSuite) { auto surface = GenerateReferenceUnrefinedQuarterSphereGeometry(); @@ -225,5 +386,79 @@ typedef Node NodeType; KRATOS_EXPECT_VECTOR_NEAR(projected_point, projected_point_expected2, TOLERANCE); } + KRATOS_TEST_CASE_IN_SUITE(NurbsSurfaceGeometryLevenbergMarquardtProjection3d, KratosCoreNurbsGeometriesFastSuite) + { + auto surface = GenerateReferenceUnrefinedQuarterSphereGeometry(); + + array_1d projected_point = ZeroVector(3); + array_1d parameter = ZeroVector(3); + array_1d point; + + const double lm_tolerance = 1e-5; + + std::vector projected_point_expected1 = { + 0.043301282246217, + -0.043301264160723, + 0.043301264160723 + }; + + std::vector projected_point_expected2 = { + 0.074813167561162, + -0.003740986465195, + 0.003740986465195 + }; + + // Projection far from the singularity + point[0] = 0.06; + point[1] = -0.06; + point[2] = 0.06; + + parameter[0] = 0.5; + parameter[1] = 0.5; + + bool is_converged_1 = ProjectionNurbsGeometryUtilities::LevenbergMarquardtSurface(parameter, point, projected_point, surface, 100, 1e-6); + + KRATOS_EXPECT_EQ(is_converged_1, true); + KRATOS_EXPECT_NEAR(parameter[0], 0.397197796315686, lm_tolerance); + KRATOS_EXPECT_NEAR(parameter[1], 0.5, lm_tolerance); + KRATOS_EXPECT_VECTOR_NEAR(projected_point, projected_point_expected1, lm_tolerance); + } + + KRATOS_TEST_CASE_IN_SUITE(NurbsSurfaceGeometryC0HemisphereProjectionNewtonVsLevenbergMarquardt, KratosCoreNurbsGeometriesFastSuite) + { + Model current_model; + ModelPart& model_part = current_model.CreateModelPart("TestModelPart"); + + auto surface = GenerateReferenceC0HemisphereGeometry(model_part); + + array_1d point; + point[0] = -0.25029993; + point[1] = 0.00097306; + point[2] = 0.10123734; + + array_1d projected_point_nr = ZeroVector(3); + array_1d projected_point_lm = ZeroVector(3); + + array_1d parameter_nr = ZeroVector(3); + array_1d parameter_lm = ZeroVector(3); + + parameter_nr[0] = 0.39269908169872414; + parameter_nr[1] = 0.39269908169872414; + + parameter_lm[0] = 0.39269908169872414; + parameter_lm[1] = 0.39269908169872414; + + // Newton-Raphson fails here + const bool is_converged_nr = ProjectionNurbsGeometryUtilities::NewtonRaphsonSurface(parameter_nr, point, projected_point_nr, surface, 20, 1e-6); + // LevenbergMarquardt works here + const bool is_converged_lm = ProjectionNurbsGeometryUtilities::LevenbergMarquardtSurface(parameter_lm, point, projected_point_lm, surface, 50, 1e-6); + + KRATOS_EXPECT_EQ(is_converged_nr, false); + KRATOS_EXPECT_EQ(is_converged_lm, true); + + KRATOS_EXPECT_NEAR(parameter_lm[0], 0.1, 1e-5); + KRATOS_EXPECT_NEAR(parameter_lm[1], 0.39169908169872414, 1e-5); + } + } // namespace Testing. } // namespace Kratos. From b335f5902267c1246dd369a8eaf6690a489e69cd Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Mon, 8 Jun 2026 17:46:12 +0200 Subject: [PATCH 38/50] modify cad io modeler and cad json input to take into account the projection algorithm --- kratos/input_output/cad_json_input.h | 128 +++++++++++++++------------ kratos/modeler/cad_io_modeler.cpp | 32 ++++++- 2 files changed, 99 insertions(+), 61 deletions(-) diff --git a/kratos/input_output/cad_json_input.h b/kratos/input_output/cad_json_input.h index ecf65d4899cf..b470cf2b0f96 100644 --- a/kratos/input_output/cad_json_input.h +++ b/kratos/input_output/cad_json_input.h @@ -88,18 +88,22 @@ class CadJsonInput : public IO /// Constructor with path to input file. CadJsonInput( const std::string& rDataFileName, - SizeType EchoLevel = 0) + SizeType EchoLevel = 0, + ProjectionAlgorithm ProjectionAlgorithmType = ProjectionAlgorithm::NewtonRaphson) : mEchoLevel(EchoLevel) + , mProjectionAlgorithm(ProjectionAlgorithmType) { - mCadJsonParameters = ReadParamatersFile(rDataFileName, EchoLevel); + mCadJsonParameters = ReadParametersFile(rDataFileName, EchoLevel); } /// Constructor with KratosParameters. CadJsonInput( Parameters CadJsonParameters, - SizeType EchoLevel = 0) + SizeType EchoLevel = 0, + ProjectionAlgorithm ProjectionAlgorithmType = ProjectionAlgorithm::NewtonRaphson) : mCadJsonParameters(CadJsonParameters) , mEchoLevel(EchoLevel) + , mProjectionAlgorithm(ProjectionAlgorithmType) { } @@ -113,7 +117,7 @@ class CadJsonInput : public IO /// Adds all CAD geometries to the herin provided model_part. void ReadModelPart(ModelPart& rModelPart) override { - ReadGeometryModelPart(mCadJsonParameters, rModelPart, mEchoLevel); + ReadGeometryModelPart(mCadJsonParameters, rModelPart, mProjectionAlgorithm, mEchoLevel); } ///@} @@ -126,12 +130,13 @@ class CadJsonInput : public IO static void ReadGeometryModelPart( const Parameters rCadJsonParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(rCadJsonParameters.Has("breps")) << "Missing \"breps\" section" << std::endl; - ReadBreps(rCadJsonParameters["breps"], rModelPart, EchoLevel); + ReadBreps(rCadJsonParameters["breps"], rModelPart, ProjectionAlgorithmType, EchoLevel); } ///@} @@ -141,40 +146,32 @@ class CadJsonInput : public IO static void ReadBreps( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { - for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) - { + for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) { KRATOS_INFO_IF("ReadBreps", (EchoLevel > 0)) << "Reading Brep \"" << GetIdOrName(rParameters[brep_index]) << "\" - faces." << std::endl; - - if (rParameters[brep_index].Has("faces")) - { - ReadBrepSurfaces(rParameters[brep_index]["faces"], rModelPart, EchoLevel); + if (rParameters[brep_index].Has("faces")) { + ReadBrepSurfaces(rParameters[brep_index]["faces"], rModelPart, ProjectionAlgorithmType, EchoLevel); } } - for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) - { + for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) { KRATOS_INFO_IF("ReadBreps", (EchoLevel > 0)) << "Reading Brep \"" << GetIdOrName(rParameters[brep_index]) << "\" - edges." << std::endl; - - if (rParameters[brep_index].Has("edges")) - { - ReadBrepCurveOnSurfaces(rParameters[brep_index]["edges"], rModelPart, EchoLevel); + if (rParameters[brep_index].Has("edges")) { + ReadBrepCurveOnSurfaces(rParameters[brep_index]["edges"], rModelPart, ProjectionAlgorithmType, EchoLevel); } } - for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) - { + for (IndexType brep_index = 0; brep_index < rParameters.size(); brep_index++) { KRATOS_INFO_IF("ReadBreps", (EchoLevel > 0)) << "Reading Brep \"" << GetIdOrName(rParameters[brep_index]) << "\" - points." << std::endl; - - if (rParameters[brep_index].Has("vertices")) - { + if (rParameters[brep_index].Has("vertices")) { ReadPointsOnGeometries(rParameters[brep_index]["vertices"], rModelPart, EchoLevel); } } @@ -187,6 +184,7 @@ class CadJsonInput : public IO static void ReadBrepSurfaces( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(rParameters.IsArray()) @@ -195,15 +193,15 @@ class CadJsonInput : public IO KRATOS_INFO_IF("ReadBrepSurfaces", EchoLevel > 2) << "Reading " << rParameters.size() << " BrepSurfaces..." << std::endl; - for (IndexType brep_surface_i = 0; brep_surface_i < rParameters.size(); ++brep_surface_i) - { - ReadBrepSurface(rParameters[brep_surface_i], rModelPart, EchoLevel); + for (IndexType brep_surface_i = 0; brep_surface_i < rParameters.size(); ++brep_surface_i) { + ReadBrepSurface(rParameters[brep_surface_i], rModelPart, ProjectionAlgorithmType, EchoLevel); } } static void ReadBrepSurface( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_INFO_IF("ReadBrepSurface", (EchoLevel > 3)) @@ -216,7 +214,7 @@ class CadJsonInput : public IO << "Missing 'surface' in brep face." << std::endl; auto p_surface(ReadNurbsSurface<3, TNodeType>( - rParameters["surface"], rModelPart, EchoLevel)); + rParameters["surface"], rModelPart, ProjectionAlgorithmType, EchoLevel)); const bool is_trimmed = (rParameters["surface"].Has("is_trimmed")) ? rParameters["surface"]["is_trimmed"].GetBool() @@ -230,7 +228,7 @@ class CadJsonInput : public IO { BrepCurveOnSurfaceLoopArrayType outer_loops, inner_loops; tie(outer_loops, inner_loops) = - ReadBoundaryLoops(rParameters["boundary_loops"], p_surface, rModelPart, EchoLevel); + ReadBoundaryLoops(rParameters["boundary_loops"], p_surface, rModelPart, ProjectionAlgorithmType, EchoLevel); auto p_brep_surface = Kratos::make_shared( @@ -244,7 +242,7 @@ class CadJsonInput : public IO SetIdOrName(rParameters, p_brep_surface); - ReadAndAddEmbeddedEdges(p_brep_surface, rParameters, p_surface, rModelPart, EchoLevel); + ReadAndAddEmbeddedEdges(p_brep_surface, rParameters, p_surface, rModelPart, ProjectionAlgorithmType, EchoLevel); rModelPart.AddGeometry(p_brep_surface); } @@ -261,7 +259,7 @@ class CadJsonInput : public IO SetIdOrName(rParameters, p_brep_surface); - ReadAndAddEmbeddedEdges(p_brep_surface, rParameters, p_surface, rModelPart, EchoLevel); + ReadAndAddEmbeddedEdges(p_brep_surface, rParameters, p_surface, rModelPart, ProjectionAlgorithmType, EchoLevel); rModelPart.AddGeometry(p_brep_surface); } @@ -271,12 +269,12 @@ class CadJsonInput : public IO ///@name Read in Surface Trimming ///@{ - static BrepCurveOnSurfaceLoopType - ReadTrimmingCurveVector( - const Parameters rParameters, - typename NurbsSurfaceType::Pointer pNurbsSurface, - ModelPart& rModelPart, - SizeType EchoLevel = 0) + static BrepCurveOnSurfaceLoopType ReadTrimmingCurveVector( + const Parameters rParameters, + typename NurbsSurfaceType::Pointer pNurbsSurface, + ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, + SizeType EchoLevel = 0) { KRATOS_ERROR_IF(rParameters.size() < 1) << "Trimming curve list has no element." << std::endl; @@ -287,18 +285,18 @@ class CadJsonInput : public IO for (IndexType tc_idx = 0; tc_idx < rParameters.size(); tc_idx++) { trimming_brep_curve_vector[tc_idx] = ReadTrimmingCurve( - rParameters[tc_idx], pNurbsSurface, rModelPart, EchoLevel); + rParameters[tc_idx], pNurbsSurface, rModelPart, ProjectionAlgorithmType, EchoLevel); } return trimming_brep_curve_vector; } - static typename BrepCurveOnSurfaceType::Pointer - ReadTrimmingCurve( - const Parameters rParameters, - typename NurbsSurfaceType::Pointer pNurbsSurface, - ModelPart& rModelPart, - SizeType EchoLevel = 0) + static typename BrepCurveOnSurfaceType::Pointer ReadTrimmingCurve( + const Parameters rParameters, + typename NurbsSurfaceType::Pointer pNurbsSurface, + ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, + SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(rParameters.Has("curve_direction")) << "Missing 'curve_direction' in nurbs curve" << std::endl; @@ -308,7 +306,7 @@ class CadJsonInput : public IO << "Missing 'parameter_curve' in nurbs curve" << std::endl; auto p_trimming_curve(ReadNurbsCurve<2, TEmbeddedNodeType>( - rParameters["parameter_curve"], rModelPart, EchoLevel)); + rParameters["parameter_curve"], rModelPart, ProjectionAlgorithmType, EchoLevel)); KRATOS_ERROR_IF_NOT(rParameters["parameter_curve"].Has("active_range")) << "Missing 'active_range' in parameter_curve, in trimming curve." << std::endl; @@ -331,6 +329,7 @@ class CadJsonInput : public IO const Parameters rParameters, typename NurbsSurfaceType::Pointer pNurbsSurface, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { BrepCurveOnSurfaceLoopArrayType outer_loops; @@ -347,7 +346,7 @@ class CadJsonInput : public IO << "Missing 'trimming_curves' in boundary loops" << bl_idx << " loop." << std::endl; auto trimming_curves(ReadTrimmingCurveVector( - rParameters[bl_idx]["trimming_curves"], pNurbsSurface, rModelPart, EchoLevel)); + rParameters[bl_idx]["trimming_curves"], pNurbsSurface, rModelPart, ProjectionAlgorithmType, EchoLevel)); if (loop_type == "outer") { @@ -374,12 +373,13 @@ class CadJsonInput : public IO const Parameters rParameters, typename NurbsSurfaceType::Pointer pNurbsSurface, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { if (rParameters.Has("embedded_edges")) { if (rParameters["embedded_edges"].size() > 0) { BrepCurveOnSurfaceArrayType embedded_edges(ReadTrimmingCurveVector( - rParameters["embedded_edges"], pNurbsSurface, rModelPart, EchoLevel)); + rParameters["embedded_edges"], pNurbsSurface, rModelPart, ProjectionAlgorithmType, EchoLevel)); pBrepSurface->AddEmbeddedEdges(embedded_edges); } @@ -393,6 +393,7 @@ class CadJsonInput : public IO static void ReadBrepCurveOnSurfaces( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(rParameters.IsArray()) @@ -403,13 +404,14 @@ class CadJsonInput : public IO for (IndexType i = 0; i < rParameters.size(); i++) { - ReadBrepEdge(rParameters[i], rModelPart, EchoLevel); + ReadBrepEdge(rParameters[i], rModelPart, ProjectionAlgorithmType, EchoLevel); } } static void ReadBrepEdge( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(HasIdOrName(rParameters)) @@ -419,7 +421,7 @@ class CadJsonInput : public IO { if (rParameters["topology"].size() == 0) { - ReadBrepCurve(rParameters, rModelPart, EchoLevel); + ReadBrepCurve(rParameters, rModelPart, ProjectionAlgorithmType, EchoLevel); } else if (rParameters["topology"].size() == 1) { @@ -434,6 +436,7 @@ class CadJsonInput : public IO static void ReadBrepCurve( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType, SizeType EchoLevel = 0) { KRATOS_ERROR_IF_NOT(HasIdOrName(rParameters)) @@ -446,7 +449,7 @@ class CadJsonInput : public IO << "Missing '3d_curve' in brep curve." << std::endl; auto p_curve = ReadNurbsCurve<3, TNodeType>( - rParameters["3d_curve"], rModelPart, EchoLevel); + rParameters["3d_curve"], rModelPart, ProjectionAlgorithmType, EchoLevel); auto p_brep_curve = Kratos::make_shared(p_curve); @@ -630,10 +633,11 @@ class CadJsonInput : public IO */ template static typename NurbsCurveGeometry>::Pointer - ReadNurbsCurve( - const Parameters rParameters, - ModelPart& rModelPart, - SizeType EchoLevel = 0) + ReadNurbsCurve( + const Parameters rParameters, + ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType = ProjectionAlgorithm::NewtonRaphson, + SizeType EchoLevel = 0) { bool is_rational = true; if (rParameters.Has("is_rational")) { @@ -664,18 +668,20 @@ class CadJsonInput : public IO Vector control_point_weights = ReadControlPointWeightVector( rParameters["control_points"]); - return Kratos::make_shared>>( + return Kratos::make_shared>>( NurbsCurveGeometry>( control_points, polynomial_degree, knot_vector, - control_point_weights)); + control_point_weights, + ProjectionAlgorithmType)); } typename NurbsCurveGeometry>::Pointer p_nurbs_curve( new NurbsCurveGeometry>( control_points, polynomial_degree, - knot_vector)); + knot_vector, + ProjectionAlgorithmType)); return p_nurbs_curve; } @@ -702,6 +708,7 @@ class CadJsonInput : public IO ReadNurbsSurface( const Parameters rParameters, ModelPart& rModelPart, + ProjectionAlgorithm ProjectionAlgorithmType = ProjectionAlgorithm::NewtonRaphson, SizeType EchoLevel = 0) { bool is_rational = true; @@ -745,7 +752,8 @@ class CadJsonInput : public IO q, knot_vector_u, knot_vector_v, - control_point_weights); + control_point_weights, + ProjectionAlgorithmType); } typename NurbsSurfaceGeometry>::Pointer p_nurbs_surface( new NurbsSurfaceGeometry>( @@ -753,7 +761,8 @@ class CadJsonInput : public IO p, q, knot_vector_u, - knot_vector_v)); + knot_vector_v, + ProjectionAlgorithmType)); return p_nurbs_surface; } @@ -932,7 +941,7 @@ class CadJsonInput : public IO } /// Reads in a json formatted file and returns its KratosParameters instance. - static Parameters ReadParamatersFile( + static Parameters ReadParametersFile( const std::string& rDataFileName, SizeType EchoLevel = 0) { @@ -944,7 +953,7 @@ class CadJsonInput : public IO std::ifstream infile(data_file_name); KRATOS_ERROR_IF_NOT(infile.good()) << "CAD geometry file: " << data_file_name << " cannot be found." << std::endl; - KRATOS_INFO_IF("ReadParamatersFile", EchoLevel > 3) + KRATOS_INFO_IF("ReadParametersFile", EchoLevel > 3) << "Reading file: \"" << data_file_name << "\"" << std::endl; std::stringstream buffer; @@ -959,6 +968,7 @@ class CadJsonInput : public IO Parameters mCadJsonParameters; int mEchoLevel; + ProjectionAlgorithm mProjectionAlgorithm = ProjectionAlgorithm::NewtonRaphson; ///@} }; // Class CadJsonInput diff --git a/kratos/modeler/cad_io_modeler.cpp b/kratos/modeler/cad_io_modeler.cpp index 3ea1d238b159..4d00c57aa16b 100644 --- a/kratos/modeler/cad_io_modeler.cpp +++ b/kratos/modeler/cad_io_modeler.cpp @@ -13,6 +13,7 @@ #include "cad_io_modeler.h" #include "input_output/cad_json_input.h" #include "input_output/cad_json_output.h" +#include "utilities/nurbs_utilities/projection_nurbs_geometry_utilities.h" namespace Kratos @@ -24,7 +25,9 @@ namespace Kratos { KRATOS_ERROR_IF_NOT(mParameters.Has("cad_model_part_name")) << "Missing \"cad_model_part_name\" in CadIoModeler Parameters." << std::endl; + const std::string cad_model_part_name = mParameters["cad_model_part_name"].GetString(); + ModelPart& cad_model_part = mpModel->HasModelPart(cad_model_part_name) ? mpModel->GetModelPart(cad_model_part_name) : mpModel->CreateModelPart(cad_model_part_name); @@ -33,10 +36,35 @@ namespace Kratos ? mParameters["geometry_file_name"].GetString() : "geometry.cad.json"; - KRATOS_INFO_IF("::[CadIoModeler]::", mEchoLevel > 0) << "Importing Cad Model from: " << DataFileName << std::endl; + KRATOS_INFO_IF("::[CadIoModeler]::", mEchoLevel > 0) + << "Importing Cad Model from: " << DataFileName << std::endl; + + ProjectionAlgorithm projection_algorithm = + ProjectionAlgorithm::NewtonRaphson; + + if (mParameters.Has("projection_algorithm")) { + const std::string algorithm_name = + mParameters["projection_algorithm"].GetString(); + + if (algorithm_name == "newton_raphson") { + projection_algorithm = ProjectionAlgorithm::NewtonRaphson; + } else if (algorithm_name == "levenberg_marquardt") { + projection_algorithm = ProjectionAlgorithm::LevenbergMarquardt; + } else { + KRATOS_ERROR + << "Unknown projection algorithm \"" + << algorithm_name + << "\". Available options are:" + << "\n - newton_raphson" + << "\n - levenberg_marquardt" + << std::endl; + } + } CadJsonInput( - DataFileName, mEchoLevel).ReadModelPart(cad_model_part); + DataFileName, + mEchoLevel, + projection_algorithm).ReadModelPart(cad_model_part); } void CadIoModeler::SetupModelPart() From ce72add074720033eeed9a2a6624ecac6582bde5 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Camarotti Date: Mon, 8 Jun 2026 17:46:33 +0200 Subject: [PATCH 39/50] incorporate changes in the geometries --- kratos/geometries/brep_curve_on_surface.h | 15 ++++++-- kratos/geometries/nurbs_curve_geometry.h | 30 ++++++++++++++-- .../nurbs_curve_on_surface_geometry.h | 15 ++++++-- kratos/geometries/nurbs_surface_geometry.h | 36 ++++++++++++++++--- 4 files changed, 84 insertions(+), 12 deletions(-) diff --git a/kratos/geometries/brep_curve_on_surface.h b/kratos/geometries/brep_curve_on_surface.h index 4da3c62228ec..f80454e3e0a5 100644 --- a/kratos/geometries/brep_curve_on_surface.h +++ b/kratos/geometries/brep_curve_on_surface.h @@ -431,12 +431,23 @@ class BrepCurveOnSurface { CoordinatesArrayType point_global_coordinates; - return ProjectionNurbsGeometryUtilities::NewtonRaphsonCurve( + if (mpCurveOnSurface->pGetCurve()->GetProjectionAlgorithm() == ProjectionAlgorithm::NewtonRaphson) { + return ProjectionNurbsGeometryUtilities::NewtonRaphsonCurve( + rProjectedPointLocalCoordinates, + rPointGlobalCoordinates, + point_global_coordinates, + *this, + 20, + Tolerance); + } + + return ProjectionNurbsGeometryUtilities::LevenbergMarquardtCurve( rProjectedPointLocalCoordinates, rPointGlobalCoordinates, point_global_coordinates, *this, - 20, Tolerance); + 50, + Tolerance); } ///@} diff --git a/kratos/geometries/nurbs_curve_geometry.h b/kratos/geometries/nurbs_curve_geometry.h index 3ac08e986a97..64943f23b506 100644 --- a/kratos/geometries/nurbs_curve_geometry.h +++ b/kratos/geometries/nurbs_curve_geometry.h @@ -64,10 +64,12 @@ class NurbsCurveGeometry : public GeometryGetProjectionAlgorithm() == ProjectionAlgorithm::NewtonRaphson) { + return ProjectionNurbsGeometryUtilities::NewtonRaphsonCurve( + rProjectedPointLocalCoordinates, + rPointGlobalCoordinates, + point_global_coordinates, + *this, + 20, + Tolerance); + } + + return ProjectionNurbsGeometryUtilities::LevenbergMarquardtCurve( rProjectedPointLocalCoordinates, rPointGlobalCoordinates, point_global_coordinates, *this, - 20, Tolerance); + 50, + Tolerance); } ///@} diff --git a/kratos/geometries/nurbs_surface_geometry.h b/kratos/geometries/nurbs_surface_geometry.h index 9c746541cfdf..245bf5f18732 100644 --- a/kratos/geometries/nurbs_surface_geometry.h +++ b/kratos/geometries/nurbs_surface_geometry.h @@ -70,12 +70,14 @@ class NurbsSurfaceGeometry : public Geometry with the coordinates in working space @@ -1001,6 +1026,7 @@ class NurbsSurfaceGeometry : public Geometry Date: Mon, 8 Jun 2026 17:49:29 +0200 Subject: [PATCH 40/50] solve bug --- kratos/geometries/nurbs_curve_geometry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kratos/geometries/nurbs_curve_geometry.h b/kratos/geometries/nurbs_curve_geometry.h index 64943f23b506..9e542e20e999 100644 --- a/kratos/geometries/nurbs_curve_geometry.h +++ b/kratos/geometries/nurbs_curve_geometry.h @@ -401,7 +401,7 @@ class NurbsCurveGeometry : public Geometry Date: Tue, 9 Jun 2026 15:29:17 +0200 Subject: [PATCH 41/50] [GeoMechanicsApplication] Make tension cut off truly optional for Mohr Coulomb model (#14467) --- .../custom_constitutive/README.md | 12 +- ...sion_cut_off_impl.cpp => coulomb_impl.cpp} | 193 ++++++++++-------- ..._tension_cut_off_impl.h => coulomb_impl.h} | 20 +- ..._cut_off.cpp => interface_coulomb_law.cpp} | 84 ++++---- ...sion_cut_off.h => interface_coulomb_law.h} | 22 +- ...ension_cutoff.cpp => mohr_coulomb_law.cpp} | 95 ++++----- ...th_tension_cutoff.h => mohr_coulomb_law.h} | 22 +- .../apply_c_phi_reduction_process.cpp | 7 +- .../constitutive_law_utilities.cpp | 11 + .../constitutive_law_utilities.h | 3 + .../geo_mechanics_application.cpp | 11 +- .../geo_mechanics_application.h | 11 +- .../geo_mechanics_application_variables.cpp | 1 + .../geo_mechanics_application_variables.h | 1 + .../MaterialParameters_stage2.json | 3 +- .../mohr_coulomb/MaterialParameters.json | 48 ++--- ...off.cpp => test_interface_coulomb_law.cpp} | 76 ++++--- ...n_cutoff.cpp => test_mohr_coulomb_law.cpp} | 140 +++++++------ ...eo_mechanics_fast_suite_without_kernel.cpp | 1 + .../MaterialParameters.json | 64 +++--- ...ll_installation__expected_results_wall.csv | 10 +- ...irst_excavation__expected_results_wall.csv | 8 +- ...hird_excavation__expected_results_wall.csv | 6 +- .../mohr_coulomb/MaterialParameters.json | 3 +- .../mohr_coulomb/MaterialParameters.json | 3 +- .../drained/MaterialParameters.json | 3 +- .../common/MaterialParameters2D.json | 3 +- .../common/MaterialParameters3D.json | 3 +- .../MaterialParameters.json | 3 +- .../MaterialParameters.json | 35 ++-- .../MaterialParameters2D.json | 3 +- 31 files changed, 489 insertions(+), 416 deletions(-) rename applications/GeoMechanicsApplication/custom_constitutive/{coulomb_with_tension_cut_off_impl.cpp => coulomb_impl.cpp} (60%) rename applications/GeoMechanicsApplication/custom_constitutive/{coulomb_with_tension_cut_off_impl.h => coulomb_impl.h} (90%) rename applications/GeoMechanicsApplication/custom_constitutive/{interface_coulomb_with_tension_cut_off.cpp => interface_coulomb_law.cpp} (65%) rename applications/GeoMechanicsApplication/custom_constitutive/{interface_coulomb_with_tension_cut_off.h => interface_coulomb_law.h} (77%) rename applications/GeoMechanicsApplication/custom_constitutive/{mohr_coulomb_with_tension_cutoff.cpp => mohr_coulomb_law.cpp} (66%) rename applications/GeoMechanicsApplication/custom_constitutive/{mohr_coulomb_with_tension_cutoff.h => mohr_coulomb_law.h} (76%) rename applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/{test_interface_coulomb_with_tension_cut_off.cpp => test_interface_coulomb_law.cpp} (90%) rename applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/{test_mohr_coulomb_with_tension_cutoff.cpp => test_mohr_coulomb_law.cpp} (90%) diff --git a/applications/GeoMechanicsApplication/custom_constitutive/README.md b/applications/GeoMechanicsApplication/custom_constitutive/README.md index 8372890701fa..c9d748c72806 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/README.md +++ b/applications/GeoMechanicsApplication/custom_constitutive/README.md @@ -94,7 +94,7 @@ where: This criterion represents a linear envelope in the Mohr stress space, approximating the shear strength of a material under different stress states. For $`F_{MC} \le 0`$ we have elastic behavior, while $`F_{MC} \gt 0`$ corresponds to plastic behavior. -Since the Mohr-Coulomb criterion primarily accounts for shear failure, it does not limit tensile stresses. In geomechanical applications, materials such as rocks and soils have a limited tensile strength . A tension cutoff is imposed as: +Since the Mohr-Coulomb criterion primarily accounts for shear failure, it does not limit tensile stresses. In geomechanical applications, materials such as rocks and soils have a limited tensile strength . Therefore, the Mohr-Coulomb model in the geomechanics application supports an optional tension cutoff, which is imposed as: ```math F_{tc}(\sigma) = \sigma_1 - t_c = 0 @@ -106,6 +106,8 @@ The combination of these two, yields to the following figure: Mohr-Coulomb with tension cutoff +If the tension cutoff is not active, the figure can be simplified. In that case, the corner return coincides with the apex, resulting in the regular failure zone and the adjacent apex return zone, bound by the $\frac{\partial G_{MC}}{\partial \sigma}$ line and the horizontal $\sigma$ axis. + ### 2.2 Implementation Mohr-Coulomb with tension cutoff @@ -123,16 +125,16 @@ To incorporate the Mohr-Coulomb model with tension cutoff in numerical simulatio 4. Evaluate the condition and mapping 4.1. If the trial stress falls in the elastic zone, it stays unchanged. No mapping is applied. - 4.2. If the trial stress falls in the tensile apex return zone. The trial stress then needs to be mapped back to the apex. - 4.3. If the trial stress falls in the tension cutoff zone. The trial stress then needs to be mapped back to the tension cutoff yield surface. - 4.4. If it falls in the tensile corner return zone, then it needs to be mapped to the corner point. + 4.2. If the trial stress falls in the (tensile) apex return zone. The trial stress then needs to be mapped back to the apex. + 4.3. If the trial stress falls in the tension cutoff zone. The trial stress then needs to be mapped back to the tension cutoff yield surface (optional). + 4.4. If it falls in the tensile corner return zone, then it needs to be mapped to the corner point (optional). 4.5. In the case of regular failure zone, then it is mapped back to the Mohr-Coulomb yield surface along the normal direction of flow function. The flow function is defined by ```math G_{MC}(\sigma) = \frac{\sigma_1 - \sigma_3}{2} + \frac{\sigma_1 + \sigma_3}{2} \sin⁡{\psi} ``` where $`\psi`$ is the dilatancy angle. -5. If after mapping, the condidition $`\sigma_1 \ge \sigma_2 \ge \sigma_3`$ is not valid, average the principal stresses of stage 2 and the direction of the mapping and map the principal stresses again. +5. If after mapping, the condition $`\sigma_1 \ge \sigma_2 \ge \sigma_3`$ is not valid, average the principal stresses of stage 2 and the direction of the mapping and map the principal stresses again. - If $`\sigma_1 \le \sigma_2`$ set: ```math diff --git a/applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.cpp b/applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.cpp similarity index 60% rename from applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.cpp rename to applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.cpp index f421cb67f96e..df3545731b7e 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.cpp +++ b/applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.cpp @@ -13,9 +13,10 @@ // Anne van de Graaf // -#include "custom_constitutive/coulomb_with_tension_cut_off_impl.h" +#include "custom_constitutive/coulomb_impl.h" #include "custom_constitutive/principal_stresses.hpp" #include "custom_constitutive/sigma_tau.hpp" +#include "custom_utilities/constitutive_law_utilities.h" #include "custom_utilities/stress_strain_utilities.h" #include "custom_utilities/ublas_utilities.h" #include "geo_mechanics_application_variables.h" @@ -38,13 +39,38 @@ auto CalculatePrincipalStressCorrection(const Geo::PrincipalStresses& rTrialPrin return Geo::PrincipalStresses{prod(subrange(rElasticConstitutiveTensor, 0, 3, 0, 3), dG_dSigma)}; } +std::optional CreateOptionalTensionCutOff(const Properties& rMaterialProperties) +{ + if (ConstitutiveLawUtilities::WantTensionCutOff(rMaterialProperties)) { + return std::make_optional(rMaterialProperties[GEO_TENSILE_STRENGTH]); + } + + KRATOS_WARNING_IF("CoulombImpl", rMaterialProperties.Has(GEO_TENSILE_STRENGTH) && + rMaterialProperties.Has(GEO_ENABLE_TENSION_CUT_OFF) && + !rMaterialProperties[GEO_ENABLE_TENSION_CUT_OFF]) + << "Material property " << GEO_TENSILE_STRENGTH << " is provided but " << GEO_ENABLE_TENSION_CUT_OFF + << " is false. The provided " << GEO_TENSILE_STRENGTH << " value will be ignored. Please set " + << GEO_ENABLE_TENSION_CUT_OFF << " to true to enable the tension cut-off behavior.\n"; + + return std::nullopt; +} + +template +bool IsAdmissibleStressState(const YieldSurfaceType& rYieldSurface, const StressStateType& rTrialStressState) +{ + const auto yield_function_value = rYieldSurface.YieldFunctionValue(rTrialStressState); + const auto tolerance = 1.0e-10 * (1.0 + std::abs(yield_function_value)); + return yield_function_value < tolerance; +} + } // namespace namespace Kratos { -CoulombWithTensionCutOffImpl::CoulombWithTensionCutOffImpl(const Properties& rMaterialProperties) - : mCoulombYieldSurface{rMaterialProperties}, mTensionCutOff{rMaterialProperties[GEO_TENSILE_STRENGTH]} +CoulombImpl::CoulombImpl(const Properties& rMaterialProperties) + : mCoulombYieldSurface{rMaterialProperties}, + mTensionCutOff{CreateOptionalTensionCutOff(rMaterialProperties)} { if (rMaterialProperties.Has(GEO_ABS_YIELD_FUNCTION_TOLERANCE)) { mAbsoluteYieldFunctionValueTolerance = rMaterialProperties[GEO_ABS_YIELD_FUNCTION_TOLERANCE]; @@ -55,27 +81,27 @@ CoulombWithTensionCutOffImpl::CoulombWithTensionCutOffImpl(const Properties& rMa } } -bool CoulombWithTensionCutOffImpl::IsAdmissibleStressState(const Geo::SigmaTau& rTrialTraction) +bool CoulombImpl::IsAdmissibleStressState(const Geo::SigmaTau& rTrialTraction) { return IsAdmissibleStressState<>(rTrialTraction); } -bool CoulombWithTensionCutOffImpl::IsAdmissibleStressState(const Geo::PrincipalStresses& rTrialPrincipalStresses) +bool CoulombImpl::IsAdmissibleStressState(const Geo::PrincipalStresses& rTrialPrincipalStresses) { return IsAdmissibleStressState<>(rTrialPrincipalStresses); } -Geo::SigmaTau CoulombWithTensionCutOffImpl::DoReturnMapping(const Geo::SigmaTau& rTrialTraction, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) +Geo::SigmaTau CoulombImpl::DoReturnMapping(const Geo::SigmaTau& rTrialTraction, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) { auto sigma_tau_to_sigma_tau = [](const Geo::SigmaTau& rTraction) { return rTraction; }; return DoReturnMapping<>(rTrialTraction, sigma_tau_to_sigma_tau, rElasticConstitutiveTensor, AveragingType); } -Geo::PrincipalStresses CoulombWithTensionCutOffImpl::DoReturnMapping(const Geo::PrincipalStresses& rTrialPrincipalStresses, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) +Geo::PrincipalStresses CoulombImpl::DoReturnMapping(const Geo::PrincipalStresses& rTrialPrincipalStresses, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) { auto principal_stresses_to_sigma_tau = [](const Geo::PrincipalStresses& rPrincipalStresses) { return StressStrainUtilities::TransformPrincipalStressesToSigmaTau(rPrincipalStresses); @@ -84,36 +110,33 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::DoReturnMapping(const Geo:: rElasticConstitutiveTensor, AveragingType); } -void CoulombWithTensionCutOffImpl::SaveKappaOfCoulombYieldSurface() +void CoulombImpl::SaveKappaOfCoulombYieldSurface() { mSavedKappaOfCoulombYieldSurface = mCoulombYieldSurface.GetKappa(); } -void CoulombWithTensionCutOffImpl::RestoreKappaOfCoulombYieldSurface() +void CoulombImpl::RestoreKappaOfCoulombYieldSurface() { mCoulombYieldSurface.SetKappa(mSavedKappaOfCoulombYieldSurface); } template -bool CoulombWithTensionCutOffImpl::IsAdmissibleStressState(const StressStateType& rTrialStressState) +bool CoulombImpl::IsAdmissibleStressState(const StressStateType& rTrialStressState) { - const auto coulomb_yield_function_value = mCoulombYieldSurface.YieldFunctionValue(rTrialStressState); - const auto tension_yield_function_value = mTensionCutOff.YieldFunctionValue(rTrialStressState); - constexpr auto tolerance = 1.0e-10; - const auto coulomb_tolerance = tolerance * (1.0 + std::abs(coulomb_yield_function_value)); - const auto tension_tolerance = tolerance * (1.0 + std::abs(tension_yield_function_value)); - - const auto admissible_state = coulomb_yield_function_value < coulomb_tolerance && - tension_yield_function_value < tension_tolerance; - if (admissible_state) mPlasticityStatus = PlasticityStatus::ELASTIC; - return admissible_state; + if (!::IsAdmissibleStressState(mCoulombYieldSurface, rTrialStressState)) return false; + + if (mTensionCutOff && !::IsAdmissibleStressState(*mTensionCutOff, rTrialStressState)) + return false; + + mPlasticityStatus = PlasticityStatus::ELASTIC; + return true; } template -StressStateType CoulombWithTensionCutOffImpl::DoReturnMapping(const StressStateType& rTrialStressState, - const StressStateToSigmaTauFunctionType& rStressStateToSigmaTau, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) +StressStateType CoulombImpl::DoReturnMapping(const StressStateType& rTrialStressState, + const StressStateToSigmaTauFunctionType& rStressStateToSigmaTau, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) { auto result = StressStateType{}; @@ -121,15 +144,17 @@ StressStateType CoulombWithTensionCutOffImpl::DoReturnMapping(const StressStateT auto kappa_start = mCoulombYieldSurface.GetKappa(); for (auto counter = std::size_t{0}; counter < mMaxNumberOfPlasticIterations; ++counter) { - if (IsStressAtTensionApexReturnZone(trial_traction)) { - mPlasticityStatus = PlasticityStatus::TENSION_APEX; - return ReturnStressAtTensionApexReturnZone(rTrialStressState); - } - - if (IsStressAtTensionCutoffReturnZone(trial_traction)) { - mPlasticityStatus = PlasticityStatus::TENSION_CUT_OFF; - return ReturnStressAtTensionCutoffReturnZone(rTrialStressState, - rElasticConstitutiveTensor, AveragingType); + if (mTensionCutOff) { + if (IsStressAtTensionApexReturnZone(trial_traction)) { + mPlasticityStatus = PlasticityStatus::TENSION_APEX; + return ReturnStressAtTensionApexReturnZone(rTrialStressState); + } + + if (IsStressAtTensionCutoffReturnZone(trial_traction)) { + mPlasticityStatus = PlasticityStatus::TENSION_CUT_OFF; + return ReturnStressAtTensionCutoffReturnZone( + rTrialStressState, rElasticConstitutiveTensor, AveragingType); + } } if (IsStressAtCornerReturnZone(trial_traction, AveragingType)) { @@ -152,9 +177,11 @@ StressStateType CoulombWithTensionCutOffImpl::DoReturnMapping(const StressStateT return result; } -Geo::SigmaTau CoulombWithTensionCutOffImpl::CalculateCornerPoint() const +Geo::SigmaTau CoulombImpl::CalculateCornerPoint() const { - const auto tensile_strength = mTensionCutOff.GetTensileStrength(); + if (!mTensionCutOff) return mCoulombYieldSurface.CalculateApex(); + + const auto tensile_strength = mTensionCutOff->GetTensileStrength(); if (const auto apex = mCoulombYieldSurface.CalculateApex(); tensile_strength > apex.Sigma()) return apex; @@ -165,22 +192,22 @@ Geo::SigmaTau CoulombWithTensionCutOffImpl::CalculateCornerPoint() const (cohesion * cos_phi - tensile_strength * sin_phi) / (1.0 - sin_phi)}; } -bool CoulombWithTensionCutOffImpl::IsStressAtTensionApexReturnZone(const Geo::SigmaTau& rTrialTraction) const +bool CoulombImpl::IsStressAtTensionApexReturnZone(const Geo::SigmaTau& rTrialTraction) const { - const auto tensile_strength = mTensionCutOff.GetTensileStrength(); + const auto tensile_strength = mTensionCutOff->GetTensileStrength(); return tensile_strength < mCoulombYieldSurface.CalculateApex().Sigma() && rTrialTraction.Sigma() - rTrialTraction.Tau() - tensile_strength > 0.0; } -bool CoulombWithTensionCutOffImpl::IsStressAtTensionCutoffReturnZone(const Geo::SigmaTau& rTrialTraction) const +bool CoulombImpl::IsStressAtTensionCutoffReturnZone(const Geo::SigmaTau& rTrialTraction) const { const auto corner_point = CalculateCornerPoint(); - return mTensionCutOff.GetTensileStrength() < mCoulombYieldSurface.CalculateApex().Sigma() && + return mTensionCutOff->GetTensileStrength() < mCoulombYieldSurface.CalculateApex().Sigma() && corner_point.Tau() - rTrialTraction.Tau() - corner_point.Sigma() + rTrialTraction.Sigma() > 0.0; } -bool CoulombWithTensionCutOffImpl::IsStressAtCornerReturnZone(const Geo::SigmaTau& rTrialTraction, - Geo::PrincipalStresses::AveragingType AveragingType) const +bool CoulombImpl::IsStressAtCornerReturnZone(const Geo::SigmaTau& rTrialTraction, + Geo::PrincipalStresses::AveragingType AveragingType) const { const auto corner_point = CalculateCornerPoint(); const auto derivative_of_flow_function = @@ -190,13 +217,12 @@ bool CoulombWithTensionCutOffImpl::IsStressAtCornerReturnZone(const Geo::SigmaTa 0.0; } -Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtTensionApexReturnZone(const Geo::SigmaTau&) const +Geo::SigmaTau CoulombImpl::ReturnStressAtTensionApexReturnZone(const Geo::SigmaTau&) const { - return Geo::SigmaTau{mTensionCutOff.GetTensileStrength(), 0.0}; + return Geo::SigmaTau{mTensionCutOff->GetTensileStrength(), 0.0}; } -Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtTensionApexReturnZone( - const Geo::PrincipalStresses& rTrialPrincipalStresses) const +Geo::PrincipalStresses CoulombImpl::ReturnStressAtTensionApexReturnZone(const Geo::PrincipalStresses& rTrialPrincipalStresses) const { return StressStrainUtilities::TransformSigmaTauToPrincipalStresses( ReturnStressAtTensionApexReturnZone( @@ -204,37 +230,35 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtTensionApexRe rTrialPrincipalStresses); } -Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtTensionCutoffReturnZone( - const Geo::SigmaTau& rTrialTraction, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) const +Geo::SigmaTau CoulombImpl::ReturnStressAtTensionCutoffReturnZone(const Geo::SigmaTau& rTrialTraction, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) const { const auto derivative_of_flow_function = - mTensionCutOff.DerivativeOfFlowFunction(rTrialTraction, AveragingType); - const auto lambda = mTensionCutOff.CalculatePlasticMultiplier( + mTensionCutOff->DerivativeOfFlowFunction(rTrialTraction, AveragingType); + const auto lambda = mTensionCutOff->CalculatePlasticMultiplier( rTrialTraction, derivative_of_flow_function, rElasticConstitutiveTensor); return rTrialTraction + Geo::SigmaTau{lambda * prod(rElasticConstitutiveTensor, derivative_of_flow_function)}; } -Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtTensionCutoffReturnZone( +Geo::PrincipalStresses CoulombImpl::ReturnStressAtTensionCutoffReturnZone( const Geo::PrincipalStresses& rTrialPrincipalStresses, const Matrix& rElasticConstitutiveTensor, Geo::PrincipalStresses::AveragingType AveragingType) const { const auto derivative_of_flow_function = - mTensionCutOff.DerivativeOfFlowFunction(rTrialPrincipalStresses, AveragingType); - const auto lambda = mTensionCutOff.CalculatePlasticMultiplier( + mTensionCutOff->DerivativeOfFlowFunction(rTrialPrincipalStresses, AveragingType); + const auto lambda = mTensionCutOff->CalculatePlasticMultiplier( rTrialPrincipalStresses, derivative_of_flow_function, rElasticConstitutiveTensor); return rTrialPrincipalStresses + Geo::PrincipalStresses{lambda * prod(subrange(rElasticConstitutiveTensor, 0, 3, 0, 3), derivative_of_flow_function)}; } -Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailureZone( - const Geo::SigmaTau& rTrialTraction, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) const +Geo::SigmaTau CoulombImpl::ReturnStressAtRegularFailureZone(const Geo::SigmaTau& rTrialTraction, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) const { const auto derivative_of_flow_function = mCoulombYieldSurface.DerivativeOfFlowFunction(rTrialTraction, AveragingType); @@ -244,10 +268,9 @@ Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailureZone( Geo::SigmaTau{lambda * prod(rElasticConstitutiveTensor, derivative_of_flow_function)}; } -Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailureZone( - const Geo::PrincipalStresses& rTrialPrincipalStresses, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) const +Geo::PrincipalStresses CoulombImpl::ReturnStressAtRegularFailureZone(const Geo::PrincipalStresses& rTrialPrincipalStresses, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) const { const auto derivative_of_flow_function = mCoulombYieldSurface.DerivativeOfFlowFunction(rTrialPrincipalStresses, AveragingType); @@ -258,13 +281,12 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailur derivative_of_flow_function)}; } -Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtCornerPoint( - const Geo::PrincipalStresses& rTrialPrincipalStresses, - const Matrix& rElasticConstitutiveTensor, - Geo::PrincipalStresses::AveragingType AveragingType) const +Geo::PrincipalStresses CoulombImpl::ReturnStressAtCornerPoint(const Geo::PrincipalStresses& rTrialPrincipalStresses, + const Matrix& rElasticConstitutiveTensor, + Geo::PrincipalStresses::AveragingType AveragingType) const { if (const auto apex = mCoulombYieldSurface.CalculateApex(); - mTensionCutOff.GetTensileStrength() > apex.Sigma()) + !mTensionCutOff || mTensionCutOff->GetTensileStrength() > apex.Sigma()) return StressStrainUtilities::TransformSigmaTauToPrincipalStresses(apex, rTrialPrincipalStresses); const auto principal_stress_correction_Coulomb = CalculatePrincipalStressCorrection( @@ -273,7 +295,7 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtCornerPoint( StressStrainUtilities::TransformPrincipalStressesToSigmaTau(principal_stress_correction_Coulomb); const auto principal_stress_correction_tension_cut_off = CalculatePrincipalStressCorrection( - rTrialPrincipalStresses, AveragingType, rElasticConstitutiveTensor, mTensionCutOff); + rTrialPrincipalStresses, AveragingType, rElasticConstitutiveTensor, *mTensionCutOff); const auto traction_correction_tension_cut_off = StressStrainUtilities::TransformPrincipalStressesToSigmaTau(principal_stress_correction_tension_cut_off); @@ -290,7 +312,7 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtCornerPoint( const auto b = UblasUtilities::CreateVector( {-1.0 * mCoulombYieldSurface.YieldFunctionValue(rTrialPrincipalStresses), - -1.0 * mTensionCutOff.YieldFunctionValue(rTrialPrincipalStresses)}); + -1.0 * mTensionCutOff->YieldFunctionValue(rTrialPrincipalStresses)}); const auto plastic_multipliers = Vector{prod(A_inverse, b)}; return rTrialPrincipalStresses + @@ -299,30 +321,35 @@ Geo::PrincipalStresses CoulombWithTensionCutOffImpl::ReturnStressAtCornerPoint( plastic_multipliers[1] * principal_stress_correction_tension_cut_off.Values()}; } -Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtCornerPoint( - const Geo::SigmaTau&, const Matrix&, Geo::PrincipalStresses::AveragingType AveragingType) const +Geo::SigmaTau CoulombImpl::ReturnStressAtCornerPoint(const Geo::SigmaTau&, + const Matrix&, + Geo::PrincipalStresses::AveragingType AveragingType) const { KRATOS_DEBUG_ERROR_IF(AveragingType != Geo::PrincipalStresses::AveragingType::NO_AVERAGING) << "When returning the traction to the corner point, averaging of principal stresses is not supported\n"; return CalculateCornerPoint(); } -PlasticityStatus CoulombWithTensionCutOffImpl::GetPlasticityStatus() const -{ - return mPlasticityStatus; -} +PlasticityStatus CoulombImpl::GetPlasticityStatus() const { return mPlasticityStatus; } -void CoulombWithTensionCutOffImpl::save(Serializer& rSerializer) const +void CoulombImpl::save(Serializer& rSerializer) const { rSerializer.save("CoulombYieldSurface", mCoulombYieldSurface); - rSerializer.save("TensionCutOff", mTensionCutOff); + rSerializer.save("HasTensionCutOff", mTensionCutOff.has_value()); + if (mTensionCutOff.has_value()) rSerializer.save("TensionCutOff", *mTensionCutOff); rSerializer.save("PlasticityStatus", static_cast(mPlasticityStatus)); } -void CoulombWithTensionCutOffImpl::load(Serializer& rSerializer) +void CoulombImpl::load(Serializer& rSerializer) { rSerializer.load("CoulombYieldSurface", mCoulombYieldSurface); - rSerializer.load("TensionCutOff", mTensionCutOff); + bool has_tension_cutoff; + rSerializer.load("HasTensionCutOff", has_tension_cutoff); + if (has_tension_cutoff) { + TensionCutoff tension_cutoff; + rSerializer.load("TensionCutoff", tension_cutoff); + mTensionCutOff = std::make_optional(tension_cutoff); + } int plasticity_status; rSerializer.load("PlasticityStatus", plasticity_status); mPlasticityStatus = static_cast(plasticity_status); diff --git a/applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.h b/applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.h similarity index 90% rename from applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.h rename to applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.h index 7b3bbeeca557..9f40d9fe70ef 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/coulomb_with_tension_cut_off_impl.h +++ b/applications/GeoMechanicsApplication/custom_constitutive/coulomb_impl.h @@ -15,6 +15,8 @@ #pragma once +#include + #include "coulomb_yield_surface.h" #include "custom_constitutive/principal_stresses.hpp" #include "geo_mechanics_application_constants.h" @@ -31,11 +33,11 @@ namespace Geo class SigmaTau; } // namespace Geo -class CoulombWithTensionCutOffImpl +class CoulombImpl { public: - CoulombWithTensionCutOffImpl() = default; - explicit CoulombWithTensionCutOffImpl(const Properties& rMaterialProperties); + CoulombImpl() = default; + explicit CoulombImpl(const Properties& rMaterialProperties); [[nodiscard]] bool IsAdmissibleStressState(const Geo::SigmaTau& rTrialTraction); [[nodiscard]] bool IsAdmissibleStressState(const Geo::PrincipalStresses& rTrialPrincipalStresses); @@ -52,12 +54,12 @@ class CoulombWithTensionCutOffImpl [[nodiscard]] PlasticityStatus GetPlasticityStatus() const; private: - CoulombYieldSurface mCoulombYieldSurface; - TensionCutoff mTensionCutOff; - double mSavedKappaOfCoulombYieldSurface{0.0}; - double mAbsoluteYieldFunctionValueTolerance{1.0e-8}; - std::size_t mMaxNumberOfPlasticIterations{100}; - PlasticityStatus mPlasticityStatus{PlasticityStatus::ELASTIC}; + CoulombYieldSurface mCoulombYieldSurface; + std::optional mTensionCutOff; + double mSavedKappaOfCoulombYieldSurface{0.0}; + double mAbsoluteYieldFunctionValueTolerance{1.0e-8}; + std::size_t mMaxNumberOfPlasticIterations{100}; + PlasticityStatus mPlasticityStatus{PlasticityStatus::ELASTIC}; template [[nodiscard]] bool IsAdmissibleStressState(const StressStateType& rTrialStressState); diff --git a/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.cpp b/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.cpp similarity index 65% rename from applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.cpp rename to applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.cpp index 93d2e521651d..89ce12994997 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.cpp +++ b/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.cpp @@ -13,7 +13,7 @@ // // Application includes -#include "custom_constitutive/interface_coulomb_with_tension_cut_off.h" +#include "custom_constitutive/interface_coulomb_law.h" #include "custom_constitutive/constitutive_law_dimension.h" #include "custom_constitutive/sigma_tau.hpp" #include "custom_utilities/check_utilities.hpp" @@ -28,7 +28,7 @@ namespace Kratos { -InterfaceCoulombWithTensionCutOff::InterfaceCoulombWithTensionCutOff(std::unique_ptr pConstitutiveDimension) +InterfaceCoulombLaw::InterfaceCoulombLaw(std::unique_ptr pConstitutiveDimension) : mpConstitutiveDimension(std::move(pConstitutiveDimension)), mTractionVector(ZeroVector(mpConstitutiveDimension->GetStrainSize())), mTractionVectorFinalized(ZeroVector(mpConstitutiveDimension->GetStrainSize())), @@ -36,18 +36,18 @@ InterfaceCoulombWithTensionCutOff::InterfaceCoulombWithTensionCutOff(std::unique { } -ConstitutiveLaw::Pointer InterfaceCoulombWithTensionCutOff::Clone() const +ConstitutiveLaw::Pointer InterfaceCoulombLaw::Clone() const { - auto p_result = std::make_shared(mpConstitutiveDimension->Clone()); + auto p_result = std::make_shared(mpConstitutiveDimension->Clone()); p_result->mTractionVector = mTractionVector; p_result->mTractionVectorFinalized = mTractionVectorFinalized; p_result->mRelativeDisplacementVectorFinalized = mRelativeDisplacementVectorFinalized; - p_result->mCoulombWithTensionCutOffImpl = mCoulombWithTensionCutOffImpl; + p_result->mCoulombImpl = mCoulombImpl; p_result->mIsModelInitialized = mIsModelInitialized; return p_result; } -Vector& InterfaceCoulombWithTensionCutOff::GetValue(const Variable& rVariable, Vector& rValue) +Vector& InterfaceCoulombLaw::GetValue(const Variable& rVariable, Vector& rValue) { if (rVariable == GEO_EFFECTIVE_TRACTION_VECTOR) { rValue = mTractionVector; @@ -57,17 +57,15 @@ Vector& InterfaceCoulombWithTensionCutOff::GetValue(const Variable& rVar return rValue; } -int& InterfaceCoulombWithTensionCutOff::GetValue(const Variable& rVariable, int& rValue) +int& InterfaceCoulombLaw::GetValue(const Variable& rVariable, int& rValue) { if (rVariable == GEO_PLASTICITY_STATUS) { - rValue = static_cast(mCoulombWithTensionCutOffImpl.GetPlasticityStatus()); + rValue = static_cast(mCoulombImpl.GetPlasticityStatus()); } return rValue; } -void InterfaceCoulombWithTensionCutOff::SetValue(const Variable& rVariable, - const Vector& rValue, - const ProcessInfo& rCurrentProcessInfo) +void InterfaceCoulombLaw::SetValue(const Variable& rVariable, const Vector& rValue, const ProcessInfo& rCurrentProcessInfo) { if (rVariable == GEO_EFFECTIVE_TRACTION_VECTOR) { mTractionVector = rValue; @@ -76,15 +74,15 @@ void InterfaceCoulombWithTensionCutOff::SetValue(const Variable& rVariab } } -SizeType InterfaceCoulombWithTensionCutOff::WorkingSpaceDimension() +SizeType InterfaceCoulombLaw::WorkingSpaceDimension() { // Note that this implementation assumes line interface elements. It needs to be modified when planar interface elements become available. return N_DIM_2D; } -int InterfaceCoulombWithTensionCutOff::Check(const Properties& rMaterialProperties, - const GeometryType& rElementGeometry, - const ProcessInfo& rCurrentProcessInfo) const +int InterfaceCoulombLaw::Check(const Properties& rMaterialProperties, + const GeometryType& rElementGeometry, + const ProcessInfo& rCurrentProcessInfo) const { const auto result = ConstitutiveLaw::Check(rMaterialProperties, rElementGeometry, rCurrentProcessInfo); @@ -93,40 +91,40 @@ int InterfaceCoulombWithTensionCutOff::Check(const Properties& rMaterialProper constexpr auto max_value_angle = 90.0; check_properties.SingleUseBounds(CheckProperties::Bounds::AllExclusive).Check(GEO_FRICTION_ANGLE, 0.0, max_value_angle); check_properties.Check(GEO_DILATANCY_ANGLE, rMaterialProperties[GEO_FRICTION_ANGLE]); - check_properties.Check( - GEO_TENSILE_STRENGTH, - rMaterialProperties[GEO_COHESION] / - std::tan(MathUtils<>::DegreesToRadians(rMaterialProperties[GEO_FRICTION_ANGLE]))); + if (ConstitutiveLawUtilities::WantTensionCutOff(rMaterialProperties)) { + check_properties.Check( + GEO_TENSILE_STRENGTH, + rMaterialProperties[GEO_COHESION] / + std::tan(MathUtils<>::DegreesToRadians(rMaterialProperties[GEO_FRICTION_ANGLE]))); + } check_properties.Check(INTERFACE_NORMAL_STIFFNESS); check_properties.Check(INTERFACE_SHEAR_STIFFNESS); return result; } -ConstitutiveLaw::StressMeasure InterfaceCoulombWithTensionCutOff::GetStressMeasure() +ConstitutiveLaw::StressMeasure InterfaceCoulombLaw::GetStressMeasure() { return ConstitutiveLaw::StressMeasure_Cauchy; } -SizeType InterfaceCoulombWithTensionCutOff::GetStrainSize() const +SizeType InterfaceCoulombLaw::GetStrainSize() const { // Note that this implementation assumes line interface elements. It needs to be modified when planar interface elements become available. return VOIGT_SIZE_2D_INTERFACE; } -ConstitutiveLaw::StrainMeasure InterfaceCoulombWithTensionCutOff::GetStrainMeasure() +ConstitutiveLaw::StrainMeasure InterfaceCoulombLaw::GetStrainMeasure() { return ConstitutiveLaw::StrainMeasure_Infinitesimal; } -bool InterfaceCoulombWithTensionCutOff::IsIncremental() { return true; } +bool InterfaceCoulombLaw::IsIncremental() { return true; } -bool InterfaceCoulombWithTensionCutOff::RequiresInitializeMaterialResponse() { return true; } +bool InterfaceCoulombLaw::RequiresInitializeMaterialResponse() { return true; } -void InterfaceCoulombWithTensionCutOff::InitializeMaterial(const Properties& rMaterialProperties, - const Geometry&, - const Vector&) +void InterfaceCoulombLaw::InitializeMaterial(const Properties& rMaterialProperties, const Geometry&, const Vector&) { - mCoulombWithTensionCutOffImpl = CoulombWithTensionCutOffImpl{rMaterialProperties}; + mCoulombImpl = CoulombImpl{rMaterialProperties}; mRelativeDisplacementVectorFinalized = HasInitialState() ? GetInitialState().GetInitialStrainVector() : ZeroVector{GetStrainSize()}; @@ -134,7 +132,7 @@ void InterfaceCoulombWithTensionCutOff::InitializeMaterial(const Properties& rMa HasInitialState() ? GetInitialState().GetInitialStressVector() : ZeroVector{GetStrainSize()}; } -void InterfaceCoulombWithTensionCutOff::InitializeMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) +void InterfaceCoulombLaw::InitializeMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) { if (!mIsModelInitialized) { mTractionVectorFinalized = rConstitutiveLawParameters.GetStressVector(); @@ -143,7 +141,7 @@ void InterfaceCoulombWithTensionCutOff::InitializeMaterialResponseCauchy(Paramet } } -void InterfaceCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) +void InterfaceCoulombLaw::CalculateMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) { if (!rConstitutiveLawParameters.GetOptions().Is(ConstitutiveLaw::COMPUTE_STRESS)) { return; @@ -159,8 +157,8 @@ void InterfaceCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(Paramete const auto negative = std::signbit(trial_sigma_tau.Tau()); trial_sigma_tau.Tau() = std::abs(trial_sigma_tau.Tau()); - if (!mCoulombWithTensionCutOffImpl.IsAdmissibleStressState(trial_sigma_tau)) { - mapped_sigma_tau = mCoulombWithTensionCutOffImpl.DoReturnMapping( + if (!mCoulombImpl.IsAdmissibleStressState(trial_sigma_tau)) { + mapped_sigma_tau = mCoulombImpl.DoReturnMapping( trial_sigma_tau, mpConstitutiveDimension->CalculateElasticConstitutiveTensor(r_properties), Geo::PrincipalStresses::AveragingType::NO_AVERAGING); if (negative) mapped_sigma_tau.Tau() *= -1.0; @@ -170,9 +168,9 @@ void InterfaceCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(Paramete rConstitutiveLawParameters.GetStressVector() = mTractionVector; } -Geo::SigmaTau InterfaceCoulombWithTensionCutOff::CalculateTrialTractionVector(const Vector& rRelativeDisplacementVector, - double NormalStiffness, - double ShearStiffness) const +Geo::SigmaTau InterfaceCoulombLaw::CalculateTrialTractionVector(const Vector& rRelativeDisplacementVector, + double NormalStiffness, + double ShearStiffness) const { constexpr auto number_of_normal_components = std::size_t{1}; return Geo::SigmaTau{mTractionVectorFinalized + @@ -181,15 +179,15 @@ Geo::SigmaTau InterfaceCoulombWithTensionCutOff::CalculateTrialTractionVector(co rRelativeDisplacementVector - mRelativeDisplacementVectorFinalized)}; } -void InterfaceCoulombWithTensionCutOff::FinalizeMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) +void InterfaceCoulombLaw::FinalizeMaterialResponseCauchy(Parameters& rConstitutiveLawParameters) { mRelativeDisplacementVectorFinalized = rConstitutiveLawParameters.GetStrainVector(); mTractionVectorFinalized = mTractionVector; } -Matrix& InterfaceCoulombWithTensionCutOff::CalculateValue(Parameters& rConstitutiveLawParameters, - const Variable& rVariable, - Matrix& rValue) +Matrix& InterfaceCoulombLaw::CalculateValue(Parameters& rConstitutiveLawParameters, + const Variable& rVariable, + Matrix& rValue) { if (rVariable == CONSTITUTIVE_MATRIX) { const auto& r_properties = rConstitutiveLawParameters.GetMaterialProperties(); @@ -204,25 +202,25 @@ Matrix& InterfaceCoulombWithTensionCutOff::CalculateValue(Parameters& rConstitut return rValue; } -void InterfaceCoulombWithTensionCutOff::save(Serializer& rSerializer) const +void InterfaceCoulombLaw::save(Serializer& rSerializer) const { KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, ConstitutiveLaw) rSerializer.save("ConstitutiveDimension", mpConstitutiveDimension); rSerializer.save("TractionVector", mTractionVector); rSerializer.save("TractionVectorFinalized", mTractionVectorFinalized); rSerializer.save("RelativeDisplacementVectorFinalized", mRelativeDisplacementVectorFinalized); - rSerializer.save("CoulombWithTensionCutOffImpl", mCoulombWithTensionCutOffImpl); + rSerializer.save("CoulombImpl", mCoulombImpl); rSerializer.save("IsModelInitialized", mIsModelInitialized); } -void InterfaceCoulombWithTensionCutOff::load(Serializer& rSerializer) +void InterfaceCoulombLaw::load(Serializer& rSerializer) { KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, ConstitutiveLaw) rSerializer.load("ConstitutiveDimension", mpConstitutiveDimension); rSerializer.load("TractionVector", mTractionVector); rSerializer.load("TractionVectorFinalized", mTractionVectorFinalized); rSerializer.load("RelativeDisplacementVectorFinalized", mRelativeDisplacementVectorFinalized); - rSerializer.load("CoulombWithTensionCutOffImpl", mCoulombWithTensionCutOffImpl); + rSerializer.load("CoulombImpl", mCoulombImpl); rSerializer.load("IsModelInitialized", mIsModelInitialized); } diff --git a/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.h b/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.h similarity index 77% rename from applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.h rename to applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.h index a41aa3c52244..e90318649104 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_with_tension_cut_off.h +++ b/applications/GeoMechanicsApplication/custom_constitutive/interface_coulomb_law.h @@ -14,7 +14,7 @@ #pragma once -#include "custom_constitutive/coulomb_with_tension_cut_off_impl.h" +#include "custom_constitutive/coulomb_impl.h" #include "includes/constitutive_law.h" namespace Kratos @@ -22,21 +22,21 @@ namespace Kratos class ConstitutiveLawDimension; -class KRATOS_API(GEO_MECHANICS_APPLICATION) InterfaceCoulombWithTensionCutOff : public ConstitutiveLaw +class KRATOS_API(GEO_MECHANICS_APPLICATION) InterfaceCoulombLaw : public ConstitutiveLaw { public: - KRATOS_CLASS_POINTER_DEFINITION(InterfaceCoulombWithTensionCutOff); + KRATOS_CLASS_POINTER_DEFINITION(InterfaceCoulombLaw); - InterfaceCoulombWithTensionCutOff() = default; - explicit InterfaceCoulombWithTensionCutOff(std::unique_ptr pConstitutiveDimension); + InterfaceCoulombLaw() = default; + explicit InterfaceCoulombLaw(std::unique_ptr pConstitutiveDimension); // Copying is not allowed. Use member `Clone` instead. - InterfaceCoulombWithTensionCutOff(const InterfaceCoulombWithTensionCutOff&) = delete; - InterfaceCoulombWithTensionCutOff& operator=(const InterfaceCoulombWithTensionCutOff&) = delete; + InterfaceCoulombLaw(const InterfaceCoulombLaw&) = delete; + InterfaceCoulombLaw& operator=(const InterfaceCoulombLaw&) = delete; // Moving is supported - InterfaceCoulombWithTensionCutOff(InterfaceCoulombWithTensionCutOff&&) noexcept = default; - InterfaceCoulombWithTensionCutOff& operator=(InterfaceCoulombWithTensionCutOff&&) noexcept = default; + InterfaceCoulombLaw(InterfaceCoulombLaw&&) noexcept = default; + InterfaceCoulombLaw& operator=(InterfaceCoulombLaw&&) noexcept = default; [[nodiscard]] ConstitutiveLaw::Pointer Clone() const override; SizeType WorkingSpaceDimension() override; @@ -69,7 +69,7 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) InterfaceCoulombWithTensionCutOff : Vector mTractionVector; Vector mTractionVectorFinalized; Vector mRelativeDisplacementVectorFinalized; - CoulombWithTensionCutOffImpl mCoulombWithTensionCutOffImpl; + CoulombImpl mCoulombImpl; bool mIsModelInitialized = false; [[nodiscard]] Geo::SigmaTau CalculateTrialTractionVector(const Vector& rRelativeDisplacementVector, @@ -79,6 +79,6 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) InterfaceCoulombWithTensionCutOff : friend class Serializer; void save(Serializer& rSerializer) const override; void load(Serializer& rSerializer) override; -}; // Class InterfaceMohrCoulombWithTensionCutOff +}; // Class InterfaceMohrCoulomb } // namespace Kratos diff --git a/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.cpp b/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.cpp similarity index 66% rename from applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.cpp rename to applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.cpp index f42a376b55ea..bf6e04f47658 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.cpp +++ b/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.cpp @@ -13,7 +13,7 @@ // // Application includes -#include "custom_constitutive/mohr_coulomb_with_tension_cutoff.h" +#include "custom_constitutive/mohr_coulomb_law.h" #include "custom_constitutive/constitutive_law_dimension.h" #include "custom_constitutive/principal_stresses.hpp" #include "custom_utilities/check_utilities.hpp" @@ -78,7 +78,7 @@ Geo::PrincipalStresses::AveragingType FindAveragingType(const Geo::PrincipalStre namespace Kratos { -MohrCoulombWithTensionCutOff::MohrCoulombWithTensionCutOff(std::unique_ptr pConstitutiveDimension) +MohrCoulombLaw::MohrCoulombLaw(std::unique_ptr pConstitutiveDimension) : mpConstitutiveDimension(std::move(pConstitutiveDimension)), mStressVector(ZeroVector(mpConstitutiveDimension->GetStrainSize())), mStressVectorFinalized(ZeroVector(mpConstitutiveDimension->GetStrainSize())), @@ -86,17 +86,17 @@ MohrCoulombWithTensionCutOff::MohrCoulombWithTensionCutOff(std::unique_ptr(mpConstitutiveDimension->Clone()); - p_result->mStressVector = mStressVector; - p_result->mStressVectorFinalized = mStressVectorFinalized; - p_result->mStrainVectorFinalized = mStrainVectorFinalized; - p_result->mCoulombWithTensionCutOffImpl = mCoulombWithTensionCutOffImpl; + auto p_result = std::make_shared(mpConstitutiveDimension->Clone()); + p_result->mStressVector = mStressVector; + p_result->mStressVectorFinalized = mStressVectorFinalized; + p_result->mStrainVectorFinalized = mStrainVectorFinalized; + p_result->mCoulombImpl = mCoulombImpl; return p_result; } -Vector& MohrCoulombWithTensionCutOff::GetValue(const Variable& rVariable, Vector& rValue) +Vector& MohrCoulombLaw::GetValue(const Variable& rVariable, Vector& rValue) { if (rVariable == CAUCHY_STRESS_VECTOR) { rValue = mStressVector; @@ -106,17 +106,15 @@ Vector& MohrCoulombWithTensionCutOff::GetValue(const Variable& rVariable return rValue; } -int& MohrCoulombWithTensionCutOff::GetValue(const Variable& rVariable, int& rValue) +int& MohrCoulombLaw::GetValue(const Variable& rVariable, int& rValue) { if (rVariable == GEO_PLASTICITY_STATUS) { - rValue = static_cast(mCoulombWithTensionCutOffImpl.GetPlasticityStatus()); + rValue = static_cast(mCoulombImpl.GetPlasticityStatus()); } return rValue; } -void MohrCoulombWithTensionCutOff::SetValue(const Variable& rVariable, - const Vector& rValue, - const ProcessInfo& rCurrentProcessInfo) +void MohrCoulombLaw::SetValue(const Variable& rVariable, const Vector& rValue, const ProcessInfo& rCurrentProcessInfo) { if (rVariable == CAUCHY_STRESS_VECTOR) { mStressVector = rValue; @@ -125,55 +123,49 @@ void MohrCoulombWithTensionCutOff::SetValue(const Variable& rVariable, } } -SizeType MohrCoulombWithTensionCutOff::WorkingSpaceDimension() -{ - return mpConstitutiveDimension->GetDimension(); -} +SizeType MohrCoulombLaw::WorkingSpaceDimension() { return mpConstitutiveDimension->GetDimension(); } -int MohrCoulombWithTensionCutOff::Check(const Properties& rMaterialProperties, - const GeometryType& rElementGeometry, - const ProcessInfo& rCurrentProcessInfo) const +int MohrCoulombLaw::Check(const Properties& rMaterialProperties, + const GeometryType& rElementGeometry, + const ProcessInfo& rCurrentProcessInfo) const { const auto result = ConstitutiveLaw::Check(rMaterialProperties, rElementGeometry, rCurrentProcessInfo); const CheckProperties check_properties(rMaterialProperties, "property", CheckProperties::Bounds::AllInclusive); - check_properties.Check( - GEO_TENSILE_STRENGTH, - rMaterialProperties[GEO_COHESION] / - std::tan(MathUtils<>::DegreesToRadians(rMaterialProperties[GEO_FRICTION_ANGLE]))); + if (ConstitutiveLawUtilities::WantTensionCutOff(rMaterialProperties)) { + check_properties.Check( + GEO_TENSILE_STRENGTH, + rMaterialProperties[GEO_COHESION] / + std::tan(MathUtils<>::DegreesToRadians(rMaterialProperties[GEO_FRICTION_ANGLE]))); + } check_properties.Check(YOUNG_MODULUS); constexpr auto max_value_poisson_ratio = 0.5; check_properties.Check(POISSON_RATIO, max_value_poisson_ratio); return result; } -ConstitutiveLaw::StressMeasure MohrCoulombWithTensionCutOff::GetStressMeasure() +ConstitutiveLaw::StressMeasure MohrCoulombLaw::GetStressMeasure() { return ConstitutiveLaw::StressMeasure_Cauchy; } -SizeType MohrCoulombWithTensionCutOff::GetStrainSize() const -{ - return mpConstitutiveDimension->GetStrainSize(); -} +SizeType MohrCoulombLaw::GetStrainSize() const { return mpConstitutiveDimension->GetStrainSize(); } -ConstitutiveLaw::StrainMeasure MohrCoulombWithTensionCutOff::GetStrainMeasure() +ConstitutiveLaw::StrainMeasure MohrCoulombLaw::GetStrainMeasure() { return ConstitutiveLaw::StrainMeasure_Infinitesimal; } -bool MohrCoulombWithTensionCutOff::IsIncremental() { return true; } +bool MohrCoulombLaw::IsIncremental() { return true; } -bool MohrCoulombWithTensionCutOff::RequiresInitializeMaterialResponse() { return true; } +bool MohrCoulombLaw::RequiresInitializeMaterialResponse() { return true; } -void MohrCoulombWithTensionCutOff::InitializeMaterial(const Properties& rMaterialProperties, - const Geometry&, - const Vector&) +void MohrCoulombLaw::InitializeMaterial(const Properties& rMaterialProperties, const Geometry&, const Vector&) { - mCoulombWithTensionCutOffImpl = CoulombWithTensionCutOffImpl{rMaterialProperties}; + mCoulombImpl = CoulombImpl{rMaterialProperties}; } -void MohrCoulombWithTensionCutOff::InitializeMaterialResponseCauchy(Parameters& rValues) +void MohrCoulombLaw::InitializeMaterialResponseCauchy(Parameters& rValues) { if (!mIsModelInitialized) { mStressVectorFinalized = rValues.GetStressVector(); @@ -182,7 +174,7 @@ void MohrCoulombWithTensionCutOff::InitializeMaterialResponseCauchy(Parameters& } } -void MohrCoulombWithTensionCutOff::GetLawFeatures(Features& rFeatures) +void MohrCoulombLaw::GetLawFeatures(Features& rFeatures) { auto options = Flags{}; options.Set(mpConstitutiveDimension->GetSpatialType()); @@ -195,7 +187,7 @@ void MohrCoulombWithTensionCutOff::GetLawFeatures(Features& rFeatures) rFeatures.SetSpaceDimension(WorkingSpaceDimension()); } -void MohrCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(ConstitutiveLaw::Parameters& rParameters) +void MohrCoulombLaw::CalculateMaterialResponseCauchy(ConstitutiveLaw::Parameters& rParameters) { const auto& r_properties = rParameters.GetMaterialProperties(); @@ -211,11 +203,11 @@ void MohrCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(ConstitutiveL const auto& [trial_principal_stresses, rotation_matrix] = StressStrainUtilities::CalculatePrincipalStressesAndRotationMatrix(trial_stress_vector); - if (mCoulombWithTensionCutOffImpl.IsAdmissibleStressState(trial_principal_stresses)) { + if (mCoulombImpl.IsAdmissibleStressState(trial_principal_stresses)) { mStressVector = trial_stress_vector; } else { - mCoulombWithTensionCutOffImpl.SaveKappaOfCoulombYieldSurface(); - auto mapped_principal_stresses = mCoulombWithTensionCutOffImpl.DoReturnMapping( + mCoulombImpl.SaveKappaOfCoulombYieldSurface(); + auto mapped_principal_stresses = mCoulombImpl.DoReturnMapping( trial_principal_stresses, mpConstitutiveDimension->CalculateElasticConstitutiveTensor(r_properties), Geo::PrincipalStresses::AveragingType::NO_AVERAGING); @@ -224,8 +216,8 @@ void MohrCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(ConstitutiveL averaging_type != Geo::PrincipalStresses::AveragingType::NO_AVERAGING) { const auto averaged_principal_trial_stress_vector = AveragePrincipalStressComponents(trial_principal_stresses, averaging_type); - mCoulombWithTensionCutOffImpl.RestoreKappaOfCoulombYieldSurface(); - mapped_principal_stresses = mCoulombWithTensionCutOffImpl.DoReturnMapping( + mCoulombImpl.RestoreKappaOfCoulombYieldSurface(); + mapped_principal_stresses = mCoulombImpl.DoReturnMapping( averaged_principal_trial_stress_vector, mpConstitutiveDimension->CalculateElasticConstitutiveTensor(r_properties), averaging_type); mapped_principal_stresses.Values()[1] = @@ -238,38 +230,37 @@ void MohrCoulombWithTensionCutOff::CalculateMaterialResponseCauchy(ConstitutiveL rParameters.GetStressVector() = mStressVector; } -Vector MohrCoulombWithTensionCutOff::CalculateTrialStressVector(const Vector& rStrainVector, - const Properties& rProperties) const +Vector MohrCoulombLaw::CalculateTrialStressVector(const Vector& rStrainVector, const Properties& rProperties) const { return mStressVectorFinalized + prod(mpConstitutiveDimension->CalculateElasticConstitutiveTensor(rProperties), rStrainVector - mStrainVectorFinalized); } -void MohrCoulombWithTensionCutOff::FinalizeMaterialResponseCauchy(ConstitutiveLaw::Parameters& rValues) +void MohrCoulombLaw::FinalizeMaterialResponseCauchy(ConstitutiveLaw::Parameters& rValues) { mStrainVectorFinalized = rValues.GetStrainVector(); mStressVectorFinalized = mStressVector; } -void MohrCoulombWithTensionCutOff::save(Serializer& rSerializer) const +void MohrCoulombLaw::save(Serializer& rSerializer) const { KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, ConstitutiveLaw) rSerializer.save("ConstitutiveLawDimension", mpConstitutiveDimension); rSerializer.save("StressVector", mStressVector); rSerializer.save("StressVectorFinalized", mStressVectorFinalized); rSerializer.save("StrainVectorFinalized", mStrainVectorFinalized); - rSerializer.save("CoulombWithTensionCutOffImpl", mCoulombWithTensionCutOffImpl); + rSerializer.save("mCoulombImpl", mCoulombImpl); rSerializer.save("IsModelInitialized", mIsModelInitialized); } -void MohrCoulombWithTensionCutOff::load(Serializer& rSerializer) +void MohrCoulombLaw::load(Serializer& rSerializer) { KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, ConstitutiveLaw) rSerializer.load("ConstitutiveLawDimension", mpConstitutiveDimension); rSerializer.load("StressVector", mStressVector); rSerializer.load("StressVectorFinalized", mStressVectorFinalized); rSerializer.load("StrainVectorFinalized", mStrainVectorFinalized); - rSerializer.load("CoulombWithTensionCutOffImpl", mCoulombWithTensionCutOffImpl); + rSerializer.load("mCoulombImpl", mCoulombImpl); rSerializer.load("IsModelInitialized", mIsModelInitialized); } diff --git a/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.h b/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.h similarity index 76% rename from applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.h rename to applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.h index ca41e6cb96a3..773d47b154f7 100644 --- a/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_with_tension_cutoff.h +++ b/applications/GeoMechanicsApplication/custom_constitutive/mohr_coulomb_law.h @@ -14,7 +14,7 @@ #pragma once -#include "custom_constitutive/coulomb_with_tension_cut_off_impl.h" +#include "custom_constitutive/coulomb_impl.h" #include "includes/constitutive_law.h" namespace Kratos @@ -22,21 +22,21 @@ namespace Kratos class ConstitutiveLawDimension; -class KRATOS_API(GEO_MECHANICS_APPLICATION) MohrCoulombWithTensionCutOff : public ConstitutiveLaw +class KRATOS_API(GEO_MECHANICS_APPLICATION) MohrCoulombLaw : public ConstitutiveLaw { public: - KRATOS_CLASS_POINTER_DEFINITION(MohrCoulombWithTensionCutOff); + KRATOS_CLASS_POINTER_DEFINITION(MohrCoulombLaw); - MohrCoulombWithTensionCutOff() = default; - explicit MohrCoulombWithTensionCutOff(std::unique_ptr pConstitutiveDimension); + MohrCoulombLaw() = default; + explicit MohrCoulombLaw(std::unique_ptr pConstitutiveDimension); // Copying is not allowed. Use member `Clone` instead. - MohrCoulombWithTensionCutOff(const MohrCoulombWithTensionCutOff&) = delete; - MohrCoulombWithTensionCutOff& operator=(const MohrCoulombWithTensionCutOff&) = delete; + MohrCoulombLaw(const MohrCoulombLaw&) = delete; + MohrCoulombLaw& operator=(const MohrCoulombLaw&) = delete; // Moving is supported - MohrCoulombWithTensionCutOff(MohrCoulombWithTensionCutOff&&) noexcept = default; - MohrCoulombWithTensionCutOff& operator=(MohrCoulombWithTensionCutOff&&) noexcept = default; + MohrCoulombLaw(MohrCoulombLaw&&) noexcept = default; + MohrCoulombLaw& operator=(MohrCoulombLaw&&) noexcept = default; [[nodiscard]] ConstitutiveLaw::Pointer Clone() const override; SizeType WorkingSpaceDimension() override; @@ -66,7 +66,7 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) MohrCoulombWithTensionCutOff : publi Vector mStressVector; Vector mStressVectorFinalized; Vector mStrainVectorFinalized; - CoulombWithTensionCutOffImpl mCoulombWithTensionCutOffImpl; + CoulombImpl mCoulombImpl; bool mIsModelInitialized = false; [[nodiscard]] Vector CalculateTrialStressVector(const Vector& rStrainVector, const Properties& rProperties) const; @@ -74,6 +74,6 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) MohrCoulombWithTensionCutOff : publi friend class Serializer; void save(Serializer& rSerializer) const override; void load(Serializer& rSerializer) override; -}; // Class MohrCoulombWithTensionCutOff +}; // Class MohrCoulombLaw } // namespace Kratos diff --git a/applications/GeoMechanicsApplication/custom_processes/apply_c_phi_reduction_process.cpp b/applications/GeoMechanicsApplication/custom_processes/apply_c_phi_reduction_process.cpp index 1a896ea34fe4..35297cc25c71 100644 --- a/applications/GeoMechanicsApplication/custom_processes/apply_c_phi_reduction_process.cpp +++ b/applications/GeoMechanicsApplication/custom_processes/apply_c_phi_reduction_process.cpp @@ -16,7 +16,7 @@ #include "custom_processes/apply_c_phi_reduction_process.h" #include "containers/model.h" #include "custom_constitutive/constitutive_law_dimension.h" -#include "custom_constitutive/mohr_coulomb_with_tension_cutoff.h" +#include "custom_constitutive/mohr_coulomb_law.h" #include "custom_utilities/check_utilities.hpp" #include "custom_utilities/constitutive_law_utilities.h" #include "custom_utilities/process_utilities.h" @@ -45,8 +45,7 @@ bool UsesInternalMohrCoulombModel(const Element& rElement) KRATOS_ERROR_IF_NOT(rElement.GetProperties().Has(CONSTITUTIVE_LAW)) << "Properties do not have CONSTITUTIVE_LAW" << std::endl; - return dynamic_cast( - rElement.GetProperties()[CONSTITUTIVE_LAW].get()) != nullptr; + return dynamic_cast(rElement.GetProperties()[CONSTITUTIVE_LAW].get()) != nullptr; } } // namespace @@ -200,7 +199,7 @@ void ApplyCPhiReductionProcess::InitializeParametersForInternalMohrCoulombModel( const auto dummy_geometry = Geometry{}; const auto dummy_vector = Vector(); for (const auto& p_law : constitutive_laws) { - if (const auto p_mohr_coulomb = dynamic_cast(p_law.get())) { + if (const auto p_mohr_coulomb = dynamic_cast(p_law.get())) { p_mohr_coulomb->InitializeMaterial(r_properties, dummy_geometry, dummy_vector); } } diff --git a/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.cpp b/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.cpp index 82cce9b1b40c..8510dc5f156a 100644 --- a/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.cpp +++ b/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.cpp @@ -342,4 +342,15 @@ double ConstitutiveLawUtilities::CalculateExcessPorePressureIncrement(const Prop << "." << std::endl; return biot_coefficient * VolumetricStrainIncrement / denominator; } + +bool ConstitutiveLawUtilities::WantTensionCutOff(const Properties& rMaterialProperties) +{ + if (rMaterialProperties.Has(GEO_ENABLE_TENSION_CUT_OFF) && rMaterialProperties[GEO_ENABLE_TENSION_CUT_OFF]) { + return true; + } + + // The following statement is to support backward compatibility (i.e. GEO_ENABLE_TENSION_CUT_OFF is not specified, + // but the GEO_TENSILE_STRENGTH is provided), which results in an enabled tension cutoff. + return !rMaterialProperties.Has(GEO_ENABLE_TENSION_CUT_OFF) && rMaterialProperties.Has(GEO_TENSILE_STRENGTH); +} } // namespace Kratos \ No newline at end of file diff --git a/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.h b/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.h index 786d508d3a0f..0302a9bae8c8 100644 --- a/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.h +++ b/applications/GeoMechanicsApplication/custom_utilities/constitutive_law_utilities.h @@ -73,6 +73,9 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) ConstitutiveLawUtilities [[nodiscard]] static double CalculateExcessPorePressureIncrement(const Properties& rProperties, double VolumetricStrainIncrement); + + [[nodiscard]] static bool WantTensionCutOff(const Properties& rProperties); + }; /* Class ConstitutiveLawUtilities*/ } // namespace Kratos diff --git a/applications/GeoMechanicsApplication/geo_mechanics_application.cpp b/applications/GeoMechanicsApplication/geo_mechanics_application.cpp index f7b5ffb27519..ad22fb3c2c3b 100644 --- a/applications/GeoMechanicsApplication/geo_mechanics_application.cpp +++ b/applications/GeoMechanicsApplication/geo_mechanics_application.cpp @@ -355,10 +355,14 @@ void KratosGeoMechanicsApplication::Register() KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoIncrementalLinearElasticInterface3DSurfaceLaw", mIncrementalLinearElasticInterface3DSurfaceLaw) - KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombWithTensionCutOff2D", mMohrCoulombWithTensionCutOff2D) - KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombWithTensionCutOff3D", mMohrCoulombWithTensionCutOff3D) + // Deprecated! Keeping the old names for backward compatibility, but will be removed. + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombWithTensionCutOff2D", mMohrCoulombLawPlaneStrain) + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombWithTensionCutOff3D", mMohrCoulombLaw3D) + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoInterfaceCoulombWithTensionCutOff", mInterfaceCoulombLawPlaneStrain) - KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoInterfaceCoulombWithTensionCutOff", mInterfaceCoulombWithTensionCutOff) + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombLawPlaneStrain", mMohrCoulombLawPlaneStrain) + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoMohrCoulombLaw3D", mMohrCoulombLaw3D) + KRATOS_REGISTER_CONSTITUTIVE_LAW("GeoInterfaceCoulombLawPlaneStrain", mInterfaceCoulombLawPlaneStrain) // Register Variables KRATOS_REGISTER_VARIABLE(VELOCITY_COEFFICIENT) @@ -379,6 +383,7 @@ void KratosGeoMechanicsApplication::Register() KRATOS_REGISTER_VARIABLE(GEO_COHESION) KRATOS_REGISTER_VARIABLE(GEO_FRICTION_ANGLE) KRATOS_REGISTER_VARIABLE(GEO_DILATANCY_ANGLE) + KRATOS_REGISTER_VARIABLE(GEO_ENABLE_TENSION_CUT_OFF) KRATOS_REGISTER_VARIABLE(GEO_TENSILE_STRENGTH) KRATOS_REGISTER_VARIABLE(GEO_COULOMB_HARDENING_TYPE) KRATOS_REGISTER_VARIABLE(GEO_COHESION_FUNCTION_COEFFICIENTS) diff --git a/applications/GeoMechanicsApplication/geo_mechanics_application.h b/applications/GeoMechanicsApplication/geo_mechanics_application.h index 61d59449cacd..d56fb0ee2910 100644 --- a/applications/GeoMechanicsApplication/geo_mechanics_application.h +++ b/applications/GeoMechanicsApplication/geo_mechanics_application.h @@ -107,12 +107,12 @@ // constitutive models #include "custom_constitutive/incremental_linear_elastic_interface_law.h" #include "custom_constitutive/incremental_linear_elastic_law.h" -#include "custom_constitutive/interface_coulomb_with_tension_cut_off.h" +#include "custom_constitutive/interface_coulomb_law.h" #include "custom_constitutive/interface_plane_strain.h" #include "custom_constitutive/interface_three_dimensional_surface.h" #include "custom_constitutive/linear_elastic_2D_interface_law.h" #include "custom_constitutive/linear_elastic_3D_interface_law.h" -#include "custom_constitutive/mohr_coulomb_with_tension_cutoff.h" +#include "custom_constitutive/mohr_coulomb_law.h" #include "custom_constitutive/plane_strain.h" #include "custom_constitutive/small_strain_udsm_2D_interface_law.h" #include "custom_constitutive/small_strain_udsm_3D_interface_law.h" @@ -961,11 +961,10 @@ class KRATOS_API(GEO_MECHANICS_APPLICATION) KratosGeoMechanicsApplication : publ const GeoIncrementalLinearElasticInterfaceLaw mIncrementalLinearElasticInterface3DSurfaceLaw{ std::make_unique()}; - const MohrCoulombWithTensionCutOff mMohrCoulombWithTensionCutOff2D{std::make_unique()}; - const MohrCoulombWithTensionCutOff mMohrCoulombWithTensionCutOff3D{std::make_unique()}; + const MohrCoulombLaw mMohrCoulombLawPlaneStrain{std::make_unique()}; + const MohrCoulombLaw mMohrCoulombLaw3D{std::make_unique()}; - const InterfaceCoulombWithTensionCutOff mInterfaceCoulombWithTensionCutOff{ - std::make_unique()}; + const InterfaceCoulombLaw mInterfaceCoulombLawPlaneStrain{std::make_unique()}; ///@} diff --git a/applications/GeoMechanicsApplication/geo_mechanics_application_variables.cpp b/applications/GeoMechanicsApplication/geo_mechanics_application_variables.cpp index 1552d48d1da6..390acab5eed2 100644 --- a/applications/GeoMechanicsApplication/geo_mechanics_application_variables.cpp +++ b/applications/GeoMechanicsApplication/geo_mechanics_application_variables.cpp @@ -35,6 +35,7 @@ KRATOS_CREATE_VARIABLE(double, GEO_COHESION) KRATOS_CREATE_VARIABLE(double, GEO_FRICTION_ANGLE) KRATOS_CREATE_VARIABLE(double, GEO_DILATANCY_ANGLE) KRATOS_CREATE_VARIABLE(double, GEO_TENSILE_STRENGTH) +KRATOS_CREATE_VARIABLE(bool, GEO_ENABLE_TENSION_CUT_OFF) KRATOS_CREATE_VARIABLE(std::string, GEO_COULOMB_HARDENING_TYPE) KRATOS_CREATE_VARIABLE(Vector, GEO_COHESION_FUNCTION_COEFFICIENTS) KRATOS_CREATE_VARIABLE(Vector, GEO_FRICTION_ANGLE_FUNCTION_COEFFICIENTS) diff --git a/applications/GeoMechanicsApplication/geo_mechanics_application_variables.h b/applications/GeoMechanicsApplication/geo_mechanics_application_variables.h index ba0a8a1cf571..6a8cf710867d 100644 --- a/applications/GeoMechanicsApplication/geo_mechanics_application_variables.h +++ b/applications/GeoMechanicsApplication/geo_mechanics_application_variables.h @@ -65,6 +65,7 @@ KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, double, GEO_COHESI KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, double, GEO_FRICTION_ANGLE) KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, double, GEO_DILATANCY_ANGLE) KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, double, GEO_TENSILE_STRENGTH) +KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, bool, GEO_ENABLE_TENSION_CUT_OFF) KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, std::string, GEO_COULOMB_HARDENING_TYPE) KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, Vector, GEO_COHESION_FUNCTION_COEFFICIENTS) KRATOS_DEFINE_APPLICATION_VARIABLE(GEO_MECHANICS_APPLICATION, Vector, GEO_FRICTION_ANGLE_FUNCTION_COEFFICIENTS) diff --git a/applications/GeoMechanicsApplication/tests/C-Phi_reduction_process/Mohr_Coulomb_model/MaterialParameters_stage2.json b/applications/GeoMechanicsApplication/tests/C-Phi_reduction_process/Mohr_Coulomb_model/MaterialParameters_stage2.json index c1e82fc3e579..e9c88e71e563 100644 --- a/applications/GeoMechanicsApplication/tests/C-Phi_reduction_process/Mohr_Coulomb_model/MaterialParameters_stage2.json +++ b/applications/GeoMechanicsApplication/tests/C-Phi_reduction_process/Mohr_Coulomb_model/MaterialParameters_stage2.json @@ -4,7 +4,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoMohrCoulombWithTensionCutOff2D" + "name" : "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE" : "CONSTANT_PW_FIELD", @@ -24,6 +24,7 @@ "POISSON_RATIO" : 0.2, "GEO_COHESION" : 1000.0, "GEO_FRICTION_ANGLE" : 30.0, + "GEO_ENABLE_TENSION_CUT_OFF": true, "GEO_TENSILE_STRENGTH" : 1000.0, "GEO_DILATANCY_ANGLE" : 0.0 } diff --git a/applications/GeoMechanicsApplication/tests/building_pit/mohr_coulomb/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/building_pit/mohr_coulomb/MaterialParameters.json index bcc1771c8e4b..750e18b6c9ba 100644 --- a/applications/GeoMechanicsApplication/tests/building_pit/mohr_coulomb/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/building_pit/mohr_coulomb/MaterialParameters.json @@ -5,7 +5,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -27,7 +27,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -37,7 +37,7 @@ "properties_id": 2, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -59,7 +59,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -69,7 +69,7 @@ "properties_id": 3, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -91,7 +91,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -101,7 +101,7 @@ "properties_id": 4, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -123,7 +123,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -133,7 +133,7 @@ "properties_id": 5, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -155,7 +155,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 2.0 } } @@ -165,7 +165,7 @@ "properties_id": 6, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -187,7 +187,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 2.0 } } @@ -197,14 +197,14 @@ "properties_id": 7, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+07, "INTERFACE_SHEAR_STIFFNESS": 2.0869565e+07, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -220,14 +220,14 @@ "properties_id": 8, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+07, "INTERFACE_SHEAR_STIFFNESS": 2.0869565e+07, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -243,14 +243,14 @@ "properties_id": 9, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+07, "INTERFACE_SHEAR_STIFFNESS": 2.0869565e+07, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -266,14 +266,14 @@ "properties_id": 10, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+07, "INTERFACE_SHEAR_STIFFNESS": 2.0869565e+07, "GEO_COHESION": 1.0e+03, "GEO_FRICTION_ANGLE": 25.0, - "GEO_TENSILE_STRENGTH": 2.1445e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -289,14 +289,14 @@ "properties_id": 11, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+08, "INTERFACE_SHEAR_STIFFNESS": 2.0e+08, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 2.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -312,14 +312,14 @@ "properties_id": 12, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS": 4.8e+08, "INTERFACE_SHEAR_STIFFNESS": 2.0e+08, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 2.0, "BIOT_COEFFICIENT": 1.0, "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", diff --git a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_with_tension_cut_off.cpp b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_law.cpp similarity index 90% rename from applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_with_tension_cut_off.cpp rename to applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_law.cpp index 99a8a163496d..518f70f57773 100644 --- a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_with_tension_cut_off.cpp +++ b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_interface_coulomb_law.cpp @@ -11,7 +11,7 @@ // Mohamed Nabi // -#include "custom_constitutive/interface_coulomb_with_tension_cut_off.h" +#include "custom_constitutive/interface_coulomb_law.h" #include "custom_constitutive/interface_plane_strain.h" #include "custom_utilities/registration_utilities.hpp" #include "custom_utilities/ublas_utilities.h" @@ -40,10 +40,10 @@ void InitializeLawMaterial(ConstitutiveLaw& rLaw, const Properties& rProperties) namespace Kratos::Testing { -KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Clone, KratosGeoMechanicsFastSuiteWithoutKernel) +KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulomb_Clone, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - const auto original_law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + const auto original_law = InterfaceCoulombLaw{std::make_unique()}; // Act auto p_cloned_law = original_law.Clone(); @@ -51,7 +51,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Clone, KratosGeoMech // Assert KRATOS_EXPECT_NE(p_cloned_law.get(), nullptr); KRATOS_EXPECT_NE(p_cloned_law.get(), &original_law); - KRATOS_EXPECT_NE(dynamic_cast(p_cloned_law.get()), nullptr); + KRATOS_EXPECT_NE(dynamic_cast(p_cloned_law.get()), nullptr); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialResponseCauchyAtElasticZone, @@ -62,6 +62,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); auto parameters = ConstitutiveLaw::Parameters{}; @@ -77,7 +78,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes p_initial_state->SetInitialStressVector(initial_traction_vector); p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; law.SetInitialState(p_initial_state); InitializeLawMaterial(law, properties); @@ -128,6 +129,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); auto parameters = ConstitutiveLaw::Parameters{}; @@ -143,7 +145,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes p_initial_state->SetInitialStressVector(initial_traction_vector); p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; law.SetInitialState(p_initial_state); InitializeLawMaterial(law, properties); @@ -167,6 +169,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(INTERFACE_NORMAL_STIFFNESS, 25.0); properties.SetValue(INTERFACE_SHEAR_STIFFNESS, 12.5); @@ -184,7 +187,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes p_initial_state->SetInitialStressVector(initial_traction_vector); p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; law.SetInitialState(p_initial_state); InitializeLawMaterial(law, properties); @@ -208,6 +211,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); auto parameters = ConstitutiveLaw::Parameters{}; @@ -223,7 +227,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes p_initial_state->SetInitialStressVector(initial_traction_vector); p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; law.SetInitialState(p_initial_state); InitializeLawMaterial(law, properties); @@ -247,6 +251,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(INTERFACE_NORMAL_STIFFNESS, 25.0); properties.SetValue(INTERFACE_SHEAR_STIFFNESS, 12.5); @@ -264,7 +269,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateMaterialRes p_initial_state->SetInitialStressVector(initial_traction_vector); p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; law.SetInitialState(p_initial_state); InitializeLawMaterial(law, properties); @@ -288,6 +293,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_DoesNotCalculateStre properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(INTERFACE_NORMAL_STIFFNESS, 25.0); properties.SetValue(INTERFACE_SHEAR_STIFFNESS, 12.5); @@ -299,7 +305,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_DoesNotCalculateStre auto relative_displacement_vector = Vector{2, 1.0}; parameters.SetStrainVector(relative_displacement_vector); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; InitializeLawMaterial(law, properties); // Act @@ -323,6 +329,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Serialization, Krato properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); auto parameters = ConstitutiveLaw::Parameters{}; @@ -339,15 +346,15 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Serialization, Krato p_initial_state->SetInitialStrainVector(Vector{ZeroVector{2}}); auto p_law = std::unique_ptr{ - std::make_unique(std::make_unique())}; + std::make_unique(std::make_unique())}; p_law->SetInitialState(p_initial_state); InitializeLawMaterial(*p_law, properties); p_law->CalculateMaterialResponseCauchy(parameters); const auto calculated_traction_vector = parameters.GetStressVector(); - const auto scoped_registration_law = ScopedSerializerRegistration{ - std::make_pair("InterfaceCoulombWithTensionCutOff"s, InterfaceCoulombWithTensionCutOff{})}; + const auto scoped_registration_law = + ScopedSerializerRegistration{std::make_pair("InterfaceCoulombLaw"s, InterfaceCoulombLaw{})}; auto serializer = StreamSerializer{}; // Act @@ -370,44 +377,43 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Serialization, Krato KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Has2DWorkingSpaceDimension, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(InterfaceCoulombWithTensionCutOff{std::make_unique()}.WorkingSpaceDimension(), - N_DIM_2D); + KRATOS_EXPECT_EQ( + InterfaceCoulombLaw{std::make_unique()}.WorkingSpaceDimension(), N_DIM_2D); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_HasCauchyStressMeasure, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(InterfaceCoulombWithTensionCutOff{std::make_unique()}.GetStressMeasure(), + KRATOS_EXPECT_EQ(InterfaceCoulombLaw{std::make_unique()}.GetStressMeasure(), ConstitutiveLaw::StressMeasure_Cauchy); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_StrainSizeEqualsTwo, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ( - InterfaceCoulombWithTensionCutOff{std::make_unique()}.GetStrainSize(), 2); + KRATOS_EXPECT_EQ(InterfaceCoulombLaw{std::make_unique()}.GetStrainSize(), 2); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_HasInfinitesimalStrainMeasure, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(InterfaceCoulombWithTensionCutOff{std::make_unique()}.GetStrainMeasure(), + KRATOS_EXPECT_EQ(InterfaceCoulombLaw{std::make_unique()}.GetStrainMeasure(), ConstitutiveLaw::StrainMeasure_Infinitesimal); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_HasIncrementalFormulation, KratosGeoMechanicsFastSuiteWithoutKernel) { - EXPECT_TRUE(InterfaceCoulombWithTensionCutOff{std::make_unique()}.IsIncremental()); + EXPECT_TRUE(InterfaceCoulombLaw{std::make_unique()}.IsIncremental()); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_RequiresInitializeMaterialResponse, KratosGeoMechanicsFastSuiteWithoutKernel) { - EXPECT_TRUE(InterfaceCoulombWithTensionCutOff{std::make_unique()}.RequiresInitializeMaterialResponse()); + EXPECT_TRUE(InterfaceCoulombLaw{std::make_unique()}.RequiresInitializeMaterialResponse()); } KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Check, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; ConstitutiveLaw::Parameters parameters; Properties properties(3); parameters.SetMaterialProperties(properties); @@ -442,17 +448,6 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Check, KratosGeoMech [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_DILATANCY_ANGLE in the property with Id 3 has an invalid value: 40 is out of the range [0, 30].") properties.SetValue(GEO_DILATANCY_ANGLE, 30.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), - "GEO_TENSILE_STRENGTH does not exist in the property with Id 3.") - properties.SetValue(GEO_TENSILE_STRENGTH, -1.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: -1 is out of the range [0, 1.73205].") - properties.SetValue(GEO_TENSILE_STRENGTH, 2.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: 2 is out of the range [0, 1.73205].") - properties.SetValue(GEO_TENSILE_STRENGTH, 1.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "INTERFACE_NORMAL_STIFFNESS does not exist in the property with Id 3.") @@ -468,6 +463,19 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_Check, KratosGeoMech KRATOS_EXPECT_EXCEPTION_IS_THROWN( [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "INTERFACE_SHEAR_STIFFNESS in the property with Id 3 has an invalid value: -1 is out of the range [0, -).") properties.SetValue(INTERFACE_SHEAR_STIFFNESS, 1.0); + KRATOS_EXPECT_EQ(law.Check(properties, element_geometry, process_info), 0); + + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), + "GEO_TENSILE_STRENGTH does not exist in the property with Id 3.") + properties.SetValue(GEO_TENSILE_STRENGTH, -1.0); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: -1 is out of the range [0, 1.73205].") + properties.SetValue(GEO_TENSILE_STRENGTH, 2.0); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: 2 is out of the range [0, 1.73205].") + properties.SetValue(GEO_TENSILE_STRENGTH, 1.0); KRATOS_EXPECT_EQ(law.Check(properties, element_geometry, process_info), 0); } @@ -486,7 +494,7 @@ KRATOS_TEST_CASE_IN_SUITE(InterfaceCoulombWithTensionCutOff_CalculateConstitutiv auto parameters = ConstitutiveLaw::Parameters{}; parameters.SetMaterialProperties(properties); - auto law = InterfaceCoulombWithTensionCutOff{std::make_unique()}; + auto law = InterfaceCoulombLaw{std::make_unique()}; InitializeLawMaterial(law, properties); // Act diff --git a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_with_tension_cutoff.cpp b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_law.cpp similarity index 90% rename from applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_with_tension_cutoff.cpp rename to applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_law.cpp index 92ffbfaefe5c..7cb021a43b7f 100644 --- a/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_with_tension_cutoff.cpp +++ b/applications/GeoMechanicsApplication/tests/cpp_tests/custom_constitutive/test_mohr_coulomb_law.cpp @@ -11,7 +11,7 @@ // Mohamed Nabi // -#include "custom_constitutive/mohr_coulomb_with_tension_cutoff.h" +#include "custom_constitutive/mohr_coulomb_law.h" #include "custom_constitutive/plane_strain.h" #include "custom_constitutive/three_dimensional.h" #include "custom_utilities/registration_utilities.hpp" @@ -25,9 +25,9 @@ using namespace std::string_literals; namespace Kratos::Testing { -Vector CalculateMappedStressVector(Vector& rCauchyStressVector, - ConstitutiveLaw::Parameters& rParameters, - MohrCoulombWithTensionCutOff& rLaw) +Vector CalculateMappedStressVector(Vector& rCauchyStressVector, + ConstitutiveLaw::Parameters& rParameters, + MohrCoulombLaw& rLaw) { Vector strain_vector = ZeroVector(4); rParameters.SetStrainVector(strain_vector); @@ -44,10 +44,10 @@ Vector CalculateMappedStressVector(Vector& rCauchyStressVe return result; } -KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Clone, KratosGeoMechanicsFastSuiteWithoutKernel) +KRATOS_TEST_CASE_IN_SUITE(MohrCoulombLaw_Clone, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - const auto original_law = MohrCoulombWithTensionCutOff(std::make_unique()); + const auto original_law = MohrCoulombLaw(std::make_unique()); // Act auto p_cloned_law = original_law.Clone(); @@ -55,13 +55,13 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Clone, KratosGeoMechanics // Assert KRATOS_EXPECT_NE(p_cloned_law.get(), nullptr); KRATOS_EXPECT_NE(p_cloned_law.get(), &original_law); - KRATOS_EXPECT_NE(dynamic_cast(p_cloned_law.get()), nullptr); + KRATOS_EXPECT_NE(dynamic_cast(p_cloned_law.get()), nullptr); } -KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Check, KratosGeoMechanicsFastSuiteWithoutKernel) +KRATOS_TEST_CASE_IN_SUITE(MohrCoulombLaw_Check, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); ConstitutiveLaw::Parameters parameters; Properties properties(3); parameters.SetMaterialProperties(properties); @@ -71,16 +71,6 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Check, KratosGeoMechanics // Act & Assert properties.SetValue(GEO_COHESION, 1.0); properties.SetValue(GEO_FRICTION_ANGLE, 30.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), - "GEO_TENSILE_STRENGTH does not exist in the property with Id 3.") - properties.SetValue(GEO_TENSILE_STRENGTH, -1.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: -1 is out of the range [0, 1.73205].") - properties.SetValue(GEO_TENSILE_STRENGTH, 2.0); - KRATOS_EXPECT_EXCEPTION_IS_THROWN( - [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: 2 is out of the range [0, 1.73205].") - properties.SetValue(GEO_TENSILE_STRENGTH, 1.0); KRATOS_EXPECT_EXCEPTION_IS_THROWN( [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), @@ -101,6 +91,19 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Check, KratosGeoMechanics [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), " POISSON_RATIO in the property with Id 3 has an invalid value: 1 is out of the range [0, 0.5].") properties.SetValue(POISSON_RATIO, 0.3); + KRATOS_EXPECT_EQ(law.Check(properties, element_geometry, process_info), 0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), + "GEO_TENSILE_STRENGTH does not exist in the property with Id 3.") + properties.SetValue(GEO_TENSILE_STRENGTH, -1.0); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: -1 is out of the range [0, 1.73205].") + properties.SetValue(GEO_TENSILE_STRENGTH, 2.0); + KRATOS_EXPECT_EXCEPTION_IS_THROWN( + [[maybe_unused]] const auto unused = law.Check(properties, element_geometry, process_info), "GEO_TENSILE_STRENGTH in the property with Id 3 has an invalid value: 2 is out of the range [0, 1.73205].") + properties.SetValue(GEO_TENSILE_STRENGTH, 1.0); + KRATOS_EXPECT_EQ(law.Check(properties, element_geometry, process_info), 0); } @@ -108,11 +111,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); ConstitutiveLaw::Parameters parameters; @@ -145,11 +149,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.25); @@ -212,11 +217,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.25); @@ -267,11 +273,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.0); @@ -318,11 +325,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.0); @@ -358,7 +366,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(YOUNG_MODULUS, 1.0e6); @@ -366,6 +374,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 20.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -385,13 +394,14 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Serialization, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto p_law = std::unique_ptr{ - std::make_unique(std::make_unique())}; + auto p_law = + std::unique_ptr{std::make_unique(std::make_unique())}; Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"s); properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -412,8 +422,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Serialization, KratosGeoM p_law->GetValue(CAUCHY_STRESS_VECTOR, calculated_cauchy_stress_vector); const auto scoped_registration = ScopedSerializerRegistration{ - std::make_pair("PlaneStrain"s, PlaneStrain{}), - std::make_pair("MohrCoulombWithTensionCutOff"s, MohrCoulombWithTensionCutOff{})}; + std::make_pair("PlaneStrain"s, PlaneStrain{}), std::make_pair("MohrCoulombLaw"s, MohrCoulombLaw{})}; auto serializer = StreamSerializer{}; ConstitutiveLaw::Parameters parameters_to_be_ignored; @@ -441,7 +450,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Serialization, KratosGeoM KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateConstitutiveMatrix, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(YOUNG_MODULUS, 1.0e8); @@ -449,6 +458,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateConstitutiveMatr properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -479,53 +489,52 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateConstitutiveMatr KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_WorkingSpaceDimensionDependsOnConstitutiveLawDimension, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.WorkingSpaceDimension(), 2); - KRATOS_EXPECT_EQ( - MohrCoulombWithTensionCutOff{std::make_unique()}.WorkingSpaceDimension(), 3); + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.WorkingSpaceDimension(), 2); + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.WorkingSpaceDimension(), 3); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_StressMeasureIsAlwaysCauchy, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStressMeasure(), + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStressMeasure(), ConstitutiveLaw::StressMeasure_Cauchy); - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStressMeasure(), + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStressMeasure(), ConstitutiveLaw::StressMeasure_Cauchy); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_StrainSizeDependsOnConstitutiveLawDimension, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStrainSize(), 4); - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStrainSize(), 6); + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStrainSize(), 4); + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStrainSize(), 6); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_StrainMeasureIsAlwaysInfinitesimal, KratosGeoMechanicsFastSuiteWithoutKernel) { - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStrainMeasure(), + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStrainMeasure(), ConstitutiveLaw::StrainMeasure_Infinitesimal); - KRATOS_EXPECT_EQ(MohrCoulombWithTensionCutOff{std::make_unique()}.GetStrainMeasure(), + KRATOS_EXPECT_EQ(MohrCoulombLaw{std::make_unique()}.GetStrainMeasure(), ConstitutiveLaw::StrainMeasure_Infinitesimal); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_HasIncrementalFormulation, KratosGeoMechanicsFastSuiteWithoutKernel) { - EXPECT_TRUE(MohrCoulombWithTensionCutOff{std::make_unique()}.IsIncremental()); - EXPECT_TRUE(MohrCoulombWithTensionCutOff{std::make_unique()}.IsIncremental()); + EXPECT_TRUE(MohrCoulombLaw{std::make_unique()}.IsIncremental()); + EXPECT_TRUE(MohrCoulombLaw{std::make_unique()}.IsIncremental()); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_RequiresInitializeMaterialResponse, KratosGeoMechanicsFastSuiteWithoutKernel) { - EXPECT_TRUE(MohrCoulombWithTensionCutOff{std::make_unique()}.RequiresInitializeMaterialResponse()); - EXPECT_TRUE(MohrCoulombWithTensionCutOff{std::make_unique()}.RequiresInitializeMaterialResponse()); + EXPECT_TRUE(MohrCoulombLaw{std::make_unique()}.RequiresInitializeMaterialResponse()); + EXPECT_TRUE(MohrCoulombLaw{std::make_unique()}.RequiresInitializeMaterialResponse()); } KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_GetPlaneStrainLawFeatures, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange & act ConstitutiveLaw::Features features; - MohrCoulombWithTensionCutOff{std::make_unique()}.GetLawFeatures(features); + MohrCoulombLaw{std::make_unique()}.GetLawFeatures(features); // Assert KRATOS_EXPECT_TRUE(features.GetOptions().Is(ConstitutiveLaw::INFINITESIMAL_STRAINS)) @@ -540,7 +549,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_Get3DLawFeatures, KratosG { // Arrange & act ConstitutiveLaw::Features features; - MohrCoulombWithTensionCutOff{std::make_unique()}.GetLawFeatures(features); + MohrCoulombLaw{std::make_unique()}.GetLawFeatures(features); // Assert KRATOS_EXPECT_TRUE(features.GetOptions().Is(ConstitutiveLaw::INFINITESIMAL_STRAINS)) @@ -555,12 +564,13 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -587,12 +597,13 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.0); @@ -615,12 +626,13 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.0); @@ -639,11 +651,11 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse Defaults::absolute_tolerance); } -KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_TrialStressInDegeneratedTensileApexReturnZoneIsReturnedToApex, +KRATOS_TEST_CASE_IN_SUITE(MohrCoulombLawWithoutTensionCutoff_TrialStressInDegeneratedTensileApexReturnZoneIsReturnedToApex, KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); constexpr auto phi_in_degrees = 30.0; @@ -651,10 +663,9 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_TrialStressInDegeneratedT constexpr auto cohesion = 10.0; properties.SetValue(GEO_COHESION, cohesion); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); - const auto tensile_strength = cohesion / std::tan(MathUtils<>::DegreesToRadians(phi_in_degrees)); - properties.SetValue(GEO_TENSILE_STRENGTH, tensile_strength); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.15); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, false); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); const auto dummy_element_geometry = Geometry{}; @@ -662,16 +673,15 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_TrialStressInDegeneratedT law.InitializeMaterial(properties, dummy_element_geometry, dummy_shape_function_values); // Act - auto cauchy_stress_vector = UblasUtilities::CreateVector( - {tensile_strength + 20.0, tensile_strength + 10.0, tensile_strength, 0.0}); + const auto apex = cohesion / std::tan(MathUtils<>::DegreesToRadians(phi_in_degrees)); + auto cauchy_stress_vector = UblasUtilities::CreateVector({apex + 20.0, apex + 10.0, apex, 0.0}); const auto resulting_cauchy_stress_vector = CalculateMappedStressVector(cauchy_stress_vector, parameters, law); auto plasticity_status = 0; law.GetValue(GEO_PLASTICITY_STATUS, plasticity_status); // Assert - const auto expected_cauchy_stress_vector = - UblasUtilities::CreateVector({tensile_strength, tensile_strength, tensile_strength, 0.0}); + const auto expected_cauchy_stress_vector = UblasUtilities::CreateVector({apex, apex, apex, 0.0}); KRATOS_EXPECT_VECTOR_NEAR(resulting_cauchy_stress_vector, expected_cauchy_stress_vector, Defaults::absolute_tolerance); KRATOS_EXPECT_EQ(plasticity_status, static_cast(PlasticityStatus::TENSION_MOHR_COULOMB_CORNER)); @@ -681,7 +691,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(YOUNG_MODULUS, 1.0e6); @@ -689,6 +699,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -715,7 +726,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_DoesNotCalculateStressWhe KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(YOUNG_MODULUS, 1.0e6); @@ -723,6 +734,7 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_DoesNotCalculateStressWhe properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -751,12 +763,13 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(GEO_FRICTION_ANGLE, 35.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 20.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, -1.0); ConstitutiveLaw::Parameters parameters; parameters.SetMaterialProperties(properties); @@ -776,13 +789,14 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutOff_CalculateMaterialResponse KratosGeoMechanicsFastSuiteWithoutKernel) { // Arrange - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); Properties properties; properties.SetValue(GEO_DRAINAGE_TYPE, "FULLY_COUPLED"); properties.SetValue(GEO_COULOMB_HARDENING_TYPE, "Linear"); properties.SetValue(GEO_FRICTION_ANGLE, 30.0); properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 10.0); properties.SetValue(YOUNG_MODULUS, 1.0e6); properties.SetValue(POISSON_RATIO, 0.0); @@ -843,11 +857,12 @@ Vector ComputeStressVectorUsingCPhiReductionTestData(double Cohesion, properties.SetValue(GEO_COHESION, Cohesion); properties.SetValue(GEO_FRICTION_ANGLE, FrictionAngle); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 1000.0); properties.SetValue(YOUNG_MODULUS, 30.0e6); properties.SetValue(POISSON_RATIO, 0.2); - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); const auto dummy_element_geometry = Geometry{}; const auto dummy_shape_function_values = Vector{}; @@ -964,11 +979,12 @@ KRATOS_TEST_CASE_IN_SUITE(MohrCoulombWithTensionCutoff_InitialPlasticityStatusEq properties.SetValue(GEO_COHESION, 10.0); properties.SetValue(GEO_FRICTION_ANGLE, 30.0); properties.SetValue(GEO_DILATANCY_ANGLE, 0.0); + properties.SetValue(GEO_ENABLE_TENSION_CUT_OFF, true); properties.SetValue(GEO_TENSILE_STRENGTH, 1000.0); properties.SetValue(YOUNG_MODULUS, 30.0e6); properties.SetValue(POISSON_RATIO, 0.2); - auto law = MohrCoulombWithTensionCutOff(std::make_unique()); + auto law = MohrCoulombLaw(std::make_unique()); const auto dummy_element_geometry = Geometry{}; const auto dummy_shape_function_values = Vector{}; diff --git a/applications/GeoMechanicsApplication/tests/cpp_tests/geo_mechanics_fast_suite_without_kernel.cpp b/applications/GeoMechanicsApplication/tests/cpp_tests/geo_mechanics_fast_suite_without_kernel.cpp index 741b8601685e..b2785cd3291f 100644 --- a/applications/GeoMechanicsApplication/tests/cpp_tests/geo_mechanics_fast_suite_without_kernel.cpp +++ b/applications/GeoMechanicsApplication/tests/cpp_tests/geo_mechanics_fast_suite_without_kernel.cpp @@ -52,6 +52,7 @@ KratosGeoMechanicsFastSuiteWithoutKernel::KratosGeoMechanicsFastSuiteWithoutKern KRATOS_REGISTER_VARIABLE(GEO_FRICTION_ANGLE) KRATOS_REGISTER_VARIABLE(GEO_COHESION) KRATOS_REGISTER_VARIABLE(GEO_DILATANCY_ANGLE) + KRATOS_REGISTER_VARIABLE(GEO_ENABLE_TENSION_CUT_OFF) KRATOS_REGISTER_VARIABLE(GEO_TENSILE_STRENGTH) KRATOS_REGISTER_VARIABLE(GEO_MAX_PLASTIC_ITERATIONS) KRATOS_REGISTER_VARIABLE(GEO_ABS_YIELD_FUNCTION_TOLERANCE) diff --git a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/MaterialParameters.json index bd899aa43de6..6e36e09803f2 100644 --- a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/MaterialParameters.json @@ -5,7 +5,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -23,7 +23,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -33,7 +33,7 @@ "properties_id": 2, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -51,7 +51,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -61,7 +61,7 @@ "properties_id": 3, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -79,7 +79,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -89,7 +89,7 @@ "properties_id": 4, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -107,7 +107,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -117,7 +117,7 @@ "properties_id": 5, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -135,7 +135,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.5, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -145,7 +145,7 @@ "properties_id": 6, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -163,7 +163,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 32.5, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -173,7 +173,7 @@ "properties_id": 7, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -191,7 +191,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -201,7 +201,7 @@ "properties_id": 8, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -219,7 +219,7 @@ "MINIMUM_RELATIVE_PERMEABILITY": 1.0e-04, "GEO_COHESION": 3.0e+03, "GEO_FRICTION_ANGLE": 22.5, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "GEO_DILATANCY_ANGLE": 0.0 } } @@ -229,7 +229,7 @@ "properties_id": 9, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -238,7 +238,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -252,7 +252,7 @@ "properties_id": 10, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -261,7 +261,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -275,7 +275,7 @@ "properties_id": 11, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -284,7 +284,7 @@ "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 20.0, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -298,7 +298,7 @@ "properties_id": 12, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -307,7 +307,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -321,7 +321,7 @@ "properties_id": 13, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -330,7 +330,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -344,7 +344,7 @@ "properties_id": 14, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -353,7 +353,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -367,7 +367,7 @@ "properties_id": 15, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -376,7 +376,7 @@ "GEO_COHESION": 1.44065e+03, "GEO_FRICTION_ANGLE": 11.25, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 7.24263e+03, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, @@ -390,7 +390,7 @@ "properties_id": 16, "Material": { "constitutive_law": { - "name": "GeoInterfaceCoulombWithTensionCutOff" + "name": "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -399,7 +399,7 @@ "GEO_COHESION": 0.0, "GEO_FRICTION_ANGLE": 20.0, "GEO_DILATANCY_ANGLE": 0.0, - "GEO_TENSILE_STRENGTH": 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": false, "BIOT_COEFFICIENT": 1.0, "RETENTION_LAW": "SaturatedBelowPhreaticLevelLaw", "SATURATED_SATURATION": 1.0, diff --git a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/3_Wall_installation__expected_results_wall.csv b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/3_Wall_installation__expected_results_wall.csv index b9601fe5adcb..195f954b305b 100644 --- a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/3_Wall_installation__expected_results_wall.csv +++ b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/3_Wall_installation__expected_results_wall.csv @@ -11,7 +11,7 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4090,15084.1,-9329.6,-0.00600868 4102,17421.5,-8844.16,-0.00635568 4120,19486.2,-8238.82,-0.00668975 -4135,21549.0,-7634.68,-0.00700933 +4135,21549.0,-7634.67,-0.00700933 4148,23291.3,-6956.89,-0.00731291 4161,25032.4,-6280.28,-0.00759917 4172,26423.9,-5558.53,-0.00786685 @@ -47,8 +47,8 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4571,1795.19,3507.96,-0.00660404 4582,924.432,2461.82,-0.00637605 4595,539.331,1565.35,-0.00614732 -4604,169.336,718.947,-0.00591819 -4614,94.4921,384.744,-0.0056889 -4624,12.1328,55.508,-0.00545954 +4604,169.336,718.946,-0.00591819 +4614,94.4921,384.743,-0.0056889 +4624,12.1328,55.5083,-0.00545954 4633,11.4316,58.1114,-0.00523015 -4639,-3.09622,20.9569,-0.00500076 +4639,-3.09622,20.9568,-0.00500076 diff --git a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/4_First_excavation__expected_results_wall.csv b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/4_First_excavation__expected_results_wall.csv index 81e0360b38fd..da34361cc6da 100644 --- a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/4_First_excavation__expected_results_wall.csv +++ b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/4_First_excavation__expected_results_wall.csv @@ -28,7 +28,7 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4322,-17584.9,12290.7,-0.0284111 4338,-20665.3,12270.6,-0.0298497 4352,-23746.9,12254.0,-0.0313257 -4361,-26736.3,11901.4,-0.0328406 +4361,-26736.3,11901.5,-0.0328406 4375,-29729.9,11552.7,-0.0343958 4390,-32439.6,10766.0,-0.0359927 4403,-35158.1,9986.7,-0.0376322 @@ -38,7 +38,7 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4457,-41940.1,2217.02,-0.0446275 4470,-41668.8,-1249.35,-0.0464855 4483,-41413.3,-4675.49,-0.0483853 -4497,-39103.8,-9465.37,-0.0503251 +4497,-39103.8,-9465.38,-0.0503251 4509,-36661.7,-14472.2,-0.052302 4522,-32170.6,-17661.7,-0.0543126 4536,-27661.7,-20528.4,-0.0563525 @@ -49,6 +49,6 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4595,-5348.15,-10308.3,-0.0668249 4604,-2807.88,-7138.78,-0.0689453 4614,-1631.54,-4852.56,-0.0710681 -4624,-455.179,-2592.7,-0.0731922 +4624,-455.179,-2592.69,-0.0731922 4633,-188.084,-1215.49,-0.0753167 -4639,115.789,173.976,-0.0774414 +4639,115.789,173.971,-0.0774414 diff --git a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/7_Third_excavation__expected_results_wall.csv b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/7_Third_excavation__expected_results_wall.csv index 37667e47f9ad..bc2139341568 100644 --- a/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/7_Third_excavation__expected_results_wall.csv +++ b/applications/GeoMechanicsApplication/tests/crow_validation/mohr_coulomb_clay-sand/staged_construction/7_Third_excavation__expected_results_wall.csv @@ -1,5 +1,5 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_in_m -3968,-453.737,-7386.38,-0.0153258 +3968,-453.737,-7386.37,-0.0153258 3982,2754.07,-12831.2,-0.0173536 3996,5322.71,-17087.8,-0.0193781 4010,13854.6,-36684.4,-0.0213953 @@ -31,7 +31,7 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4361,324218.0,30171.7,-0.0434495 4375,316654.0,37393.7,-0.0421605 4390,305606.0,44109.6,-0.0407082 -4403,294559.0,50826.4,-0.0391025 +4403,294559.0,50826.5,-0.0391025 4415,280270.0,57078.4,-0.0373536 4430,265980.0,63324.4,-0.0354725 4444,248689.0,69082.6,-0.0334698 @@ -51,4 +51,4 @@ node,bending_moment_in_Nm_per_m,shear_force_in_N_per_m,horizontal_displacement_i 4614,-4083.95,-10493.4,0.0014717 4624,-1464.33,-6959.38,0.00410448 4633,-589.333,-3514.93,0.00673654 -4639,289.401,-42.123,0.00936835 +4639,289.401,-42.1226,0.00936835 diff --git a/applications/GeoMechanicsApplication/tests/test_element_lab/test_crs/drained/mohr_coulomb/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/test_element_lab/test_crs/drained/mohr_coulomb/MaterialParameters.json index 15deed90d5b6..5d5c47f1649d 100644 --- a/applications/GeoMechanicsApplication/tests/test_element_lab/test_crs/drained/mohr_coulomb/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/test_element_lab/test_crs/drained/mohr_coulomb/MaterialParameters.json @@ -5,7 +5,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -17,6 +17,7 @@ "POISSON_RATIO": 0.25, "GEO_COHESION": 2.0e+03, "GEO_FRICTION_ANGLE": 25.0, + "GEO_ENABLE_TENSION_CUT_OFF": true, "GEO_TENSILE_STRENGTH": 0.0, "GEO_DILATANCY_ANGLE": 2.0 } diff --git a/applications/GeoMechanicsApplication/tests/test_element_lab/test_dss/drained/mohr_coulomb/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/test_element_lab/test_dss/drained/mohr_coulomb/MaterialParameters.json index 15deed90d5b6..5d5c47f1649d 100644 --- a/applications/GeoMechanicsApplication/tests/test_element_lab/test_dss/drained/mohr_coulomb/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/test_element_lab/test_dss/drained/mohr_coulomb/MaterialParameters.json @@ -5,7 +5,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -17,6 +17,7 @@ "POISSON_RATIO": 0.25, "GEO_COHESION": 2.0e+03, "GEO_FRICTION_ANGLE": 25.0, + "GEO_ENABLE_TENSION_CUT_OFF": true, "GEO_TENSILE_STRENGTH": 0.0, "GEO_DILATANCY_ANGLE": 2.0 } diff --git a/applications/GeoMechanicsApplication/tests/test_element_lab/test_triaxial/drained/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/test_element_lab/test_triaxial/drained/MaterialParameters.json index ca1cb4612993..4e17d2222844 100644 --- a/applications/GeoMechanicsApplication/tests/test_element_lab/test_triaxial/drained/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/test_element_lab/test_triaxial/drained/MaterialParameters.json @@ -5,7 +5,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name": "GeoMohrCoulombWithTensionCutOff2D" + "name": "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE": "CONSTANT_PW_FIELD", @@ -17,6 +17,7 @@ "POISSON_RATIO": 0.25, "GEO_COHESION": 2.0, "GEO_FRICTION_ANGLE": 25.0, + "GEO_ENABLE_TENSION_CUT_OFF": true, "GEO_TENSILE_STRENGTH": 0.0, "GEO_DILATANCY_ANGLE": 2.0 } diff --git a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters2D.json b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters2D.json index 0cb6641b1949..45c7a4276a6e 100644 --- a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters2D.json +++ b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters2D.json @@ -4,7 +4,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoMohrCoulombWithTensionCutOff2D" + "name" : "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE" : "FULLY_COUPLED", @@ -24,6 +24,7 @@ "SATURATED_SATURATION" : 1.0, "GEO_COHESION" : 10.0, "GEO_FRICTION_ANGLE" : 35.0, + "GEO_ENABLE_TENSION_CUT_OFF" : true, "GEO_TENSILE_STRENGTH" : 10.0, "GEO_DILATANCY_ANGLE" : 20.0 } diff --git a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters3D.json b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters3D.json index 72277b663d61..97ea52fc9aef 100644 --- a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters3D.json +++ b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/common/MaterialParameters3D.json @@ -4,7 +4,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoMohrCoulombWithTensionCutOff3D" + "name" : "GeoMohrCoulombLaw3D" }, "Variables": { "GEO_DRAINAGE_TYPE" : "FULLY_COUPLED", @@ -27,6 +27,7 @@ "SATURATED_SATURATION" : 1.0, "GEO_COHESION" : 10.0, "GEO_FRICTION_ANGLE" : 35.0, + "GEO_ENABLE_TENSION_CUT_OFF" : true, "GEO_TENSILE_STRENGTH" : 10.0, "GEO_DILATANCY_ANGLE" : 20.0 } diff --git a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/interface_coulomb_2plus2/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/interface_coulomb_2plus2/MaterialParameters.json index d3647ba860ad..846cf4124f66 100644 --- a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/interface_coulomb_2plus2/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/interface_coulomb_2plus2/MaterialParameters.json @@ -4,13 +4,14 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoInterfaceCoulombWithTensionCutOff" + "name" : "GeoInterfaceCoulombLawPlaneStrain" }, "Variables": { "INTERFACE_NORMAL_STIFFNESS" : 30000000, "INTERFACE_SHEAR_STIFFNESS" : 5000, "GEO_COHESION" : 10.0, "GEO_FRICTION_ANGLE" : 35.0, + "GEO_ENABLE_TENSION_CUT_OFF" : true, "GEO_TENSILE_STRENGTH" : 10.0, "GEO_DILATANCY_ANGLE" : 0.0, "GEO_DRAINAGE_TYPE" : "FULLY_COUPLED" diff --git a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_column_under_gravity/MaterialParameters.json b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_column_under_gravity/MaterialParameters.json index 86e8e7c58e00..7cb2011e4216 100644 --- a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_column_under_gravity/MaterialParameters.json +++ b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_column_under_gravity/MaterialParameters.json @@ -4,25 +4,26 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoMohrCoulombWithTensionCutOff2D" + "name" : "GeoMohrCoulombLawPlaneStrain" }, "Variables": { - "GEO_DRAINAGE_TYPE" : "CONSTANT_PW_FIELD", - "DENSITY_SOLID" : 3.0e3, - "DENSITY_WATER" : 1.0e3, - "POROSITY" : 0.3, - "BULK_MODULUS_SOLID" : 1.0e9, - "BULK_MODULUS_FLUID" : 2.0e6, - "PERMEABILITY_XX" : 4.5e-13, - "PERMEABILITY_YY" : 4.5e-13, - "PERMEABILITY_XY" : 0.0, - "DYNAMIC_VISCOSITY" : 8.90e-7, - "YOUNG_MODULUS" : 30.0e6, - "POISSON_RATIO" : 0.0, - "GEO_COHESION" : 1000.0, - "GEO_FRICTION_ANGLE" : 30.0, - "GEO_DILATANCY_ANGLE" : 0.0, - "GEO_TENSILE_STRENGTH" : 1000.0 + "GEO_DRAINAGE_TYPE" : "CONSTANT_PW_FIELD", + "DENSITY_SOLID" : 3.0e3, + "DENSITY_WATER" : 1.0e3, + "POROSITY" : 0.3, + "BULK_MODULUS_SOLID" : 1.0e9, + "BULK_MODULUS_FLUID" : 2.0e6, + "PERMEABILITY_XX" : 4.5e-13, + "PERMEABILITY_YY" : 4.5e-13, + "PERMEABILITY_XY" : 0.0, + "DYNAMIC_VISCOSITY" : 8.90e-7, + "YOUNG_MODULUS" : 30.0e6, + "POISSON_RATIO" : 0.0, + "GEO_COHESION" : 1000.0, + "GEO_FRICTION_ANGLE" : 30.0, + "GEO_DILATANCY_ANGLE" : 0.0, + "GEO_ENABLE_TENSION_CUT_OFF": true, + "GEO_TENSILE_STRENGTH" : 1000.0 } } }] diff --git a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_dirichlet_tension_apex_return_zone_2d/MaterialParameters2D.json b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_dirichlet_tension_apex_return_zone_2d/MaterialParameters2D.json index bfe3bba355c0..144a4c7f0e57 100644 --- a/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_dirichlet_tension_apex_return_zone_2d/MaterialParameters2D.json +++ b/applications/GeoMechanicsApplication/tests/test_mohr_coulomb_with_tension_cutoff/test_dirichlet_tension_apex_return_zone_2d/MaterialParameters2D.json @@ -4,7 +4,7 @@ "properties_id": 1, "Material": { "constitutive_law": { - "name" : "GeoMohrCoulombWithTensionCutOff2D" + "name" : "GeoMohrCoulombLawPlaneStrain" }, "Variables": { "GEO_DRAINAGE_TYPE" : "FULLY_COUPLED", @@ -24,6 +24,7 @@ "SATURATED_SATURATION" : 1.0, "GEO_COHESION" : 10.0, "GEO_FRICTION_ANGLE" : 35.0, + "GEO_ENABLE_TENSION_CUT_OFF" : true, "GEO_TENSILE_STRENGTH" : 10.0, "GEO_DILATANCY_ANGLE" : 20.0 } From 9b18902eaab73baa26dbf520b24e6036ff040b9a Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 26 May 2026 17:30:22 +0200 Subject: [PATCH 42/50] first step --- .../mpm_updated_lagrangian_UP.cpp | 65 +++++++++---------- .../mpm_updated_lagrangian_UP.hpp | 5 +- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index 939b4fe14694..f36c85cd1eed 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -377,9 +377,9 @@ void MPMUpdatedLagrangianUP::CalculateAndAddRHS( const double& rIntegrationWeight, const ProcessInfo& rCurrentProcessInfo) { - rVariables.detF0 *= rVariables.detF; - double determinant_F = rVariables.detF; - rVariables.detF = 1; //in order to simplify updated and spatial lagrangian + //rVariables.detF0 *= rVariables.detF; + //double determinant_F = rVariables.detF; + //rVariables.detF = 1; //in order to simplify updated and spatial lagrangian // Operation performed: rRightHandSideVector += ExtForce*IntegrationWeight CalculateAndAddExternalForces( rRightHandSideVector, rVariables, rVolumeForce, rIntegrationWeight ); @@ -394,8 +394,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddRHS( // Operation performed: rRightHandSideVector -= Stabilized Pressure Forces CalculateAndAddStabilizedPressure( rRightHandSideVector, rVariables, rIntegrationWeight); - rVariables.detF = determinant_F; - rVariables.detF0 /= rVariables.detF; + //rVariables.detF = determinant_F; + //rVariables.detF0 /= rVariables.detF; } //************************************************************************************ @@ -454,31 +454,32 @@ void MPMUpdatedLagrangianUP::CalculateAndAddInternalForces(VectorType& rRightHan //****************************************************************************************************************** //****************************************************************************************************************** -double& MPMUpdatedLagrangianUP::CalculatePUCoefficient(double& rCoefficient, GeneralVariables & rVariables) + + +double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolumetricStrainFunction, GeneralVariables & rVariables) + { KRATOS_TRY - // TODO: Check what is the meaning of this function - rCoefficient = rVariables.detF0 - 1; - - return rCoefficient; + rVolumetricStrainFunction = (1- (1/rVariables.detFT)); //rVariables.detFT - 1; // rVariables.detF0*rVariables.detF - 1; + return rVolumetricStrainFunction; KRATOS_CATCH( "" ) } - //************************************************************************************ //************************************************************************************ -double& MPMUpdatedLagrangianUP::CalculatePUDeltaCoefficient(double &rDeltaCoefficient, GeneralVariables & rVariables) + +double& MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizarionOfVolumetricStrain(double &rFunction, GeneralVariables & rVariables) + { KRATOS_TRY - // TODO: Check what is the meaning of this function - rDeltaCoefficient = 1.0; + rFunction= 1.0; - return rDeltaCoefficient; + return rFunction; KRATOS_CATCH( "" ) @@ -507,11 +508,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan if (bulk_modulus != bulk_modulus) bulk_modulus = 1.e16; - double delta_coefficient = 0; - delta_coefficient = this->CalculatePUDeltaCoefficient( delta_coefficient, rVariables ); - - double coefficient = 0; - coefficient = this->CalculatePUCoefficient( coefficient, rVariables ); + double VolumetricStrainFunction = this->CalculateVolumetricStrainFunction( VolumetricStrainFunction, rVariables ); for ( unsigned int i = 0; i < number_of_nodes; i++ ) { @@ -519,11 +516,11 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan { const double& pressure = r_geometry[j].FastGetSolutionStepValue(PRESSURE); - rRightHandSideVector[index_p] += (1.0/(delta_coefficient * bulk_modulus)) * r_N(0, i) * r_N(0, j) * pressure * rIntegrationWeight / (rVariables.detF0/rVariables.detF) ; //2D-3D + rRightHandSideVector[index_p] += (1.0 / bulk_modulus) * r_N(0, i) * r_N(0, j) * pressure * rIntegrationWeight; //2D-3D } - rRightHandSideVector[index_p] -= coefficient/delta_coefficient * r_N(0, i) * rIntegrationWeight / (rVariables.detF0/rVariables.detF); - + rRightHandSideVector[index_p] -= VolumetricStrainFunction * r_N(0, i) * rIntegrationWeight; //FLUID-UP + //rRightHandSideVector[index_p] -= (1.0 - 1.0 / rVariables.detFT) * r_N(0, i) * rIntegrationWeight; index_p += (dimension + 1); } @@ -576,7 +573,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddStabilizedPressure(VectorType& rRigh if (i == j) consistent = 2 * alpha_stabilization / 36.0; - rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight / (rVariables.detF0/rVariables.detF); //2D + rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight; //2D } else { @@ -584,7 +581,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddStabilizedPressure(VectorType& rRigh if (i == j) consistent = 3 * alpha_stabilization / 80.0; - rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight / (rVariables.detF0/rVariables.detF) ; //3D + rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight; //3D } } index_p += (dimension + 1); @@ -601,9 +598,9 @@ void MPMUpdatedLagrangianUP::CalculateAndAddLHS( const double& rIntegrationWeight, const ProcessInfo& rCurrentProcessInfo) { - rVariables.detF0 *= rVariables.detF; - double determinant_F = rVariables.detF; - rVariables.detF = 1; //in order to simplify updated and spatial lagrangian + //rVariables.detF0 *= rVariables.detF; + //double determinant_F = rVariables.detF; + //rVariables.detF = 1; //in order to simplify updated and spatial lagrangian // Operation performed: add Km to the rLefsHandSideMatrix CalculateAndAddKuum( rLeftHandSideMatrix, rVariables, rIntegrationWeight ); @@ -627,8 +624,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddLHS( // Operation performed: add Kpp_Stab to the rLefsHandSideMatrix CalculateAndAddKppStab( rLeftHandSideMatrix, rVariables, rIntegrationWeight ); - rVariables.detF = determinant_F; - rVariables.detF0 /= rVariables.detF; + //rVariables.detF = determinant_F; + //rVariables.detF0 /= rVariables.detF; } //************************************************************************************ @@ -766,7 +763,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpu (MatrixType& rLeftHandSideMatrix unsigned int index_up = dimension*j + j; for ( unsigned int k = 0; k < dimension; k++ ) { - rLeftHandSideMatrix(index_p,index_up+k) += r_N(0, i) * rVariables.DN_DX ( j, k ) * rIntegrationWeight * rVariables.detF; + rLeftHandSideMatrix(index_p,index_up+k) += r_N(0, i) * rVariables.DN_DX ( j, k ) * rIntegrationWeight; } } index_p += (dimension + 1); @@ -802,7 +799,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpp (MatrixType& rLeftHandSideMatrix unsigned int indexpj = dimension; for (unsigned int j = 0; j < number_of_nodes; j++) { - rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight /((rVariables.detF0/rVariables.detF)); + rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight; indexpj += (dimension + 1); } @@ -863,7 +860,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKppStab (MatrixType& rLeftHandSideMa if (indexpi == indexpj) consistent = 2 * alpha_stabilization / 36.0; - rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight / (rVariables.detF0/rVariables.detF) ; //2D + rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight; //2D } else { @@ -871,7 +868,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKppStab (MatrixType& rLeftHandSideMa if (indexpi == indexpj) consistent = 3 * alpha_stabilization / 80.0; - rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight / (rVariables.detF0/rVariables.detF); //3D + rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight; //3D } indexpj += (dimension + 1); } diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp index a058aea32ab9..f7ca0f1e16e8 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp @@ -371,12 +371,13 @@ class MPMUpdatedLagrangianUP /** * Calculation of the constitutive coefficient for pressure of the Element */ - virtual double& CalculatePUCoefficient(double& rCoefficient, GeneralVariables & rVariables); + virtual double& CalculateVolumetricStrainFunction(double& rCoefficient, GeneralVariables & rVariables); /** * Calculation of the constitutive coefficient derivative for pressure of the Element */ - virtual double& CalculatePUDeltaCoefficient(double& rCoefficient, GeneralVariables & rVariables); + virtual double& CalculateFunctionFromLinearizarionOfVolumetricStrain(double& rCoefficient, GeneralVariables & rVariables); + /** * Get the Historical Deformation Gradient to calculate after finalize the step From 6e33be50329365c764e4ba130fd861000175318b Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 26 May 2026 17:53:13 +0200 Subject: [PATCH 43/50] kup_updated --- .../custom_elements/mpm_updated_lagrangian_UP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index f36c85cd1eed..bf53f1df21a0 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -461,7 +461,7 @@ double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolum { KRATOS_TRY - rVolumetricStrainFunction = (1- (1/rVariables.detFT)); //rVariables.detFT - 1; // rVariables.detF0*rVariables.detF - 1; + rVolumetricStrainFunction = (1- (1/rVariables.detFT)); return rVolumetricStrainFunction; KRATOS_CATCH( "" ) From 265cd07e9f12e45e700c64540a4898db2577fa1d Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 26 May 2026 18:16:44 +0200 Subject: [PATCH 44/50] fixing mistake at function name --- .../custom_elements/mpm_updated_lagrangian_UP.cpp | 15 +++++++-------- .../custom_elements/mpm_updated_lagrangian_UP.hpp | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index bf53f1df21a0..61a7bddb2679 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -471,7 +471,7 @@ double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolum //************************************************************************************ -double& MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizarionOfVolumetricStrain(double &rFunction, GeneralVariables & rVariables) +double& MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizationOfVolumetricStrain(double &rFunction, GeneralVariables & rVariables) { @@ -516,7 +516,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan { const double& pressure = r_geometry[j].FastGetSolutionStepValue(PRESSURE); - rRightHandSideVector[index_p] += (1.0 / bulk_modulus) * r_N(0, i) * r_N(0, j) * pressure * rIntegrationWeight; //2D-3D + rRightHandSideVector[index_p] += (1.0 / bulk_modulus) * r_N(0, i) * r_N(0, j) * pressure * rIntegrationWeight / rVariables.detFT; //2D-3D } rRightHandSideVector[index_p] -= VolumetricStrainFunction * r_N(0, i) * rIntegrationWeight; //FLUID-UP @@ -573,7 +573,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddStabilizedPressure(VectorType& rRigh if (i == j) consistent = 2 * alpha_stabilization / 36.0; - rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight; //2D + rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight / rVariables.detFT; //2D } else { @@ -581,7 +581,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddStabilizedPressure(VectorType& rRigh if (i == j) consistent = 3 * alpha_stabilization / 80.0; - rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight; //3D + rRightHandSideVector[index_p] += consistent * pressure * rIntegrationWeight / rVariables.detFT; //3D } } index_p += (dimension + 1); @@ -799,7 +799,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpp (MatrixType& rLeftHandSideMatrix unsigned int indexpj = dimension; for (unsigned int j = 0; j < number_of_nodes; j++) { - rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight; + rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight / rVariables.detFT; indexpj += (dimension + 1); } @@ -860,7 +860,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKppStab (MatrixType& rLeftHandSideMa if (indexpi == indexpj) consistent = 2 * alpha_stabilization / 36.0; - rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight; //2D + rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight / rVariables.detFT; //2D } else { @@ -868,7 +868,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKppStab (MatrixType& rLeftHandSideMa if (indexpi == indexpj) consistent = 3 * alpha_stabilization / 80.0; - rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight; //3D + rLeftHandSideMatrix(indexpi, indexpj) -= consistent * rIntegrationWeight / rVariables.detFT; //3D } indexpj += (dimension + 1); } @@ -1210,4 +1210,3 @@ void MPMUpdatedLagrangianUP::load( Serializer& rSerializer ) } } // Namespace Kratos - diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp index f7ca0f1e16e8..853c92571d93 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp @@ -376,7 +376,7 @@ class MPMUpdatedLagrangianUP /** * Calculation of the constitutive coefficient derivative for pressure of the Element */ - virtual double& CalculateFunctionFromLinearizarionOfVolumetricStrain(double& rCoefficient, GeneralVariables & rVariables); + virtual double& CalculateFunctionFromLinearizationOfVolumetricStrain(double& rCoefficient, GeneralVariables & rVariables); /** From a8e0b8bb0d5ab83985dd6efaea1d9927615fd9cc Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 26 May 2026 18:25:51 +0200 Subject: [PATCH 45/50] removing comments --- .../custom_elements/mpm_updated_lagrangian_UP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index 61a7bddb2679..922c7f9bf321 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -731,7 +731,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKup (MatrixType& rLeftHandSideMatrix { for ( unsigned int k = 0; k < dimension; k++ ) { - rLeftHandSideMatrix(index_up+k,index_p) += rVariables.DN_DX ( i, k ) * r_N(0, j) * rIntegrationWeight * rVariables.detF; + rLeftHandSideMatrix(index_up+k,index_p) += rVariables.DN_DX ( i, k ) * r_N(0, j) * rIntegrationWeight; } index_p += (dimension + 1); } From 0056765c666ee882faab155a6c4da18377d62ae6 Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 26 May 2026 18:43:09 +0200 Subject: [PATCH 46/50] cleaning spaces and renaming variables/functions --- .../mpm_updated_lagrangian_UP.cpp | 32 +++++-------------- .../mpm_updated_lagrangian_UP.hpp | 4 +-- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index 922c7f9bf321..929aacc579ac 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -377,10 +377,6 @@ void MPMUpdatedLagrangianUP::CalculateAndAddRHS( const double& rIntegrationWeight, const ProcessInfo& rCurrentProcessInfo) { - //rVariables.detF0 *= rVariables.detF; - //double determinant_F = rVariables.detF; - //rVariables.detF = 1; //in order to simplify updated and spatial lagrangian - // Operation performed: rRightHandSideVector += ExtForce*IntegrationWeight CalculateAndAddExternalForces( rRightHandSideVector, rVariables, rVolumeForce, rIntegrationWeight ); @@ -394,9 +390,6 @@ void MPMUpdatedLagrangianUP::CalculateAndAddRHS( // Operation performed: rRightHandSideVector -= Stabilized Pressure Forces CalculateAndAddStabilizedPressure( rRightHandSideVector, rVariables, rIntegrationWeight); - //rVariables.detF = determinant_F; - //rVariables.detF0 /= rVariables.detF; - } //************************************************************************************ //*********************Calculate the contribution of external force******************* @@ -457,11 +450,10 @@ void MPMUpdatedLagrangianUP::CalculateAndAddInternalForces(VectorType& rRightHan double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolumetricStrainFunction, GeneralVariables & rVariables) - { KRATOS_TRY - rVolumetricStrainFunction = (1- (1/rVariables.detFT)); + rVolumetricStrainFunction = 1.0 - (1.0 / rVariables.detFT); return rVolumetricStrainFunction; KRATOS_CATCH( "" ) @@ -472,12 +464,10 @@ double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolum double& MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizationOfVolumetricStrain(double &rFunction, GeneralVariables & rVariables) - { - KRATOS_TRY - rFunction= 1.0; + rFunction = 1.0; return rFunction; @@ -508,7 +498,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan if (bulk_modulus != bulk_modulus) bulk_modulus = 1.e16; - double VolumetricStrainFunction = this->CalculateVolumetricStrainFunction( VolumetricStrainFunction, rVariables ); + double volumetric_strain_function = 0.0; + volumetric_strain_function = this->CalculateVolumetricStrainFunction( volumetric_strain_function, rVariables ); for ( unsigned int i = 0; i < number_of_nodes; i++ ) { @@ -519,8 +510,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan rRightHandSideVector[index_p] += (1.0 / bulk_modulus) * r_N(0, i) * r_N(0, j) * pressure * rIntegrationWeight / rVariables.detFT; //2D-3D } - rRightHandSideVector[index_p] -= VolumetricStrainFunction * r_N(0, i) * rIntegrationWeight; //FLUID-UP - //rRightHandSideVector[index_p] -= (1.0 - 1.0 / rVariables.detFT) * r_N(0, i) * rIntegrationWeight; + rRightHandSideVector[index_p] -= volumetric_strain_function * r_N(0, i) * rIntegrationWeight; + index_p += (dimension + 1); } @@ -552,7 +543,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddStabilizedPressure(VectorType& rRigh if (dimension == 3) factor_value = 10.0; //JMC default value - alpha_stabilization = alpha_stabilization * factor_value / shear_modulus; + alpha_stabilization = alpha_stabilization * factor_value / shear_modulus; } else { @@ -598,10 +589,6 @@ void MPMUpdatedLagrangianUP::CalculateAndAddLHS( const double& rIntegrationWeight, const ProcessInfo& rCurrentProcessInfo) { - //rVariables.detF0 *= rVariables.detF; - //double determinant_F = rVariables.detF; - //rVariables.detF = 1; //in order to simplify updated and spatial lagrangian - // Operation performed: add Km to the rLefsHandSideMatrix CalculateAndAddKuum( rLeftHandSideMatrix, rVariables, rIntegrationWeight ); @@ -624,9 +611,6 @@ void MPMUpdatedLagrangianUP::CalculateAndAddLHS( // Operation performed: add Kpp_Stab to the rLefsHandSideMatrix CalculateAndAddKppStab( rLeftHandSideMatrix, rVariables, rIntegrationWeight ); - //rVariables.detF = determinant_F; - //rVariables.detF0 /= rVariables.detF; - } //************************************************************************************ //************************************************************************************ @@ -799,7 +783,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpp (MatrixType& rLeftHandSideMatrix unsigned int indexpj = dimension; for (unsigned int j = 0; j < number_of_nodes; j++) { - rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight / rVariables.detFT; + rLeftHandSideMatrix(indexpi,indexpj) -= ((1.0)/(bulk_modulus)) * r_N(0, i) * r_N(0, j) * rIntegrationWeight / rVariables.detFT; indexpj += (dimension + 1); } diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp index 853c92571d93..64d8d82dadac 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp @@ -369,12 +369,12 @@ class MPMUpdatedLagrangianUP /** - * Calculation of the constitutive coefficient for pressure of the Element + * Calculation of the volumetric strain function for the pressure equation */ virtual double& CalculateVolumetricStrainFunction(double& rCoefficient, GeneralVariables & rVariables); /** - * Calculation of the constitutive coefficient derivative for pressure of the Element + * Calculation of the linearization factor of the volumetric strain function */ virtual double& CalculateFunctionFromLinearizationOfVolumetricStrain(double& rCoefficient, GeneralVariables & rVariables); From 505081a27e56da6d07a88f869912a544a840ae90 Mon Sep 17 00:00:00 2001 From: Laura Date: Thu, 4 Jun 2026 17:07:41 +0200 Subject: [PATCH 47/50] modified CalculateVolumetricStrainFunction --- .../custom_elements/mpm_updated_lagrangian_UP.cpp | 8 +++----- .../custom_elements/mpm_updated_lagrangian_UP.hpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index 929aacc579ac..94e439370832 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -449,12 +449,11 @@ void MPMUpdatedLagrangianUP::CalculateAndAddInternalForces(VectorType& rRightHan //****************************************************************************************************************** -double& MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(double& rVolumetricStrainFunction, GeneralVariables & rVariables) +double MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(GeneralVariables & rVariables) { KRATOS_TRY - rVolumetricStrainFunction = 1.0 - (1.0 / rVariables.detFT); - return rVolumetricStrainFunction; + return 1.0 - (1.0 / rVariables.detFT); KRATOS_CATCH( "" ) } @@ -498,8 +497,7 @@ void MPMUpdatedLagrangianUP::CalculateAndAddPressureForces(VectorType& rRightHan if (bulk_modulus != bulk_modulus) bulk_modulus = 1.e16; - double volumetric_strain_function = 0.0; - volumetric_strain_function = this->CalculateVolumetricStrainFunction( volumetric_strain_function, rVariables ); + const double volumetric_strain_function = this->CalculateVolumetricStrainFunction(rVariables); for ( unsigned int i = 0; i < number_of_nodes; i++ ) { diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp index 64d8d82dadac..dba4d06c87b1 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp @@ -371,7 +371,7 @@ class MPMUpdatedLagrangianUP /** * Calculation of the volumetric strain function for the pressure equation */ - virtual double& CalculateVolumetricStrainFunction(double& rCoefficient, GeneralVariables & rVariables); + virtual double CalculateVolumetricStrainFunction(GeneralVariables & rVariables); /** * Calculation of the linearization factor of the volumetric strain function From 428511e6c7616dda7c2659543a6cbf9b68d16a90 Mon Sep 17 00:00:00 2001 From: Laura Date: Thu, 4 Jun 2026 17:47:02 +0200 Subject: [PATCH 48/50] called CalculateFunctionFromLinearizationOfVolumetricStrain in Kpu computation --- .../custom_elements/mpm_updated_lagrangian_UP.cpp | 11 ++++++----- .../custom_elements/mpm_updated_lagrangian_UP.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp index 94e439370832..9471c455f8a4 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.cpp @@ -462,13 +462,11 @@ double MPMUpdatedLagrangianUP::CalculateVolumetricStrainFunction(GeneralVariable //************************************************************************************ -double& MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizationOfVolumetricStrain(double &rFunction, GeneralVariables & rVariables) +double MPMUpdatedLagrangianUP::CalculateFunctionFromLinearizationOfVolumetricStrain(GeneralVariables & rVariables) { KRATOS_TRY - rFunction = 1.0; - - return rFunction; + return 1.0; KRATOS_CATCH( "" ) @@ -735,6 +733,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpu (MatrixType& rLeftHandSideMatrix const unsigned int number_of_nodes = GetGeometry().size(); const unsigned int dimension = GetGeometry().WorkingSpaceDimension(); const Matrix& r_N = GetGeometry().ShapeFunctionsValues(); + const double volumetric_strain_linearization_factor = + this->CalculateFunctionFromLinearizationOfVolumetricStrain(rVariables); // Assemble components considering added DOF matrix system unsigned int index_p = dimension; @@ -745,7 +745,8 @@ void MPMUpdatedLagrangianUP::CalculateAndAddKpu (MatrixType& rLeftHandSideMatrix unsigned int index_up = dimension*j + j; for ( unsigned int k = 0; k < dimension; k++ ) { - rLeftHandSideMatrix(index_p,index_up+k) += r_N(0, i) * rVariables.DN_DX ( j, k ) * rIntegrationWeight; + rLeftHandSideMatrix(index_p,index_up+k) += + volumetric_strain_linearization_factor * r_N(0, i) * rVariables.DN_DX(j, k) * rIntegrationWeight; } } index_p += (dimension + 1); diff --git a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp index dba4d06c87b1..439ea9b440fc 100644 --- a/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp +++ b/applications/MPMApplication/custom_elements/mpm_updated_lagrangian_UP.hpp @@ -376,7 +376,7 @@ class MPMUpdatedLagrangianUP /** * Calculation of the linearization factor of the volumetric strain function */ - virtual double& CalculateFunctionFromLinearizationOfVolumetricStrain(double& rCoefficient, GeneralVariables & rVariables); + virtual double CalculateFunctionFromLinearizationOfVolumetricStrain(GeneralVariables & rVariables); /** From 012ae6de591c0800e5e454975647fc7cc71fffb9 Mon Sep 17 00:00:00 2001 From: Vicente Mataix Ferrandiz Date: Wed, 10 Jun 2026 16:00:09 +0200 Subject: [PATCH 49/50] Rename mesh generation methods for clarity: Update GenerateMesh to GenerateCartesianMesh in modeler and Python bindings --- .../cartesian_mesh_generator_modeler.cpp | 4 +-- .../cartesian_mesh_generator_modeler.h | 26 +++---------------- kratos/python/add_modeler_to_python.cpp | 2 +- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/kratos/modeler/cartesian_mesh_generator_modeler.cpp b/kratos/modeler/cartesian_mesh_generator_modeler.cpp index d19934f604a7..ba44153808d2 100644 --- a/kratos/modeler/cartesian_mesh_generator_modeler.cpp +++ b/kratos/modeler/cartesian_mesh_generator_modeler.cpp @@ -86,7 +86,7 @@ void CartesianMeshGeneratorModeler::SetupModelPart() r_output.CreateNewProperties(0); const Element& r_ref_element = KratosComponents::Get(element_name); - GenerateMesh(r_output, r_ref_element); + GenerateCartesianMesh(r_output, r_ref_element); KRATOS_CATCH("") } @@ -94,7 +94,7 @@ void CartesianMeshGeneratorModeler::SetupModelPart() /***********************************************************************************/ /***********************************************************************************/ -void CartesianMeshGeneratorModeler::GenerateMesh( +void CartesianMeshGeneratorModeler::GenerateCartesianMesh( ModelPart& rModelPart, Element const& rReferenceElement ) diff --git a/kratos/modeler/cartesian_mesh_generator_modeler.h b/kratos/modeler/cartesian_mesh_generator_modeler.h index 63e95e057a57..3ce038d46e78 100644 --- a/kratos/modeler/cartesian_mesh_generator_modeler.h +++ b/kratos/modeler/cartesian_mesh_generator_modeler.h @@ -44,7 +44,7 @@ namespace Kratos * The class is constructed with a reference source model part * (from which the bounding box and boundary are taken) and a uniform * element size. The generated nodes and elements are placed in the - * destination model part passed to GenerateMesh(). + * destination model part passed to GenerateCartesianMesh(). * * @author Jordi Cotela Dalmau */ @@ -61,9 +61,6 @@ class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler /// The base class type using BaseType = Modeler; - /// The geometry type definition - using GeometryType = Geometry; - /// The nodes vector type definition using NodesVectorType = PointerVector; @@ -76,7 +73,7 @@ class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler /** * @brief Default constructor (required for registry). - * @note Do not call GenerateMesh() on a default-constructed instance. + * @note Do not call GenerateCartesianMesh() on a default-constructed instance. */ CartesianMeshGeneratorModeler(); @@ -140,7 +137,7 @@ class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler /** * @brief Runs mesh generation when the modeler is used through the factory. * @details Reads the input/output model part names and element name from - * the stored parameters and delegates to GenerateMesh(). + * the stored parameters and delegates to GenerateCartesianMesh(). */ void SetupModelPart() override; @@ -156,7 +153,7 @@ class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler * selects the 2D or 3D code path and whose properties are * reused for every created element. */ - void GenerateMesh(ModelPart& rThisModelPart, Element const& rReferenceElement); + void GenerateCartesianMesh(ModelPart& rThisModelPart, Element const& rReferenceElement); /** * @brief Computes outward-pointing normals at every boundary node of @@ -301,21 +298,6 @@ class KRATOS_API(KRATOS_CORE) CartesianMeshGeneratorModeler /// Accumulated boundary normals at each source-model-part node (2D only). std::vector> mNormals; - ///@} - ///@name Private Operations - ///@{ - - /** - * @brief Creates equally-spaced intermediate nodes along a geometry edge. - * @param rThisModelPart Model part in which to create the nodes. - * @param rGeometry Two-node edge geometry. - * @param NumberOfSegments Number of segments to divide the edge into; - * (NumberOfSegments - 1) new nodes are created (endpoints excluded). - * @param StartNodeId First node ID to assign; incremented for each new node. - */ - void GenerateNodes(ModelPart& rThisModelPart, GeometryType& rGeometry, - SizeType NumberOfSegments, SizeType StartNodeId); - ///@} ///@name Inaccessible methods ///@{ diff --git a/kratos/python/add_modeler_to_python.cpp b/kratos/python/add_modeler_to_python.cpp index 919ed4705cf4..d39a2c01deda 100644 --- a/kratos/python/add_modeler_to_python.cpp +++ b/kratos/python/add_modeler_to_python.cpp @@ -128,7 +128,7 @@ void AddModelerToPython(pybind11::module& m) .def(py::init()) .def(py::init()) .def("GenerateMesh", [](CartesianMeshGeneratorModeler& self, ModelPart& rModelPart, const std::string& rElementName) { - self.GenerateMesh(rModelPart, KratosComponents::Get(rElementName)); + self.GenerateCartesianMesh(rModelPart, KratosComponents::Get(rElementName)); }) ; } From 7f7f238ceaa23dffb8c6917723d0f4b52bf1aea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Mataix=20Ferr=C3=A1ndiz?= Date: Fri, 12 Jun 2026 12:27:04 +0000 Subject: [PATCH 50/50] Rename mesh generation method from GenerateMesh to GenerateCartesianMesh in tests for clarity --- .../modeler/test_cartesian_mesh_generator_modeler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp b/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp index 7f0984ff25cd..5823a0304d14 100644 --- a/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp +++ b/kratos/tests/cpp_tests/modeler/test_cartesian_mesh_generator_modeler.cpp @@ -49,7 +49,7 @@ ModelPart& CreateBoxSourceModelPart(Model& rModel, const std::string& rName, /***********************************************************************************/ /***********************************************************************************/ -/// Test that GenerateMesh (direct API) fills a 3D model part with the correct +/// Test that GenerateCartesianMesh (direct API) fills a 3D model part with the correct /// node and element counts for a unit-cube source with a given element size. KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DNodeCount, KratosCoreFastSuite) { @@ -60,7 +60,7 @@ KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DNodeCount, KratosCoreFa r_output.CreateNewProperties(0); CartesianMeshGeneratorModeler modeler(r_source, 0.5); - modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + modeler.GenerateCartesianMesh(r_output, KratosComponents::Get("Element3D4N")); // 3 nodes per direction → 27 total KRATOS_EXPECT_EQ(r_output.NumberOfNodes(), 27u); @@ -80,7 +80,7 @@ KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DNodesInsideBB, KratosCo r_output.CreateNewProperties(0); CartesianMeshGeneratorModeler modeler(r_source, 0.5); - modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + modeler.GenerateCartesianMesh(r_output, KratosComponents::Get("Element3D4N")); for (const auto& r_node : r_output.Nodes()) { KRATOS_EXPECT_GE(r_node.X(), -1.0 - 1e-12); @@ -105,7 +105,7 @@ KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModeler3DElementConnectivity, Kr r_output.CreateNewProperties(0); CartesianMeshGeneratorModeler modeler(r_source, 1.0); - modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + modeler.GenerateCartesianMesh(r_output, KratosComponents::Get("Element3D4N")); // 1 cell per direction, 6 tets KRATOS_EXPECT_EQ(r_output.NumberOfElements(), 6u); @@ -181,7 +181,7 @@ KRATOS_TEST_CASE_IN_SUITE(CartesianMeshGeneratorModelerDivisionNumbers, KratosCo r_output.CreateNewProperties(0); CartesianMeshGeneratorModeler modeler(r_source, 0.5); - modeler.GenerateMesh(r_output, KratosComponents::Get("Element3D4N")); + modeler.GenerateCartesianMesh(r_output, KratosComponents::Get("Element3D4N")); // (6+1)*(4+1)*(2+1) = 7*5*3 = 105 nodes KRATOS_EXPECT_EQ(r_output.NumberOfNodes(), 105u);