Skip to content

Commit 7585c09

Browse files
Sabine-van-DijkCopilot
andauthored
[GeoMechanicsApplication] add a new oedometer test to the test_element_lab (#14403)
* make a mesh, material and project parameters file for the oedometer test (unit convention = kN) * insert assertion function and apply it in the triaxial test * add oedometer test with assertion function * apply assert function on displacement assertion triaxial test * formatting of json files for the oedometer test * remove triaxial material parameters from the json format exception list * minor changes to triaxial test readme * add readme for the oedometer test incl schematic * changes in mesh, project and material files according to comments and changes in undrained branch * add stage name drained and add functions in triaxial test * remove old code * change to geo drainage type * change nr of checked ip's in triaxial test Co-authored-by: Copilot <copilot@github.com> * make code use general helper functions Co-authored-by: Copilot <copilot@github.com> * change output file type * change the poisson ratio * change output file name * remove value for the bulk modulus fluid * apply stepwise loading + remove unused material parameters and set to si units (N instead of kN) * si units in assertion and stepwise loading * fix fixed base constraint * use axisymmetric element type and loading * Update readme Co-authored-by: Copilot <copilot@github.com> * apply review comments --------- Co-authored-by: Copilot <copilot@github.com>
1 parent d9ca950 commit 7585c09

13 files changed

Lines changed: 1354 additions & 76 deletions

File tree

applications/GeoMechanicsApplication/exceptions_for_json_formatting.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ tests/test_constant_strip_load_2d/MaterialParameters_stage_1.json
6767
tests/test_constant_strip_load_2d/ProjectParameters.json
6868
tests/test_darcy_law.gid/MaterialParameters.json
6969
tests/test_darcy_law.gid/ProjectParameters.json
70-
tests/test_element_lab/test_triaxial/MaterialParameters.json
7170
tests/test_inclinded_phreatic_line_smaller_line.gid/MaterialParameters.json
7271
tests/test_inclinded_phreatic_line_smaller_line.gid/ProjectParameters.json
7372
tests/test_inclinded_phreatic_surface.gid/MaterialParameters.json
Lines changed: 91 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from csv import reader
12
import os
23

34
import KratosMultiphysics.KratosUnittest as KratosUnittest
@@ -7,18 +8,15 @@
78

89
class KratosGeoMechanicsLabElementTests(KratosUnittest.TestCase):
910
"""
10-
This class contains some element tests, such as triaxial and oedometer tests
11+
This class contains some element tests, such as triaxial and oedometer tests.
1112
"""
12-
def test_triaxial(self):
13-
"""
14-
Regression test for the triaxial experiment.
15-
"""
13+
def test_triaxial_drained(self):
14+
"""Regression test for the triaxial experiment on a mohr coulomb model with a constant pore water pressure."""
1615
expected_disp = [[0.0, -0.2, 0.0], [0.0527776, -0.2, 0.0], [0.0, -0.100033, 0.0], [0.0524025, -0.0996931, 0.0], [0.0, 0.0, 0.0], [0.105197, -0.2, 0.0], [0.105114, -0.100049, 0.0], [0.0524406, 0.0, 0.0], [0.104632, 0.0, 0.0]]
17-
expected_stress = [[-99.9808, -252.622, -99.9806, 0.193199, 0.0, 0.0], [-99.9991, -252.668, -99.9991, 0.00846584, 0, 0]]
18-
expected_strain = [[0.104863, -0.19973, 0.104946, 0.000440186, 0.0, 0.0], [0.1055, -0.200303, 0.104922, 3.84218e-05, 0, 0]]
16+
expected_stress = [[-99.9808, -252.622, -99.9806, 0.193199, 0.0, 0.0], [-99.8828, -252.381, -99.8827, 0.0448209, 0, 0], [-100.045, -252.78, -100.045, 0.0314238, 0, 0], [-99.9991, -252.668, -99.9991, 0.00846584, 0, 0], [-99.967, -252.589, -99.967, -0.0103576, 0, 0], [-100.064, -252.827, -100.064, 0.137162, 0, 0]]
17+
expected_strain = [[0.104863, -0.19973, 0.104946, 0.000440186, 0.0, 0.0], [0.104939, -0.199861, 0.105022, 0.000100528, 0, 0], [0.10444, -0.199182, 0.104773, 6.24562e-05, 0, 0], [0.1055, -0.200303, 0.104922, 3.84218e-05, 0, 0], [0.104915, -0.200106, 0.105298, -4.97694e-06, 0, 0], [0.105631, -0.200818, 0.105335, 0.000287088, 0, 0]]
1918
self._run_triaxial_regression_test('drained', 'triaxial_test_output.post.res', expected_disp, expected_stress,
20-
expected_strain, 4)
21-
19+
expected_strain, 4, assert_all_integration_points=True)
2220

2321
def test_triaxial_undrained(self):
2422
"""
@@ -30,10 +28,10 @@ def test_triaxial_undrained(self):
3028
self._run_triaxial_regression_test('undrained', 'triaxial_undrained_test_output.post.res', expected_disp,
3129
expected_stress, expected_strain, 4)
3230

33-
def _run_triaxial_regression_test(self, stage_name, output_file_name, expected_disp, expected_stress,
34-
expected_strain, precision_places):
35-
test_name = os.path.join('test_triaxial', stage_name)
36-
file_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name))
31+
def _run_triaxial_regression_test(self, stage_name, output_file_name, expected_displacement, expected_stress,
32+
expected_strain, precision_places, assert_all_integration_points=False):
33+
test_name = 'test_triaxial'
34+
file_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name, stage_name))
3735
test_helper.run_kratos(file_path)
3836

3937
# Read the output files from the simulation for comparison.
@@ -42,59 +40,86 @@ def _run_triaxial_regression_test(self, stage_name, output_file_name, expected_d
4240
time = 1.0
4341

4442
# Assert the displacement in all nodes in all directions.
45-
for node_id, expected_node_displacement in enumerate(expected_disp, start=1):
43+
for node_id, expected_node_displacement in enumerate(expected_displacement, start=1):
4644
node_displacement = reader.nodal_values_at_time("DISPLACEMENT", time, result, [node_id])[0]
4745
self.assertVectorAlmostEqual(node_displacement, expected_node_displacement, precision_places)
4846

49-
self._assert_first_ip_tensor(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress, precision_places, time)
50-
self._assert_first_ip_tensor(reader, result, "ENGINEERING_STRAIN_TENSOR", expected_strain, precision_places, time)
47+
if assert_all_integration_points:
48+
self._assert_integration_point_tensors(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress,
49+
precision_places, time)
50+
self._assert_integration_point_tensors(reader, result, "ENGINEERING_STRAIN_TENSOR", expected_strain,
51+
precision_places, time)
52+
else:
53+
self._assert_first_ip_tensor(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress,
54+
precision_places, time)
55+
self._assert_first_ip_tensor(reader, result, "ENGINEERING_STRAIN_TENSOR", expected_strain,
56+
precision_places, time)
57+
58+
def test_oedometer_drained(self):
59+
"""Regression test for the oedometer experiment on a linear elastic model with constant pore water pressure."""
60+
expected_stress_per_ip = [-1e+06/3.0, -1e+06, -1e+06/3.0, 0.0, 0.0, 0.0]
61+
expected_stress = [expected_stress_per_ip] * 6
62+
expected_y_displacements = [-0.0208, -0.0417, -0.0625, -0.0833]
63+
displacement_times = [0.25, 0.5, 0.75, 1.0]
64+
top_nodes = [7, 8, 9]
65+
self._run_oedometer_regression_test('drained', 'test_oedometer_output.post.res', expected_stress,
66+
expected_y_displacements, displacement_times, top_nodes, 0, 4)
67+
68+
def _run_oedometer_regression_test(self, stage_name, output_file_name, expected_stress,
69+
expected_y_displacements, displacement_times, top_nodes, precision_places_stress, precision_places_displacement=4):
70+
"""Run the oedometer regression test and validate stress tensors and y-displacements in time."""
71+
test_name = 'test_oedometer'
72+
file_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name, stage_name))
73+
test_helper.run_kratos(file_path)
5174

52-
def _assert_first_ip_tensor(self, reader, result, variable_name, expected_values, precision_places, time=1.0):
53-
for element_id, expected_tensor in enumerate(expected_values, start=1):
54-
tensor = reader.element_integration_point_values_at_time(variable_name, time, result, [element_id], [0])[0]
55-
self._assert_integration_point_tensor_results(tensor, expected_tensor, precision_places, variable_name)
75+
reader = GiDOutputFileReader()
76+
result = reader.read_output_from(os.path.join(file_path, output_file_name))
77+
78+
self._assert_integration_point_tensors(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress,
79+
precision_places_stress, time=1.0)
80+
81+
for time, expected_y in zip(displacement_times, expected_y_displacements):
82+
self._assert_y_displacements_at_time(reader, result, top_nodes, expected_y, precision_places_displacement, time)
5683

5784
def test_triaxial_comp_6n(self):
5885
"""
5986
Drained compression triaxial test on Mohr-Coulomb model with axisymmetric 2D6N elements
60-
It consistes of two calculation phases:
87+
It consists of two calculation phases:
6188
1) apply confining stress of -100 kPa
6289
2) apply deviatoric stress of -200 kPa
6390
"""
64-
project_path = test_helper.get_file_path(os.path.join('test_element_lab', 'triaxial_comp_6n'))
65-
91+
test_name = 'triaxial_comp_6n'
92+
project_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name))
6693
n_stages = 2
6794
run_multiple_stages.run_stages(project_path, n_stages)
68-
6995
reader = GiDOutputFileReader()
70-
self._assert_triaxial_comp_6n_stage(reader, project_path, "triaxial_comp_6n_stage1.post.res", 1.0,
71-
[-100.0, -100.0, -100.0], 3, 3)
72-
self._assert_triaxial_comp_6n_stage(reader, project_path, "triaxial_comp_6n_stage2.post.res", 1.25,
73-
[-100.0, -300.0, -100.0], 3, 2)
7496

97+
result = reader.read_output_from(os.path.join(project_path, "triaxial_comp_6n_stage1.post.res"))
98+
expected_stress = [[-100.0, -100.0, -100.0, 0.0, 0.0, 0.0]] * 6
99+
self._assert_integration_point_tensors(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress, 3, time=1.0)
100+
101+
result = reader.read_output_from(os.path.join(project_path, "triaxial_comp_6n_stage2.post.res"))
102+
expected_stress = [[-100.0, -300.0, -100.0, 0.0, 0.0, 0.0]] * 6
103+
self._assert_integration_point_tensors(reader, result, "CAUCHY_STRESS_TENSOR", expected_stress, 2, time=1.25)
75104

76105
def test_oedometer_ULFEM(self):
77106
"""
78107
Oedometer test on a linear elastic model with 2D6N elements
79108
"""
80109
test_name = 'oedometer_ULFEM'
81-
project_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name))
82-
simulation = test_helper.run_kratos(project_path)
110+
file_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name))
111+
simulation = test_helper.run_kratos(file_path)
83112
effective_stresses = test_helper.get_cauchy_stress_tensor(simulation)
84-
self._assert_oedometer_effective_stresses(effective_stresses, -1000000.0, 2)
113+
self._assert_oedometer_effective_stresses(effective_stresses, -1e+06, 2)
85114

86115
top_node_nbrs = [1, 2]
87-
output_file_path = os.path.join(project_path, test_name+'.post.res')
88-
output_reader = GiDOutputFileReader()
89-
output_data = output_reader.read_output_from(output_file_path)
90-
displacements = GiDOutputFileReader.nodal_values_at_time("DISPLACEMENT", 0.1, output_data, node_ids=top_node_nbrs)
91-
self._assert_y_displacements(displacements, -0.00990099, 6)
92-
93-
displacements = GiDOutputFileReader.nodal_values_at_time("DISPLACEMENT", 0.7, output_data, node_ids=top_node_nbrs)
94-
self._assert_y_displacements(displacements, -0.0654206, 6)
116+
output_file = os.path.join(file_path, test_name+'.post.res')
117+
reader = GiDOutputFileReader()
118+
result = reader.read_output_from(output_file)
95119

96-
displacements = GiDOutputFileReader.nodal_values_at_time("DISPLACEMENT", 1.0, output_data, node_ids=top_node_nbrs)
97-
self._assert_y_displacements(displacements, -0.0909090909516868, 6)
120+
self._assert_y_displacements_at_time(reader, result, top_node_nbrs, -0.0099, 4, 0.1)
121+
self._assert_y_displacements_at_time(reader, result, top_node_nbrs, -0.0654, 4, 0.7)
122+
self._assert_y_displacements_at_time(reader, result, top_node_nbrs, -0.0909, 4, 1.0)
98123

99124
def test_oedometer_ULFEM_diff_order(self):
100125
"""
@@ -104,23 +129,13 @@ def test_oedometer_ULFEM_diff_order(self):
104129
project_path = test_helper.get_file_path(os.path.join('test_element_lab', test_name))
105130
simulation = test_helper.run_kratos(project_path)
106131
effective_stresses = test_helper.get_cauchy_stress_tensor(simulation)
107-
displacements = test_helper.get_displacement(simulation)
108-
self._assert_oedometer_effective_stresses(effective_stresses, -1000.0, 3)
132+
self._assert_oedometer_effective_stresses(effective_stresses, -1e+03, 3)
109133

110-
y_displacements = [displacement[1] for displacement in displacements]
134+
output_file = os.path.join(project_path, test_name + '.post.res')
135+
reader = GiDOutputFileReader()
136+
result = reader.read_output_from(output_file)
111137
top_node_nbrs = [1]
112-
for top_node_nbr in top_node_nbrs:
113-
self.assertAlmostEqual(-1e-04, y_displacements[top_node_nbr], 6)
114-
115-
def _assert_triaxial_comp_6n_stage(self, reader, project_path, output_file_name, time, expected_stress_vector,
116-
number_of_integration_points_per_element, places):
117-
output_data = reader.read_output_from(os.path.join(project_path, output_file_name))
118-
stress_vectors_per_element = reader.element_integration_point_values_at_time("CAUCHY_STRESS_TENSOR", time, output_data)
119-
self.assertEqual(2, len(stress_vectors_per_element))
120-
121-
for element_stress_vectors in stress_vectors_per_element:
122-
self.assertEqual(number_of_integration_points_per_element, len(element_stress_vectors))
123-
self._assert_integration_point_tensor_results(element_stress_vectors, expected_stress_vector, places, "CAUCHY_STRESS_TENSOR")
138+
self._assert_y_displacements_at_time(reader, result, top_node_nbrs, -1e-4, 6, time=1.0)
124139

125140
def _assert_oedometer_effective_stresses(self, effective_stresses, expected_yy, places_yy):
126141
for element in effective_stresses:
@@ -129,14 +144,32 @@ def _assert_oedometer_effective_stresses(self, effective_stresses, expected_yy,
129144
self.assertAlmostEqual(expected_yy, integration_point[1,1], places_yy)
130145
self.assertAlmostEqual(0.0, integration_point[2,2], 3)
131146

132-
def _assert_y_displacements(self, displacements, expected_y, places):
147+
def _assert_y_displacements_at_time(self, reader, result, node_ids, expected_y, places, time=1.0):
148+
displacements = reader.nodal_values_at_time("DISPLACEMENT", time, result, node_ids=node_ids)
133149
for displacement in displacements:
134150
self.assertAlmostEqual(expected_y, displacement[1], places)
135151

136152
def _assert_integration_point_tensor_results(self, integration_point_tensors, expected_integration_point_tensor, places, result_name):
137153
for idx, ip_tensor in enumerate(integration_point_tensors):
138-
self.assertVectorAlmostEqual(expected_integration_point_tensor[:2], ip_tensor[:2], places, msg = f"{result_name} component xx, yy, zz at integration point {idx}")
154+
self.assertVectorAlmostEqual(expected_integration_point_tensor, ip_tensor, places, msg = f"{result_name} components at integration point {idx}")
155+
156+
def _assert_integration_point_tensors(self, reader, result, variable_name, expected_tensors, places, time):
157+
"""Assert tensor values for all integration points across both elements."""
158+
for flat_index, expected_tensor in enumerate(expected_tensors):
159+
element_id, ip_index = self._get_element_id_and_ip_index(flat_index)
160+
tensor = reader.element_integration_point_values_at_time(variable_name, time, result, [element_id], [ip_index])[0]
161+
self._assert_integration_point_tensor_results(tensor, expected_tensor, places, variable_name)
139162

163+
def _get_element_id_and_ip_index(self, flat_index):
164+
"""Map a flat integration-point index to the corresponding element and local integration point index."""
165+
if flat_index < 3:
166+
return 1, flat_index
167+
return 2, flat_index - 3
168+
169+
def _assert_first_ip_tensor(self, reader, result, variable_name, expected_values, precision_places, time=1.0):
170+
for element_id, expected_tensor in enumerate(expected_values, start=1):
171+
tensor = reader.element_integration_point_values_at_time(variable_name, time, result, [element_id], [0])[0]
172+
self._assert_integration_point_tensor_results(tensor, expected_tensor, precision_places, variable_name)
140173

141174
if __name__ == '__main__':
142175
KratosUnittest.main()

applications/GeoMechanicsApplication/tests/test_element_lab/oedometer_ULFEM_diff_order/MaterialParameters.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
"DENSITY_WATER" : 1.0e3,
1515
"POROSITY" : 0.3,
1616
"BULK_MODULUS_SOLID" : 1.0e12,
17-
"BULK_MODULUS_FLUID" : 2.0e-30,
1817
"PERMEABILITY_XX" : 4.5e-30,
1918
"PERMEABILITY_YY" : 4.5e-30,
2019
"PERMEABILITY_XY" : 0.0,

applications/GeoMechanicsApplication/tests/test_element_lab/oedometer_ULFEM_diff_order/ProjectParameters.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@
7373
"process_name": "GiDOutputProcess",
7474
"Parameters": {
7575
"model_part_name": "PorousDomain.porous_computational_model_part",
76-
"output_name": "Oedometer_ULFEM_diff_order",
76+
"output_name": "oedometer_ULFEM_diff_order",
7777
"postprocess_parameters": {
7878
"result_file_configuration": {
7979
"gidpost_flags": {
8080
"WriteDeformedMeshFlag": "WriteUndeformed",
8181
"WriteConditionsFlag": "WriteElementsOnly",
82-
"GiDPostMode": "GiD_PostBinary",
82+
"GiDPostMode": "GiD_PostAscii",
8383
"MultiFileFlag": "SingleFile"
8484
},
8585
"file_label": "step",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Oedometer Test
2+
3+
This test simulates an oedometer test with a prescribed stepwise top loading process on a linear elastic soil model. It replicates a laboratory test used to determine soil properties, such as consolidation characteristics.
4+
In the laboratory, this is performed on a cylindrical volume of soil, where an increasing pressure is applied on the top of the cylinder. In the model test, the soil sample is emulated by two axisymmetric differential order elements.
5+
6+
A schematic overview of the model is displayed in the figure below. Here the nodes are displayed as black dots. The two elements are numbered in red and are separated by the red line. The symmetry axis is displayed as a red dashed line.
7+
8+
![MeshStructure](drawing.svg)
9+
10+
## Setup
11+
12+
The test is performed under the following conditions:
13+
14+
- **Constraints**:
15+
- The bottom nodes (1, 2, 3) are fixed in the X and Y directions.
16+
- The side nodes and the symmetry axis (3, 6, 9 and 1, 4, 7) are fixed in the X direction.
17+
- **Material**:
18+
- The material is described by the linear elastic model with the following parameters:
19+
- Poisson's ratio = 0.25
20+
- Young's modulus = 1e+07 Pa
21+
- **Loading Conditions**:
22+
- A top load is applied in 4 equal steps:
23+
- t = 0.01 to 0.25: load = -2.5e+05 Pa
24+
- t = 0.26 to 0.50: load = -5e+05 Pa
25+
- t = 0.51 to 0.75: load = -7.5e+05 Pa
26+
- t = 0.76 to 1.0: load = -1e+06 Pa
27+
28+
## Assertions
29+
For this test, the stresses at t = 1.0 are verified.
30+
Additionally, the displacement in the Y-direction of the top nodes is verified at four time steps: t = 0.25, 0.5, 0.75, and 1.0.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
Begin Table 1 TIME LINE_NORMAL_LOAD_Y
2+
0.0 0.0
3+
0.01 2.5e+05
4+
0.25 2.5e+05
5+
0.26 5e+05
6+
0.50 5e+05
7+
0.51 7.5e+05
8+
0.75 7.5e+05
9+
0.76 1e+06
10+
1.0 1e+06
11+
End Table
12+
13+
Begin Properties 0
14+
End Properties
15+
16+
Begin Properties 1
17+
End Properties
18+
19+
Begin Nodes
20+
1 0.0 0.0 0.0
21+
2 0.5 0.0 0.0
22+
3 1.0 0.0 0.0
23+
4 0.0 0.5 0.0
24+
5 0.5 0.5 0.0
25+
6 1.0 0.5 0.0
26+
7 0.0 1.0 0.0
27+
8 0.5 1.0 0.0
28+
9 1.0 1.0 0.0
29+
End Nodes
30+
31+
Begin Elements SmallStrainUPwDiffOrderAxisymmetricElement2D6N
32+
1 1 7 1 3 4 2 5
33+
2 1 3 9 7 6 8 5
34+
End Elements
35+
36+
Begin Conditions AxisymmetricLineNormalLoadDiffOrderCondition2D3N
37+
1 0 9 7 8
38+
End Conditions
39+
40+
Begin SubModelPart Soil
41+
Begin SubModelPartNodes
42+
1
43+
2
44+
3
45+
4
46+
5
47+
6
48+
7
49+
8
50+
9
51+
End SubModelPartNodes
52+
Begin SubModelPartElements
53+
1
54+
2
55+
End SubModelPartElements
56+
End SubModelPart
57+
58+
Begin SubModelPart Top_load
59+
Begin SubModelPartTables
60+
1
61+
End SubModelPartTables
62+
Begin SubModelPartNodes
63+
7
64+
8
65+
9
66+
End SubModelPartNodes
67+
Begin SubModelPartConditions
68+
1
69+
End SubModelPartConditions
70+
End SubModelPart
71+
72+
Begin SubModelPart Fixed_base
73+
Begin SubModelPartNodes
74+
1
75+
2
76+
3
77+
End SubModelPartNodes
78+
End SubModelPart
79+
80+
Begin SubModelPart Sides_rollers
81+
Begin SubModelPartNodes
82+
3
83+
6
84+
9
85+
1
86+
4
87+
7
88+
End SubModelPartNodes
89+
End SubModelPart

0 commit comments

Comments
 (0)