Skip to content

Commit 5289b98

Browse files
authored
[GeoMechanicsApplication] Making unit tests for the erosion mechanism (#12789)
* first version of unit tests * corrected second unit test * removed unused definition * formatted * formatetd 2.0 * added this-> to call of BaseClassFinalizeSolutionStep * updated README file * changed GravitationalForce * changed to GravitationalAcceleration * response to all reviews * fixed that * response to review on geo_mechanics_newton_raphson_erosion_process_strategy * removed some include, p_scheme and p_solver
1 parent 2791602 commit 5289b98

4 files changed

Lines changed: 235 additions & 24 deletions

File tree

applications/GeoMechanicsApplication/custom_elements/steady_state_Pw_piping_element.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
namespace Kratos
2020
{
21-
2221
template <unsigned int TDim, unsigned int TNumNodes>
2322
Element::Pointer SteadyStatePwPipingElement<TDim, TNumNodes>::Create(IndexType NewId,
2423
NodesArrayType const& ThisNodes,
@@ -341,5 +340,4 @@ bool SteadyStatePwPipingElement<TDim, TNumNodes>::InEquilibrium(const Properties
341340
template class SteadyStatePwPipingElement<2, 4>;
342341
template class SteadyStatePwPipingElement<3, 6>;
343342
template class SteadyStatePwPipingElement<3, 8>;
344-
345343
} // Namespace Kratos

applications/GeoMechanicsApplication/custom_strategies/strategies/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ This function performs an iterative process towards certain equilibrium values o
5454
the modelling is performed. Then a pipe height is corrected by a given increment for each open piping element. The
5555
maximum number of iterations is the user input, "max_piping_iterations".
5656

57+
The typical case is the following. Initially, the equilibrium pipe height is small and quickly the pipe height is
58+
increased above the equilibrium height. At this moment PIPE_EROSION is set to true. Then due to the flow development,
59+
the water pressure gradient decreases, which leads to a higher value of the equilibrium height. As a result the
60+
equilibrium pipe height grows faster than the pipe height. When both of the heights become equal, the iterative process
61+
is stopped.
62+
5763
![check_pipe_equilibrium.svg](check_pipe_equilibrium.svg)
5864

5965
### Recalculate function

applications/GeoMechanicsApplication/custom_strategies/strategies/geo_mechanics_newton_raphson_erosion_process_strategy.hpp

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
namespace Kratos
3333
{
34-
3534
template <class TSparseSpace, class TDenseSpace, class TLinearSolver>
3635
class GeoMechanicsNewtonRaphsonErosionProcessStrategy
3736
: public GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>
@@ -85,7 +84,7 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
8584
if (PipeElements.empty()) {
8685
KRATOS_INFO_IF("PipingLoop", this->GetEchoLevel() > 0 && rank == 0)
8786
<< "No Pipe Elements -> Finalizing Solution " << std::endl;
88-
GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::FinalizeSolutionStep();
87+
this->BaseClassFinalizeSolutionStep();
8988
return;
9089
}
9190
// calculate max pipe height and pipe increment
@@ -124,13 +123,13 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
124123
save_or_reset_pipe_heights(OpenPipeElements, grow);
125124
}
126125
// recalculate groundwater flow
127-
bool converged = Recalculate();
126+
bool converged = this->Recalculate();
128127

129128
// error check
130129
KRATOS_ERROR_IF_NOT(converged) << "Groundwater flow calculation failed to converge." << std::endl;
131130
}
132131

133-
GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::FinalizeSolutionStep();
132+
this->BaseClassFinalizeSolutionStep();
134133
}
135134

136135
/**
@@ -140,7 +139,6 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
140139
int Check() override
141140
{
142141
KRATOS_TRY
143-
144142
BaseType::Check();
145143
this->GetBuilderAndSolver()->Check(BaseType::GetModelPart());
146144
this->GetScheme()->Check(BaseType::GetModelPart());
@@ -296,25 +294,22 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
296294
return max_pipe_height / (n_steps - 1);
297295
}
298296

299-
bool Recalculate()
297+
virtual bool Recalculate()
300298
{
301299
KRATOS_INFO_IF("ResidualBasedNewtonRaphsonStrategy", this->GetEchoLevel() > 0 && rank == 0)
302300
<< "Recalculating" << std::endl;
303-
// KRATOS_INFO_IF("PipingLoop") << "Recalculating" << std::endl;
304-
// ModelPart& CurrentModelPart = this->GetModelPart();
305-
// this->Clear();
306-
307-
// Reset displacements to the initial (Assumes Water Pressure is the convergence criteria)
308-
/* block_for_each(CurrentModelPart.Nodes(), [&](Node& rNode) {
309-
auto dold = rNode.GetSolutionStepValue(WATER_PRESSURE, 1);
310-
rNode.GetSolutionStepValue(WATER_PRESSURE, 0) = dold;
311-
});*/
312301

313302
GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::InitializeSolutionStep();
314303
GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::Predict();
315304
return GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::SolveSolutionStep();
316305
}
317306

307+
virtual void BaseClassFinalizeSolutionStep()
308+
{
309+
// to override in a unit test
310+
GeoMechanicsNewtonRaphsonStrategy<TSparseSpace, TDenseSpace, TLinearSolver>::FinalizeSolutionStep();
311+
}
312+
318313
bool check_pipe_equilibrium(filtered_elements open_pipe_elements, double amax, unsigned int mPipingIterations)
319314
{
320315
bool equilibrium = false;
@@ -331,7 +326,7 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
331326
equilibrium = true;
332327

333328
// perform a flow calculation and stop growing if the calculation doesn't converge
334-
converged = Recalculate();
329+
converged = this->Recalculate();
335330

336331
// todo: JDN (20220817) : grow not used.
337332
// if (!converged)
@@ -344,7 +339,6 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
344339
equilibrium = true;
345340
for (auto OpenPipeElement : open_pipe_elements) {
346341
auto pElement = static_cast<SteadyStatePwPipingElement<2, 4>*>(OpenPipeElement);
347-
348342
// get open pipe element geometry and properties
349343
auto& Geom = OpenPipeElement->GetGeometry();
350344
auto& prop = OpenPipeElement->GetProperties();
@@ -373,7 +367,6 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
373367
equilibrium = true;
374368
OpenPipeElement->SetValue(PIPE_HEIGHT, small_pipe_height);
375369
}
376-
377370
// calculate difference between equilibrium height and current pipe height
378371
OpenPipeElement->SetValue(DIFF_PIPE_HEIGHT, eq_height - current_height);
379372
}
@@ -437,7 +430,5 @@ class GeoMechanicsNewtonRaphsonErosionProcessStrategy
437430
}
438431
}
439432
}
440-
441-
}; // Class GeoMechanicsNewtonRaphsonStrategy
442-
443-
} // namespace Kratos
433+
}; // Class GeoMechanicsNewtonRaphsonErosionProcessStrategy
434+
} // namespace Kratos
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// KRATOS___
2+
// // ) )
3+
// // ___ ___
4+
// // ____ //___) ) // ) )
5+
// // / / // // / /
6+
// ((____/ / ((____ ((___/ / MECHANICS
7+
//
8+
// License: geo_mechanics_application/license.txt
9+
//
10+
// Main authors: Gennady Markelov
11+
//
12+
13+
// Project includes
14+
#include "custom_strategies/strategies/geo_mechanics_newton_raphson_erosion_process_strategy.hpp"
15+
#include "geo_mechanics_fast_suite.h"
16+
#include "test_utilities.h"
17+
18+
#include <geo_mechanics_application.h>
19+
#include <linear_solvers/skyline_lu_factorization_solver.h>
20+
#include <solving_strategies/convergencecriterias/mixed_generic_criteria.h>
21+
22+
namespace Kratos
23+
{
24+
template <class TSparseSpace, class TDenseSpace, class TLinearSolver>
25+
class MockGeoMechanicsNewtonRaphsonErosionProcessStrategy
26+
: public GeoMechanicsNewtonRaphsonErosionProcessStrategy<TSparseSpace, TDenseSpace, TLinearSolver>
27+
{
28+
public:
29+
using SolvingStrategyType = ImplicitSolvingStrategy<TSparseSpace, TDenseSpace, TLinearSolver>;
30+
using TConvergenceCriteriaType = ConvergenceCriteria<TSparseSpace, TDenseSpace>;
31+
using TBuilderAndSolverType = typename SolvingStrategyType::TBuilderAndSolverType;
32+
using TSchemeType = typename SolvingStrategyType::TSchemeType;
33+
34+
MockGeoMechanicsNewtonRaphsonErosionProcessStrategy(ModelPart& rModelPart,
35+
typename TSchemeType::Pointer pScheme,
36+
typename TConvergenceCriteriaType::Pointer pNewConvergenceCriteria,
37+
typename TBuilderAndSolverType::Pointer pNewBuilderAndSolver,
38+
Parameters& rParameters)
39+
: GeoMechanicsNewtonRaphsonErosionProcessStrategy<TSparseSpace, TDenseSpace, TLinearSolver>(
40+
rModelPart, pScheme, pNewConvergenceCriteria, pNewBuilderAndSolver, rParameters),
41+
mrModelPart(rModelPart)
42+
{
43+
}
44+
45+
private:
46+
bool Recalculate() override
47+
{
48+
// The function provides a pressure change over iterations that leads to a non-linear growth of an equilibrium pipe height.
49+
// As a result the height curve crosses twice a pipe height growth curve in the search algorithm implemented
50+
// in GeoMechanicsNewtonRaphsonErosionProcessStrategy. The search stops at the second point.
51+
for (auto& node : mrModelPart.Nodes()) {
52+
node.FastGetSolutionStepValue(WATER_PRESSURE) =
53+
std::pow(node.FastGetSolutionStepValue(WATER_PRESSURE), 0.9725);
54+
}
55+
return true;
56+
}
57+
58+
void BaseClassFinalizeSolutionStep() override
59+
{
60+
// to avoid calling the BaseClassFinalizeSolutionStep in tested class.
61+
}
62+
63+
ModelPart& mrModelPart;
64+
};
65+
66+
Node::Pointer CreateNodeWithSolutionStepValues(ModelPart& rModelPart, int Id, double CoordinateX, double CoordinateY, double WaterPressure)
67+
{
68+
constexpr double coordinate_z = 0.0;
69+
auto p_node = rModelPart.CreateNewNode(Id, CoordinateX, CoordinateY, coordinate_z);
70+
71+
p_node->FastGetSolutionStepValue(WATER_PRESSURE) = WaterPressure;
72+
const array_1d<double, 3> GravitationalAcceleration{0, -9.81, 0};
73+
p_node->FastGetSolutionStepValue(VOLUME_ACCELERATION) = GravitationalAcceleration;
74+
75+
return p_node;
76+
}
77+
78+
Geometry<Node>::Pointer CreateQuadrilateral2D4N(ModelPart& rModelPart,
79+
const std::vector<int>& rNodeIds,
80+
double Xmin,
81+
double Xmax,
82+
double WaterPressureLeft,
83+
double WaterPressureRight)
84+
{
85+
constexpr double y_min = -0.1;
86+
constexpr double y_max = 0.1;
87+
88+
return make_shared<Quadrilateral2D4<Node>>(
89+
CreateNodeWithSolutionStepValues(rModelPart, rNodeIds[0], Xmin, y_min, WaterPressureLeft),
90+
CreateNodeWithSolutionStepValues(rModelPart, rNodeIds[1], Xmax, y_min, WaterPressureRight),
91+
CreateNodeWithSolutionStepValues(rModelPart, rNodeIds[2], Xmax, y_max, WaterPressureRight),
92+
CreateNodeWithSolutionStepValues(rModelPart, rNodeIds[3], Xmin, y_max, WaterPressureLeft));
93+
}
94+
95+
auto SetupPipingStrategy(Model& rModel)
96+
{
97+
using SparseSpaceType = UblasSpace<double, CompressedMatrix, Vector>;
98+
using LocalSpaceType = UblasSpace<double, Matrix, Vector>;
99+
using LinearSolverType = SkylineLUFactorizationSolver<SparseSpaceType, LocalSpaceType>;
100+
using ConvergenceCriteriaType = ConvergenceCriteria<SparseSpaceType, LocalSpaceType>;
101+
using MixedGenericCriteriaType = MixedGenericCriteria<SparseSpaceType, LocalSpaceType>;
102+
using ConvergenceVariableListType = MixedGenericCriteriaType::ConvergenceVariableListType;
103+
104+
auto& r_model_part = rModel.CreateModelPart("ModelPart", 1);
105+
r_model_part.AddNodalSolutionStepVariable(WATER_PRESSURE);
106+
r_model_part.AddNodalSolutionStepVariable(VOLUME_ACCELERATION);
107+
const auto& r_process_info = r_model_part.GetProcessInfo();
108+
109+
auto p_element_props = r_model_part.CreateNewProperties(0);
110+
p_element_props->SetValue(CONSTITUTIVE_LAW, LinearElastic2DInterfaceLaw().Clone());
111+
112+
auto p_element = make_intrusive<SteadyStatePwElement<2, 4>>(
113+
0, CreateQuadrilateral2D4N(r_model_part, std::vector<int>{13, 14, 15, 16}, 3.0, 4.0, 2000.0, 2000.0),
114+
p_element_props, std::make_unique<PlaneStrainStressState>());
115+
p_element->Initialize(r_process_info);
116+
r_model_part.AddElement(p_element);
117+
118+
// Set the pipe element properties
119+
auto p_piping_element_props = r_model_part.CreateNewProperties(1);
120+
p_piping_element_props->SetValue(PIPE_D_70, 2e-4);
121+
p_piping_element_props->SetValue(PIPE_ETA, 0.25);
122+
p_piping_element_props->SetValue(PIPE_THETA, 30);
123+
p_piping_element_props->SetValue(DENSITY_SOLID, 2650);
124+
p_piping_element_props->SetValue(DENSITY_WATER, 1000);
125+
p_piping_element_props->SetValue(PIPE_ELEMENT_LENGTH, 1.0);
126+
p_piping_element_props->SetValue(PIPE_MODIFIED_D, false);
127+
p_piping_element_props->SetValue(PIPE_MODEL_FACTOR, 1);
128+
p_piping_element_props->SetValue(PIPE_START_ELEMENT, 1);
129+
p_piping_element_props->SetValue(CONSTITUTIVE_LAW, LinearElastic2DInterfaceLaw().Clone());
130+
131+
// Create the start piping element
132+
auto p_piping_element = make_intrusive<SteadyStatePwPipingElement<2, 4>>(
133+
1, CreateQuadrilateral2D4N(r_model_part, std::vector<int>{1, 2, 3, 4}, 0.0, 1.0, 0.0, 500.0),
134+
p_piping_element_props, std::make_unique<PlaneStrainStressState>());
135+
p_piping_element->Initialize(r_process_info);
136+
r_model_part.AddElement(p_piping_element);
137+
138+
// Create other piping elements
139+
p_piping_element = make_intrusive<SteadyStatePwPipingElement<2, 4>>(
140+
2, CreateQuadrilateral2D4N(r_model_part, std::vector<int>{5, 6, 7, 8}, 2.0, 3.0, 500.0, 1000.0),
141+
p_piping_element_props, std::make_unique<PlaneStrainStressState>());
142+
p_piping_element->Initialize(r_process_info);
143+
r_model_part.AddElement(p_piping_element);
144+
145+
p_piping_element = make_intrusive<SteadyStatePwPipingElement<2, 4>>(
146+
3, CreateQuadrilateral2D4N(r_model_part, std::vector<int>{9, 10, 11, 12}, 1.0, 2.0, 1000.0, 1500.0),
147+
p_piping_element_props, std::make_unique<PlaneStrainStressState>());
148+
p_piping_element->Initialize(r_process_info);
149+
r_model_part.AddElement(p_piping_element);
150+
151+
Parameters p_parameters(R"(
152+
{
153+
"max_piping_iterations": 25
154+
} )");
155+
156+
const auto p_builder_and_solver =
157+
Kratos::make_shared<ResidualBasedBlockBuilderAndSolver<SparseSpaceType, LocalSpaceType, LinearSolverType>>(nullptr);
158+
const ConvergenceVariableListType convergence_settings{};
159+
const ConvergenceCriteriaType::Pointer p_criteria =
160+
std::make_shared<MixedGenericCriteriaType>(convergence_settings);
161+
162+
return std::make_unique<MockGeoMechanicsNewtonRaphsonErosionProcessStrategy<SparseSpaceType, LocalSpaceType, LinearSolverType>>(
163+
r_model_part, nullptr, p_criteria, p_builder_and_solver, p_parameters);
164+
}
165+
} // namespace Kratos
166+
167+
namespace Kratos::Testing
168+
{
169+
KRATOS_TEST_CASE_IN_SUITE(CheckGetPipingElements, KratosGeoMechanicsFastSuiteWithoutKernel)
170+
{
171+
// Arrange
172+
Model model;
173+
auto p_solving_strategy = SetupPipingStrategy(model);
174+
175+
// Act
176+
const auto piping_elements = p_solving_strategy->GetPipingElements();
177+
178+
// Assert
179+
const auto elements = model.GetModelPart("ModelPart").Elements();
180+
constexpr int number_of_elements = 4;
181+
KRATOS_EXPECT_EQ(elements.size(), number_of_elements);
182+
183+
constexpr int number_of_piping_elements = 3;
184+
KRATOS_EXPECT_EQ(piping_elements.size(), number_of_piping_elements);
185+
KRATOS_EXPECT_EQ(piping_elements[0]->GetId(), 1);
186+
KRATOS_EXPECT_EQ(piping_elements[1]->GetId(), 3);
187+
KRATOS_EXPECT_EQ(piping_elements[2]->GetId(), 2);
188+
}
189+
190+
KRATOS_TEST_CASE_IN_SUITE(CheckFinalizeSolutionStep, KratosGeoMechanicsFastSuiteWithoutKernel)
191+
{
192+
// Arrange
193+
Model model;
194+
auto p_solving_strategy = SetupPipingStrategy(model);
195+
196+
// Act
197+
p_solving_strategy->FinalizeSolutionStep();
198+
199+
// Assert
200+
auto elements = model.GetModelPart("ModelPart").Elements();
201+
202+
constexpr int active = 1;
203+
KRATOS_EXPECT_EQ(elements[1].GetValue(PIPE_ACTIVE), active);
204+
205+
constexpr double expected_active_pipe_height = 0.0183333;
206+
KRATOS_EXPECT_NEAR(elements[1].GetValue(PIPE_HEIGHT), expected_active_pipe_height, Defaults::relative_tolerance);
207+
208+
constexpr int inactive = 0;
209+
KRATOS_EXPECT_EQ(elements[2].GetValue(PIPE_ACTIVE), inactive);
210+
KRATOS_EXPECT_EQ(elements[3].GetValue(PIPE_ACTIVE), inactive);
211+
212+
constexpr double expected_inactive_pipe_height = 0.0;
213+
KRATOS_EXPECT_NEAR(elements[2].GetValue(PIPE_HEIGHT), expected_inactive_pipe_height, Defaults::relative_tolerance);
214+
KRATOS_EXPECT_NEAR(elements[3].GetValue(PIPE_HEIGHT), expected_inactive_pipe_height, Defaults::relative_tolerance);
215+
}
216+
} // namespace Kratos::Testing

0 commit comments

Comments
 (0)