KratosDemStructuresCouplingApplication 10.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- KratosMultiphysics/.libs/KratosDemStructuresCouplingApplication.so +0 -0
- KratosMultiphysics/.libs/libKratosDemStructuresCouplingCore.dylib +0 -0
- KratosMultiphysics/DemStructuresCouplingApplication/__init__.py +7 -0
- KratosMultiphysics/DemStructuresCouplingApplication/control_module_fem_dem_utility.py +109 -0
- KratosMultiphysics/DemStructuresCouplingApplication/control_module_process.py +29 -0
- KratosMultiphysics/DemStructuresCouplingApplication/dem_fem_coupling_algorithm.py +251 -0
- KratosMultiphysics/DemStructuresCouplingApplication/dem_fem_launcher.py +10 -0
- KratosMultiphysics/DemStructuresCouplingApplication/dem_main_script_ready_for_coupling_with_fem.py +29 -0
- KratosMultiphysics/DemStructuresCouplingApplication/dem_poromechanics_coupling_analysis_stage.py +424 -0
- KratosMultiphysics/DemStructuresCouplingApplication/dem_structures_coupling_gid_output.py +201 -0
- KratosMultiphysics/DemStructuresCouplingApplication/multiaxial_control_module_fem_dem_generalized_2d_utility.py +141 -0
- KratosMultiphysics/DemStructuresCouplingApplication/sand_production_post_process_tool.py +135 -0
- KratosMultiphysics/DemStructuresCouplingApplication/sp_dem_fem_coupling_algorithm.py +303 -0
- KratosMultiphysics/DemStructuresCouplingApplication/sp_dem_fem_launcher.py +10 -0
- KratosMultiphysics/DemStructuresCouplingApplication/sp_statistics.py +143 -0
- KratosMultiphysics/DemStructuresCouplingApplication/sp_statistics_2.py +139 -0
- KratosMultiphysics/DemStructuresCouplingApplication/stress_failure_check_utility.py +36 -0
- kratosdemstructurescouplingapplication-10.4.4.dist-info/METADATA +17 -0
- kratosdemstructurescouplingapplication-10.4.4.dist-info/RECORD +27 -0
- kratosdemstructurescouplingapplication-10.4.4.dist-info/WHEEL +6 -0
- kratosdemstructurescouplingapplication.dylibs/libKratosCore.dylib +4 -0
- kratosdemstructurescouplingapplication.dylibs/libKratosDEMCore.dylib +0 -0
- kratosdemstructurescouplingapplication.dylibs/libKratosPoromechanicsCore.dylib +0 -0
- kratosdemstructurescouplingapplication.dylibs/libKratosStructuralMechanicsCore.dylib +0 -0
- kratosdemstructurescouplingapplication.dylibs/libgcc_s.1.1.dylib +0 -0
- kratosdemstructurescouplingapplication.dylibs/libgomp.1.dylib +0 -0
- kratosdemstructurescouplingapplication.dylibs/libstdc++.6.dylib +0 -0
KratosMultiphysics/DemStructuresCouplingApplication/dem_poromechanics_coupling_analysis_stage.py
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.python_solver import PythonSolver
|
|
3
|
+
import KratosMultiphysics.analysis_stage
|
|
4
|
+
|
|
5
|
+
import KratosMultiphysics.DEMApplication as DEM
|
|
6
|
+
import KratosMultiphysics.PoromechanicsApplication as Poromechanics
|
|
7
|
+
import KratosMultiphysics.PoromechanicsApplication.poromechanics_analysis
|
|
8
|
+
import KratosMultiphysics.DemStructuresCouplingApplication as DemStructuresCouplingApplication
|
|
9
|
+
from sp_2d_rigid_fem_algorithm import DEMAnalysisStage2DSpRigidFem
|
|
10
|
+
from KratosMultiphysics.DEMApplication.DEM_analysis_stage import DEMAnalysisStage
|
|
11
|
+
import os
|
|
12
|
+
import math
|
|
13
|
+
|
|
14
|
+
class PoroMechanicsCouplingWithDemRadialMultiDofsControlModuleAnalysisStage(Kratos.analysis_stage.AnalysisStage):
|
|
15
|
+
def __init__(self, model, parameters):
|
|
16
|
+
|
|
17
|
+
self.parameters = parameters
|
|
18
|
+
self.poromechanics_solution = Poromechanics.poromechanics_analysis.PoromechanicsAnalysis(model, parameters["poromechanics_parameters"])
|
|
19
|
+
self.dem_solution = DEMAnalysisStage2DSpRigidFem(model, parameters["dem_parameters"])
|
|
20
|
+
self.dem_solution.ReadModelParts = super(DEMAnalysisStage2DSpRigidFem, self.dem_solution).ReadModelParts
|
|
21
|
+
super().__init__(model, parameters)
|
|
22
|
+
|
|
23
|
+
self._CheckCoherentInputs()
|
|
24
|
+
self.creator_destructor = DEM.ParticleCreatorDestructor()
|
|
25
|
+
self.case_dir = os.getcwd()
|
|
26
|
+
graph_folder_name = self.parameters["dem_parameters"]["problem_name"].GetString() + '_Graphs'
|
|
27
|
+
graph_folder_path = os.path.join(self.case_dir, graph_folder_name)
|
|
28
|
+
images_folder_name = 'dem_poro_coupling_images'
|
|
29
|
+
self.images_folder_path = os.path.join(graph_folder_path, images_folder_name)
|
|
30
|
+
if not os.path.isdir(self.images_folder_path):
|
|
31
|
+
os.mkdir(self.images_folder_path)
|
|
32
|
+
|
|
33
|
+
# General analysis settings
|
|
34
|
+
self.number_of_DEM_steps_between_steadiness_checks = 25
|
|
35
|
+
self.stationarity_measuring_tolerance = 5e1 #5e1 converges with GD 0.8 and CR 0.3 (case poro_dem_64b8)
|
|
36
|
+
self.ignore_isolated_particles = False
|
|
37
|
+
self.remove_isolated_particles = True
|
|
38
|
+
self.breakable_material_after_first_dem_solution_steadiness_achieved = True
|
|
39
|
+
self.use_precompression = True
|
|
40
|
+
self.create_stress_ratio_animation = False
|
|
41
|
+
# Casing settings
|
|
42
|
+
self.add_casing = False
|
|
43
|
+
self.casing_radius = 0.1
|
|
44
|
+
self.casing_element_size = 0.003
|
|
45
|
+
if not self.dem_solution.rigid_face_model_part.HasSubModelPart("Casing"):
|
|
46
|
+
self.dem_solution.rigid_face_model_part.CreateSubModelPart('Casing')
|
|
47
|
+
self.dem_solution.casing_submodelpart = self.dem_solution.rigid_face_model_part.GetSubModelPart('Casing')
|
|
48
|
+
self.dem_solution.casing_submodelpart.SetValue(DEM.RIGID_BODY_OPTION, 1)
|
|
49
|
+
|
|
50
|
+
file1 = os.path.join(os.getcwd(), "poro_solution_time_vs_sp_chunks.txt")
|
|
51
|
+
file2 = os.path.join(os.getcwd(), "poro_solution_time_vs_sp_standard.txt")
|
|
52
|
+
file3 = os.path.join(os.getcwd(), "poro_solution_time_vs_dem_time_vs_dems_steps.txt")
|
|
53
|
+
file4 = os.path.join(os.getcwd(), "radial_normal_and_smoothed_reaction_stresses_values.txt")
|
|
54
|
+
if os.path.exists(file1):
|
|
55
|
+
os.remove(file1)
|
|
56
|
+
if os.path.exists(file2):
|
|
57
|
+
os.remove(file2)
|
|
58
|
+
if os.path.exists(file3):
|
|
59
|
+
os.remove(file3)
|
|
60
|
+
if os.path.exists(file4):
|
|
61
|
+
os.remove(file4)
|
|
62
|
+
|
|
63
|
+
self.CreateInitialStressTensorFile()
|
|
64
|
+
|
|
65
|
+
def FindSubModelPartWithExternalWalls(self):
|
|
66
|
+
|
|
67
|
+
modelpart = self.model.GetModelPart('RigidFacePart')
|
|
68
|
+
submodelpart_with_external_walls = modelpart.GetSubModelPart('1')
|
|
69
|
+
|
|
70
|
+
return submodelpart_with_external_walls
|
|
71
|
+
|
|
72
|
+
def CreateInitialStressTensorFile(self):
|
|
73
|
+
|
|
74
|
+
total_sigma_X = self.parameters["case_parameters"]["total_sigma_X"].GetDouble()
|
|
75
|
+
total_sigma_Y = self.parameters["case_parameters"]["total_sigma_Y"].GetDouble()
|
|
76
|
+
pore_pressure = self.parameters["case_parameters"]["pore_pressure"].GetDouble()
|
|
77
|
+
biot_coefficient = self.parameters["case_parameters"]["biot_coefficient"].GetDouble()
|
|
78
|
+
porosity = self.parameters["case_parameters"]["porosity"].GetDouble()
|
|
79
|
+
permeability = self.parameters["case_parameters"]["permeability"].GetDouble()
|
|
80
|
+
self.initial_effective_stress_X = -total_sigma_X + biot_coefficient * pore_pressure
|
|
81
|
+
self.initial_effective_stress_Y = -total_sigma_Y + biot_coefficient * pore_pressure
|
|
82
|
+
case_filename = self.parameters["poromechanics_parameters"]["problem_data"]["problem_name"].GetString()
|
|
83
|
+
case_filename_plus_extension = case_filename + ".mdpa"
|
|
84
|
+
file = open(case_filename_plus_extension, 'r')
|
|
85
|
+
Xmin = Ymin = Xmax = Ymax = 0.0
|
|
86
|
+
for line in file:
|
|
87
|
+
if line.startswith("Begin Nodes"):
|
|
88
|
+
while True:
|
|
89
|
+
nextline=next(file)
|
|
90
|
+
if nextline.startswith("End Nodes"):
|
|
91
|
+
break
|
|
92
|
+
data = nextline.split()
|
|
93
|
+
info = [float(data[1]), float(data[2])]
|
|
94
|
+
Xmin = info[0] if info[0] < Xmin else Xmin
|
|
95
|
+
Ymin = info[1] if info[1] < Ymin else Ymin
|
|
96
|
+
Xmax = info[0] if info[0] > Xmax else Xmax
|
|
97
|
+
Ymax = info[1] if info[1] > Ymax else Ymax
|
|
98
|
+
file.close()
|
|
99
|
+
initial_effective_sigmas_filename = self.parameters["poromechanics_parameters"]["problem_data"]["initial_stress_utility_settings"]["initial_input_filename"].GetString()
|
|
100
|
+
initial_effective_sigmas_filename_plus_extension = initial_effective_sigmas_filename + ".mdpa"
|
|
101
|
+
#TODO: print stresses in engineering format?
|
|
102
|
+
effective_sigmas_datafile = open(initial_effective_sigmas_filename_plus_extension, 'w')
|
|
103
|
+
effective_sigmas_datafile.write("Begin Properties 0\n")
|
|
104
|
+
effective_sigmas_datafile.write("End Properties\n\n")
|
|
105
|
+
effective_sigmas_datafile.write("Begin Nodes\n")
|
|
106
|
+
effective_sigmas_datafile.write("1 " + str(Xmin) + " " + str(Ymin) + " 0\n")
|
|
107
|
+
effective_sigmas_datafile.write("2 " + str(Xmax) + " " + str(Ymin) + " 0\n")
|
|
108
|
+
effective_sigmas_datafile.write("3 " + str(Xmax) + " " + str(Ymax) + " 0\n")
|
|
109
|
+
effective_sigmas_datafile.write("4 " + str(Xmin) + " " + str(Ymax) + " 0\n")
|
|
110
|
+
effective_sigmas_datafile.write("End Nodes\n\n")
|
|
111
|
+
effective_sigmas_datafile.write("Begin Elements Element2D3N\n")
|
|
112
|
+
effective_sigmas_datafile.write("1 0 1 2 3\n")
|
|
113
|
+
effective_sigmas_datafile.write("2 0 1 3 4\n")
|
|
114
|
+
effective_sigmas_datafile.write("End Elements\n\n")
|
|
115
|
+
effective_sigmas_datafile.write("Begin NodalData INITIAL_STRESS_TENSOR\n")
|
|
116
|
+
effective_sigmas_datafile.write("1 0 [2,2] ((" + str(self.initial_effective_stress_X) + ",0),(0," + str(self.initial_effective_stress_Y) + "))\n")
|
|
117
|
+
effective_sigmas_datafile.write("2 0 [2,2] ((" + str(self.initial_effective_stress_X) + ",0),(0," + str(self.initial_effective_stress_Y) + "))\n")
|
|
118
|
+
effective_sigmas_datafile.write("3 0 [2,2] ((" + str(self.initial_effective_stress_X) + ",0),(0," + str(self.initial_effective_stress_Y) + "))\n")
|
|
119
|
+
effective_sigmas_datafile.write("4 0 [2,2] ((" + str(self.initial_effective_stress_X) + ",0),(0," + str(self.initial_effective_stress_Y) + "))\n")
|
|
120
|
+
effective_sigmas_datafile.write("End NodalData\n")
|
|
121
|
+
effective_sigmas_datafile.close()
|
|
122
|
+
|
|
123
|
+
def Initialize(self):
|
|
124
|
+
self.poromechanics_solution.Initialize()
|
|
125
|
+
self.dem_solution.Initialize()
|
|
126
|
+
super().Initialize()
|
|
127
|
+
self.submodelpart_with_external_walls = self.FindSubModelPartWithExternalWalls()
|
|
128
|
+
self.effective_stresses_communicator = DemStructuresCouplingApplication.EffectiveStressesCommunicatorUtility(self.poromechanics_solution._GetSolver().main_model_part, self.submodelpart_with_external_walls)
|
|
129
|
+
self.effective_stresses_communicator.Initialize()
|
|
130
|
+
self.pore_pressure_communicator_utility = DemStructuresCouplingApplication.PorePressureCommunicatorUtility(self.poromechanics_solution._GetSolver().main_model_part, self.dem_solution.spheres_model_part)
|
|
131
|
+
self.pore_pressure_communicator_utility.Initialize()
|
|
132
|
+
|
|
133
|
+
if self.use_precompression:
|
|
134
|
+
self.ApplyPreCompression()
|
|
135
|
+
|
|
136
|
+
def ApplyPreCompression(self):
|
|
137
|
+
|
|
138
|
+
initial_effective_stress_matrix = Kratos.Matrix()
|
|
139
|
+
initial_effective_stress_matrix.Resize(2,2)
|
|
140
|
+
initial_effective_stress_matrix[0, 0] = self.initial_effective_stress_X
|
|
141
|
+
initial_effective_stress_matrix[1, 0] = 0.0
|
|
142
|
+
initial_effective_stress_matrix[0, 1] = 0.0
|
|
143
|
+
initial_effective_stress_matrix[1, 1] = self.initial_effective_stress_Y
|
|
144
|
+
|
|
145
|
+
self.effective_stresses_communicator.CommunicateGivenRadialEffectiveStressesToDemWalls(initial_effective_stress_matrix)
|
|
146
|
+
self.dem_solution._GetSolver().cplusplus_strategy.BreakAllBonds()
|
|
147
|
+
|
|
148
|
+
self.stationarity_checking_is_activated = False
|
|
149
|
+
print("\n************************************ Solving DEM for the first time...\n", flush=True)
|
|
150
|
+
self.DEM_steps_counter = 0
|
|
151
|
+
self.dem_time_steps_per_fem_time_step = 0
|
|
152
|
+
self.dem_solution.time = self.poromechanics_solution.time
|
|
153
|
+
|
|
154
|
+
while not self.DEMSolutionIsSteady():
|
|
155
|
+
self.dem_solution.time = self.dem_solution._GetSolver().AdvanceInTime(self.dem_solution.time)
|
|
156
|
+
self.dem_solution.InitializeSolutionStep()
|
|
157
|
+
self.dem_solution._GetSolver().Predict()
|
|
158
|
+
self.dem_solution._GetSolver().SolveSolutionStep()
|
|
159
|
+
self.dem_solution.FinalizeSolutionStep()
|
|
160
|
+
self.AdditionalDEMOperationsToFinalizeDEMSolutionStep()
|
|
161
|
+
self.dem_solution.OutputSolutionStep()
|
|
162
|
+
|
|
163
|
+
self.dem_solution._GetSolver().cplusplus_strategy.HealAllBonds()
|
|
164
|
+
DEM.ParallelBondUtilities().SetCurrentIndentationAsAReferenceInParallelBonds(self.dem_solution.spheres_model_part)
|
|
165
|
+
|
|
166
|
+
if self.remove_isolated_particles:
|
|
167
|
+
self.creator_destructor.MarkIsolatedParticlesForErasing(self.dem_solution.spheres_model_part)
|
|
168
|
+
self.dem_solution.AdjustHoleInnerRadius()
|
|
169
|
+
DEM.PreUtilities().ResetSkinParticles(self.dem_solution.spheres_model_part)
|
|
170
|
+
self.dem_solution._GetSolver().cplusplus_strategy.ComputeSkin(self.dem_solution.spheres_model_part, 1.5)
|
|
171
|
+
if self.add_casing:
|
|
172
|
+
self.AddCasing()
|
|
173
|
+
|
|
174
|
+
def AddCasing(self):
|
|
175
|
+
|
|
176
|
+
max_FEM_node_Id = self.creator_destructor.FindMaxNodeIdInModelPart(self.dem_solution.rigid_face_model_part)
|
|
177
|
+
max_FEM_elem_Id = self.creator_destructor.FindMaxConditionIdInModelPart(self.dem_solution.rigid_face_model_part)
|
|
178
|
+
casing_length = 2.0 * math.pi * self.casing_radius
|
|
179
|
+
number_of_casing_elems = casing_length / self.casing_element_size
|
|
180
|
+
number_of_casing_elems = round(number_of_casing_elems)
|
|
181
|
+
delta_angle_in_radians = 2.0 * math.pi / number_of_casing_elems
|
|
182
|
+
for cond in self.submodelpart_with_external_walls.Conditions:
|
|
183
|
+
props = cond.Properties
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
for i in range(number_of_casing_elems):
|
|
187
|
+
Xi = self.casing_radius * math.cos(delta_angle_in_radians * i)
|
|
188
|
+
Yi = self.casing_radius * math.sin(delta_angle_in_radians * i)
|
|
189
|
+
self.dem_solution.casing_submodelpart.CreateNewNode(max_FEM_node_Id + i + 1, Xi, Yi, 0.0)
|
|
190
|
+
for i in range(number_of_casing_elems - 1):
|
|
191
|
+
self.dem_solution.casing_submodelpart.CreateNewCondition("RigidEdge2D2N", max_FEM_elem_Id + i + 1, [max_FEM_node_Id + i + 1, max_FEM_node_Id + i + 2], props)
|
|
192
|
+
self.dem_solution.casing_submodelpart.CreateNewCondition("RigidEdge2D2N", max_FEM_elem_Id + number_of_casing_elems, [max_FEM_node_Id + number_of_casing_elems, max_FEM_node_Id + 1], props)
|
|
193
|
+
|
|
194
|
+
def RunSolutionLoop(self):
|
|
195
|
+
|
|
196
|
+
self.stationarity_checking_is_activated = False
|
|
197
|
+
first_dem_solution_steadiness_achieved = False
|
|
198
|
+
|
|
199
|
+
while self.poromechanics_solution.KeepAdvancingSolutionLoop():
|
|
200
|
+
print("\n************************************ Solving FEM...\n", flush=True)
|
|
201
|
+
self.poromechanics_solution.time = self.poromechanics_solution._GetSolver().AdvanceInTime(self.poromechanics_solution.time)
|
|
202
|
+
self.poromechanics_solution.InitializeSolutionStep()
|
|
203
|
+
self.poromechanics_solution._GetSolver().Predict()
|
|
204
|
+
self.poromechanics_solution._GetSolver().SolveSolutionStep()
|
|
205
|
+
self.poromechanics_solution.FinalizeSolutionStep()
|
|
206
|
+
self.poromechanics_solution.OutputSolutionStep()
|
|
207
|
+
|
|
208
|
+
self.effective_stresses_communicator.CopyWallCurrentEffectiveStressesToOldEffectiveStresses()
|
|
209
|
+
self.effective_stresses_communicator.CommunicateCurrentRadialEffectiveStressesToDemWalls()
|
|
210
|
+
self.pore_pressure_communicator_utility.ComputeForceOnParticlesDueToPorePressureGradient()
|
|
211
|
+
|
|
212
|
+
print("\n************************************ Now solving DEM...\n", flush=True)
|
|
213
|
+
self.DEM_steps_counter = 0
|
|
214
|
+
self.dem_time_steps_per_fem_time_step = 0
|
|
215
|
+
self.dem_solution.time = self.poromechanics_solution.time
|
|
216
|
+
|
|
217
|
+
if first_dem_solution_steadiness_achieved and self.breakable_material_after_first_dem_solution_steadiness_achieved:
|
|
218
|
+
for elem in self.dem_solution.spheres_model_part.Elements:
|
|
219
|
+
elem.Properties.GetSubProperties(elem.Properties.Id)[DEM.IS_UNBREAKABLE] = False
|
|
220
|
+
break
|
|
221
|
+
|
|
222
|
+
while not self.DEMSolutionIsSteady():
|
|
223
|
+
self.dem_solution.time = self.dem_solution._GetSolver().AdvanceInTime(self.dem_solution.time)
|
|
224
|
+
self.center = KratosMultiphysics.Array3()
|
|
225
|
+
self.center[0] = 0; # self.sp_parameters["problem_data"]["center"][0].GetDouble()
|
|
226
|
+
self.center[1] = 0; # self.sp_parameters["problem_data"]["center"][1].GetDouble()
|
|
227
|
+
self.center[2] = 0; # self.sp_parameters["problem_data"]["center"][2].GetDouble()
|
|
228
|
+
self.axis = KratosMultiphysics.Array3()
|
|
229
|
+
self.axis[0] = 0; # self.sp_parameters["problem_data"]["axis"][0].GetDouble()
|
|
230
|
+
self.axis[1] = 0; # self.sp_parameters["problem_data"]["axis"][1].GetDouble()
|
|
231
|
+
self.axis[2] = 1; # self.sp_parameters["problem_data"]["axis"][2].GetDouble()
|
|
232
|
+
self.radius_to_delete_sp = 0.075
|
|
233
|
+
self.creator_destructor.MarkParticlesForErasingGivenCylinder(self.dem_solution.spheres_model_part, self.center, self.axis, self.radius_to_delete_sp)
|
|
234
|
+
|
|
235
|
+
self.dem_solution.InitializeSolutionStep()
|
|
236
|
+
self.dem_solution._GetSolver().Predict()
|
|
237
|
+
self.dem_solution._GetSolver().SolveSolutionStep()
|
|
238
|
+
self.dem_solution.FinalizeSolutionStep()
|
|
239
|
+
self.AdditionalDEMOperationsToFinalizeDEMSolutionStep()
|
|
240
|
+
self.dem_solution.OutputSolutionStep()
|
|
241
|
+
|
|
242
|
+
first_dem_solution_steadiness_achieved = True
|
|
243
|
+
|
|
244
|
+
def AdditionalDEMOperationsToFinalizeDEMSolutionStep(self):
|
|
245
|
+
|
|
246
|
+
if self.dem_solution.IsTimeToPrintPostProcess():
|
|
247
|
+
|
|
248
|
+
os.chdir(self.images_folder_path)
|
|
249
|
+
|
|
250
|
+
filename = 'radial_normal_and_smoothed_reaction_stresses_values_' + str(self.dem_solution.time) + '.txt'
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
os.remove(filename)
|
|
254
|
+
except OSError:
|
|
255
|
+
pass
|
|
256
|
+
|
|
257
|
+
radial_normal_and_smoothed_reaction_stresses_file = open(filename, 'a')
|
|
258
|
+
|
|
259
|
+
average_ratio = 0.0
|
|
260
|
+
|
|
261
|
+
for node in self.dem_solution.rigid_face_model_part.Nodes:
|
|
262
|
+
total_radial_normal_stress_value = node.GetValue(DEM.RADIAL_NORMAL_STRESS_COMPONENT)
|
|
263
|
+
A = node.GetValue(DEM.SMOOTHED_REACTION_STRESS_X)
|
|
264
|
+
B = node.GetValue(DEM.SMOOTHED_REACTION_STRESS_Y)
|
|
265
|
+
C = node.GetValue(DEM.SMOOTHED_REACTION_STRESS_Z)
|
|
266
|
+
total_smoothed_reaction_stress_value = math.sqrt(A*A + B*B + C*C)
|
|
267
|
+
if abs(total_radial_normal_stress_value) > 0.0:
|
|
268
|
+
this_node_applied_stress_ratio = -total_smoothed_reaction_stress_value / total_radial_normal_stress_value
|
|
269
|
+
else:
|
|
270
|
+
this_node_applied_stress_ratio = 0.0
|
|
271
|
+
average_ratio += this_node_applied_stress_ratio
|
|
272
|
+
displ = node.GetSolutionStepValue(Kratos.DISPLACEMENT)
|
|
273
|
+
displ_norm = math.sqrt(displ[0]*displ[0]+displ[1]*displ[1]+displ[2]*displ[2])
|
|
274
|
+
vel = node.GetSolutionStepValue(Kratos.VELOCITY)
|
|
275
|
+
vel_norm = math.sqrt(vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2])
|
|
276
|
+
radial_normal_and_smoothed_reaction_stresses_file.write(str(node.Id) + " " + str(node.X) + " " + str(node.Y) + " " + str(node.Z) + " " + str(total_radial_normal_stress_value) + " " + str(total_smoothed_reaction_stress_value) + " " + str(displ_norm) + " " + str(vel_norm) + '\n')
|
|
277
|
+
|
|
278
|
+
radial_normal_and_smoothed_reaction_stresses_file.close()
|
|
279
|
+
average_ratio = average_ratio / self.dem_solution.rigid_face_model_part.NumberOfNodes()
|
|
280
|
+
self.dem_solution.KratosPrintInfo("-------- Averaged loading ratio (average quotient current stress/ target stress) is " + str(average_ratio) + " ------------ \n")
|
|
281
|
+
|
|
282
|
+
os.chdir(self.case_dir)
|
|
283
|
+
|
|
284
|
+
'''total_average_target_radial_normal_stress = 0.0
|
|
285
|
+
total_forces_modulus = 0.0
|
|
286
|
+
|
|
287
|
+
for node in self.dem_solution.rigid_face_model_part.Nodes:
|
|
288
|
+
|
|
289
|
+
total_radial_normal_stress_value = node.GetValue(DEM.RADIAL_NORMAL_STRESS_COMPONENT)
|
|
290
|
+
nodal_area = node.GetSolutionStepValue(DEM.DEM_NODAL_AREA)
|
|
291
|
+
total_average_target_radial_normal_stress += nodal_area * total_radial_normal_stress_value
|
|
292
|
+
|
|
293
|
+
for element in self.dem_solution.spheres_model_part.Elements:
|
|
294
|
+
|
|
295
|
+
total_force_X = element.GetNode(0).GetSolutionStepValue(Kratos.EXTERNAL_APPLIED_FORCE_X)
|
|
296
|
+
total_force_Y = element.GetNode(0).GetSolutionStepValue(Kratos.EXTERNAL_APPLIED_FORCE_Y)
|
|
297
|
+
total_force_Z = element.GetNode(0).GetSolutionStepValue(Kratos.EXTERNAL_APPLIED_FORCE_Z)
|
|
298
|
+
forces_modulus = math.sqrt(total_force_X * total_force_X + total_force_Y * total_force_Y + total_force_Z * total_force_Z)
|
|
299
|
+
total_forces_modulus += forces_modulus'''
|
|
300
|
+
|
|
301
|
+
def DEMSolutionIsSteady(self):
|
|
302
|
+
|
|
303
|
+
self.dem_time_steps_per_fem_time_step += 1
|
|
304
|
+
|
|
305
|
+
if self.DEM_steps_counter == self.number_of_DEM_steps_between_steadiness_checks:
|
|
306
|
+
|
|
307
|
+
self.DEM_steps_counter = 0
|
|
308
|
+
|
|
309
|
+
print("\n*** DEM stationarity will now be checked...", flush=True)
|
|
310
|
+
|
|
311
|
+
if not DEM.StationarityChecker().CheckIfVariableIsNullInModelPart(self.dem_solution.spheres_model_part, Kratos.TOTAL_FORCES_X, self.stationarity_measuring_tolerance, self.ignore_isolated_particles):
|
|
312
|
+
print(" F_X is larger than the desired maximum\n", flush=True)
|
|
313
|
+
self.stationarity_checking_is_activated = True
|
|
314
|
+
return False
|
|
315
|
+
if not DEM.StationarityChecker().CheckIfVariableIsNullInModelPart(self.dem_solution.spheres_model_part, Kratos.TOTAL_FORCES_Y, self.stationarity_measuring_tolerance, self.ignore_isolated_particles):
|
|
316
|
+
print(" F_Y is larger than the desired maximum\n", flush=True)
|
|
317
|
+
self.stationarity_checking_is_activated = True
|
|
318
|
+
return False
|
|
319
|
+
if not DEM.StationarityChecker().CheckIfVariableIsNullInModelPart(self.dem_solution.spheres_model_part, Kratos.TOTAL_FORCES_Z, self.stationarity_measuring_tolerance, self.ignore_isolated_particles):
|
|
320
|
+
print(" F_Z is larger than the desired maximum\n", flush=True)
|
|
321
|
+
self.stationarity_checking_is_activated = True
|
|
322
|
+
return False
|
|
323
|
+
|
|
324
|
+
if self.stationarity_checking_is_activated:
|
|
325
|
+
print("\n ********** DEM solution is steady! ********** \n", flush=True)
|
|
326
|
+
with open('poro_solution_time_vs_dem_time_vs_dems_steps.txt', 'a') as time_and_steps_file:
|
|
327
|
+
time_and_steps_file.write(str(self.poromechanics_solution.time) + " " + str(self.dem_solution.time) + " " + str(self.dem_time_steps_per_fem_time_step) + '\n')
|
|
328
|
+
return True
|
|
329
|
+
else:
|
|
330
|
+
return False
|
|
331
|
+
else:
|
|
332
|
+
self.DEM_steps_counter += 1
|
|
333
|
+
return False
|
|
334
|
+
|
|
335
|
+
def Finalize(self):
|
|
336
|
+
self.poromechanics_solution.Finalize()
|
|
337
|
+
self.dem_solution.Finalize()
|
|
338
|
+
super().Finalize()
|
|
339
|
+
if self.create_stress_ratio_animation:
|
|
340
|
+
self.CreateReactionStressToTargetRatioAnimation()
|
|
341
|
+
|
|
342
|
+
def CreateReactionStressToTargetRatioAnimation(self):
|
|
343
|
+
# Use 'pip install opencv-python' at the command line in Windows to obtain cv2
|
|
344
|
+
import cv2
|
|
345
|
+
import matplotlib.pyplot as plt
|
|
346
|
+
print_one_out_of_n_results = 1
|
|
347
|
+
frames_per_second = 5
|
|
348
|
+
n = 0
|
|
349
|
+
list_of_pngs = []
|
|
350
|
+
os.chdir(self.images_folder_path)
|
|
351
|
+
|
|
352
|
+
for filename in os.listdir(self.images_folder_path):
|
|
353
|
+
n = n + 1
|
|
354
|
+
|
|
355
|
+
if n % print_one_out_of_n_results:
|
|
356
|
+
continue
|
|
357
|
+
|
|
358
|
+
if filename.endswith(".txt"):
|
|
359
|
+
X, Y = [], []
|
|
360
|
+
for line in open(filename, 'r'):
|
|
361
|
+
values = [float(s) for s in line.split()]
|
|
362
|
+
if values[4]:
|
|
363
|
+
X.append(values[1])
|
|
364
|
+
Y.append(-values[5]/values[4])
|
|
365
|
+
|
|
366
|
+
plt.axis((-1.5,1.5,0,2))
|
|
367
|
+
plt.xlabel("Xcoord (m)")
|
|
368
|
+
plt.ylabel("radial effective stress to target ratio")
|
|
369
|
+
plt.plot(X, Y, '.', color='blue')
|
|
370
|
+
plt.grid()
|
|
371
|
+
printfile = filename[:-4]
|
|
372
|
+
printfilename = os.path.join(self.images_folder_path, printfile + '.png')
|
|
373
|
+
list_of_pngs.append(printfilename)
|
|
374
|
+
plt.savefig(printfilename)
|
|
375
|
+
plt.close()
|
|
376
|
+
|
|
377
|
+
video_name = 'video.avi'
|
|
378
|
+
images = [img for img in os.listdir(self.images_folder_path) if img.endswith(".png")]
|
|
379
|
+
frame = cv2.imread(os.path.join(self.images_folder_path, images[0]))
|
|
380
|
+
height, width, layers = frame.shape
|
|
381
|
+
video = cv2.VideoWriter(video_name, 0, frames_per_second, (width,height))
|
|
382
|
+
|
|
383
|
+
for image in images:
|
|
384
|
+
video.write(cv2.imread(os.path.join(self.images_folder_path, image)))
|
|
385
|
+
|
|
386
|
+
cv2.destroyAllWindows()
|
|
387
|
+
video.release()
|
|
388
|
+
os.chdir(self.case_dir)
|
|
389
|
+
|
|
390
|
+
def _CreateSolver(self):
|
|
391
|
+
return DemPoroMechanicsCouplingSolver(self.poromechanics_solution._GetSolver(), self.dem_solution._GetSolver(), self.parameters)
|
|
392
|
+
|
|
393
|
+
def _CheckCoherentInputs(self):
|
|
394
|
+
variables_exported_from_gauss_points_to_nodes = self.parameters["poromechanics_parameters"]["solver_settings"]["gp_to_nodal_variable_list"].GetStringArray()
|
|
395
|
+
if not "LIQUID_PRESSURE_GRADIENT" in variables_exported_from_gauss_points_to_nodes or not "EFFECTIVE_STRESS_TENSOR" in variables_exported_from_gauss_points_to_nodes:
|
|
396
|
+
raise Exception("Coupling DEM with Poromechanics Error: [\"poromechanics_parameters\"][\"solver_settings\"][\"gp_to_nodal_variable_list\"] must contain \"LIQUID_PRESSURE_GRADIENT\" and \"EFFECTIVE_STRESS_TENSOR\"\n")
|
|
397
|
+
|
|
398
|
+
def _YieldDEMTime(self, current_time, current_time_plus_increment, delta_time):
|
|
399
|
+
current_time += delta_time
|
|
400
|
+
tolerance = 0.0001
|
|
401
|
+
while current_time < (current_time_plus_increment - tolerance * delta_time):
|
|
402
|
+
yield current_time
|
|
403
|
+
current_time += delta_time
|
|
404
|
+
|
|
405
|
+
current_time = current_time_plus_increment
|
|
406
|
+
yield current_time
|
|
407
|
+
|
|
408
|
+
class DemPoroMechanicsCouplingSolver(PythonSolver):
|
|
409
|
+
def __init__(self, poromechanics_solver, dem_solver, parameters):
|
|
410
|
+
self.poromechanics_solver = poromechanics_solver
|
|
411
|
+
self.dem_solver = dem_solver
|
|
412
|
+
|
|
413
|
+
def ImportModelPart(self):
|
|
414
|
+
pass
|
|
415
|
+
|
|
416
|
+
def GetComputingModelPart(self):
|
|
417
|
+
return self.poromechanics_solver.GetComputingModelPart()
|
|
418
|
+
|
|
419
|
+
if __name__ == "__main__":
|
|
420
|
+
with open("ProjectParameters.json", 'r') as parameter_file:
|
|
421
|
+
project_parameters = Kratos.Parameters(parameter_file.read())
|
|
422
|
+
|
|
423
|
+
model = Kratos.Model()
|
|
424
|
+
PoroMechanicsCouplingWithDemRadialMultiDofsControlModuleAnalysisStage(model, project_parameters).Run()
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
from KratosMultiphysics import MultiFileFlag
|
|
4
|
+
from KratosMultiphysics import GiDPostMode
|
|
5
|
+
from KratosMultiphysics import Logger
|
|
6
|
+
from KratosMultiphysics import DEMApplication
|
|
7
|
+
from KratosMultiphysics import DemStructuresCouplingApplication
|
|
8
|
+
from KratosMultiphysics import StructuralMechanicsApplication
|
|
9
|
+
from KratosMultiphysics import gid_output # this is deprecated
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DemStructuresCouplingGiDOutput(gid_output.GiDOutput):
|
|
13
|
+
|
|
14
|
+
def __init__(self,
|
|
15
|
+
file_name,
|
|
16
|
+
vol_output,
|
|
17
|
+
post_mode,
|
|
18
|
+
multifile,
|
|
19
|
+
deformed_mesh,
|
|
20
|
+
write_conditions,
|
|
21
|
+
structures_model_part,
|
|
22
|
+
balls_model_part,
|
|
23
|
+
clusters_model_part,
|
|
24
|
+
rigid_faces_model_part,
|
|
25
|
+
contact_model_part,
|
|
26
|
+
mixed_model_part
|
|
27
|
+
):
|
|
28
|
+
gid_output.GiDOutput.__init__(self,
|
|
29
|
+
file_name,
|
|
30
|
+
vol_output,
|
|
31
|
+
post_mode,
|
|
32
|
+
multifile,
|
|
33
|
+
deformed_mesh,
|
|
34
|
+
write_conditions)
|
|
35
|
+
|
|
36
|
+
self.GiDMultiFileFlag = multifile
|
|
37
|
+
|
|
38
|
+
self.outerlistfilename = os.path.join("..", self.listfilename)
|
|
39
|
+
|
|
40
|
+
self.structures_model_part = structures_model_part
|
|
41
|
+
self.balls_model_part = balls_model_part
|
|
42
|
+
self.clusters_model_part = clusters_model_part
|
|
43
|
+
self.rigid_faces_model_part = rigid_faces_model_part
|
|
44
|
+
self.contact_model_part = contact_model_part
|
|
45
|
+
self.mixed_model_part = mixed_model_part
|
|
46
|
+
|
|
47
|
+
self.structures_nodal_results = []
|
|
48
|
+
self.dem_nodal_results = []
|
|
49
|
+
self.clusters_nodal_results = []
|
|
50
|
+
self.rigid_faces_nodal_results = []
|
|
51
|
+
self.contact_gauss_points_results = []
|
|
52
|
+
self.mixed_nodal_results = []
|
|
53
|
+
self.structures_gauss_points_results = []
|
|
54
|
+
|
|
55
|
+
def initialize_dem_fem_results(self,
|
|
56
|
+
structures_nodal_results,
|
|
57
|
+
dem_nodal_results,
|
|
58
|
+
clusters_nodal_results,
|
|
59
|
+
rigid_faces_nodal_results,
|
|
60
|
+
contact_gauss_points_results,
|
|
61
|
+
mixed_nodal_results,
|
|
62
|
+
structures_gauss_points_results):
|
|
63
|
+
self.structures_nodal_results = structures_nodal_results
|
|
64
|
+
self.dem_nodal_results = dem_nodal_results
|
|
65
|
+
self.clusters_nodal_results = clusters_nodal_results
|
|
66
|
+
self.rigid_faces_nodal_results = rigid_faces_nodal_results
|
|
67
|
+
self.contact_gauss_points_results = contact_gauss_points_results
|
|
68
|
+
self.mixed_nodal_results = mixed_nodal_results
|
|
69
|
+
self.structures_gauss_points_results = structures_gauss_points_results
|
|
70
|
+
|
|
71
|
+
if self.multi_file == MultiFileFlag.SingleFile:
|
|
72
|
+
print("Singlefile option is not available for the DEM-Structures Coupling application!")
|
|
73
|
+
mesh_name = 0.0
|
|
74
|
+
self.io.InitializeMesh(mesh_name)
|
|
75
|
+
self.io.WriteSphereMesh(self.balls_model_part.GetMesh())
|
|
76
|
+
self.io.WriteMesh(self.clusters_model_part.GetMesh())
|
|
77
|
+
self.io.WriteMesh(self.rigid_faces_model_part.GetMesh())
|
|
78
|
+
self.io.WriteMesh(self.contact_model_part.GetMesh())
|
|
79
|
+
self.io.WriteMesh(self.mixed_model_part.GetMesh())
|
|
80
|
+
self.io.FinalizeMesh()
|
|
81
|
+
self.io.InitializeResults(mesh_name, self.mixed_model_part.GetMesh())
|
|
82
|
+
|
|
83
|
+
# Initialize list file
|
|
84
|
+
with open(self.listfilename, "w") as listfile:
|
|
85
|
+
|
|
86
|
+
if self.multi_file == MultiFileFlag.MultipleFiles:
|
|
87
|
+
listfile.write("Multiple\n")
|
|
88
|
+
|
|
89
|
+
elif self.multi_file == MultiFileFlag.SingleFile:
|
|
90
|
+
listfile.write("Single\n")
|
|
91
|
+
|
|
92
|
+
if self.multi_file == MultiFileFlag.SingleFile:
|
|
93
|
+
|
|
94
|
+
if self.post_mode == GiDPostMode.GiD_PostBinary:
|
|
95
|
+
self.write_step_to_list()
|
|
96
|
+
|
|
97
|
+
else:
|
|
98
|
+
self.write_step_to_list(0)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def write_step_to_list(self, step_label):
|
|
102
|
+
|
|
103
|
+
if self.post_mode == GiDPostMode.GiD_PostBinary:
|
|
104
|
+
ext = ".post.bin"
|
|
105
|
+
elif self.post_mode == GiDPostMode.GiD_PostAscii:
|
|
106
|
+
ext = ".post.res"
|
|
107
|
+
elif self.post_mode == GiDPostMode.GiD_PostAsciiZipped:
|
|
108
|
+
ext = ".post.res"
|
|
109
|
+
|
|
110
|
+
with open(self.listfilename, "a") as listfile:
|
|
111
|
+
listfile.write("Multiple\n")
|
|
112
|
+
listfile.write(self.filename+"_"+"%.12g"%step_label+ext+"\n")
|
|
113
|
+
|
|
114
|
+
def write_step_to_outer_list(self, step_label):
|
|
115
|
+
|
|
116
|
+
if self.post_mode == GiDPostMode.GiD_PostBinary:
|
|
117
|
+
ext = ".post.bin"
|
|
118
|
+
elif self.post_mode == GiDPostMode.GiD_PostAscii:
|
|
119
|
+
ext = ".post.res"
|
|
120
|
+
elif self.post_mode == GiDPostMode.GiD_PostAsciiZipped:
|
|
121
|
+
ext = ".post.res"
|
|
122
|
+
|
|
123
|
+
with open(self.outerlistfilename, "a") as listfile:
|
|
124
|
+
listfile.write("Multiple\n")
|
|
125
|
+
folder_name = self.filename + "_Post_Files"
|
|
126
|
+
full_string_to_write = os.path.join(folder_name,self.filename+"_"+"%.12g"%step_label+ext)
|
|
127
|
+
listfile.write(full_string_to_write+"\n")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def Writeresults(self, time):
|
|
131
|
+
|
|
132
|
+
Logger.PrintInfo("DEM-Struct","")
|
|
133
|
+
Logger.PrintInfo("DEM-Struct","******************* PRINTING RESULTS FOR GID ***************************")
|
|
134
|
+
Logger.Flush()
|
|
135
|
+
|
|
136
|
+
if self.GiDMultiFileFlag == "Multiples":
|
|
137
|
+
self.mixed_model_part.Elements.clear()
|
|
138
|
+
self.mixed_model_part.Nodes.clear()
|
|
139
|
+
# here order is important!
|
|
140
|
+
DEMApplication.PostUtilities().AddModelPartToModelPart(self.mixed_model_part, self.balls_model_part)
|
|
141
|
+
DEMApplication.PostUtilities().AddModelPartToModelPart(self.mixed_model_part, self.rigid_faces_model_part)
|
|
142
|
+
DEMApplication.PostUtilities().AddModelPartToModelPart(self.mixed_model_part, self.contact_model_part)
|
|
143
|
+
DEMApplication.PostUtilities().AddModelPartToModelPart(self.mixed_model_part, self.structures_model_part)
|
|
144
|
+
|
|
145
|
+
self.write_dem_fem_results(time)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def write_dem_fem_results(self, label):
|
|
149
|
+
# label = str(label) #it should be a C double
|
|
150
|
+
# update cut data if necessary
|
|
151
|
+
out_model_part = self.get_out_model_part(self.structures_model_part)
|
|
152
|
+
|
|
153
|
+
# update cut data if necessary
|
|
154
|
+
if not self.volume_output:
|
|
155
|
+
self.cut_app.UpdateCutData(out_model_part, self.structures_model_part)
|
|
156
|
+
|
|
157
|
+
if self.multi_file == MultiFileFlag.MultipleFiles:
|
|
158
|
+
self.io.InitializeMesh(label)
|
|
159
|
+
self.io.WriteSphereMesh(self.balls_model_part.GetMesh())
|
|
160
|
+
self.io.WriteMesh(self.mixed_model_part.GetMesh())
|
|
161
|
+
self.io.WriteMesh(self.rigid_faces_model_part.GetMesh())
|
|
162
|
+
self.io.WriteMesh(self.contact_model_part.GetMesh())
|
|
163
|
+
self.io.FinalizeMesh()
|
|
164
|
+
self.io.InitializeResults(label, self.mixed_model_part.GetMesh())
|
|
165
|
+
|
|
166
|
+
for var in self.structures_nodal_results:
|
|
167
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
168
|
+
self._write_nodal_results(label, self.structures_model_part, kratos_variable)
|
|
169
|
+
|
|
170
|
+
for var in self.dem_nodal_results:
|
|
171
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
172
|
+
self._write_nodal_results(label, self.balls_model_part, kratos_variable)
|
|
173
|
+
|
|
174
|
+
for var in self.clusters_nodal_results:
|
|
175
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
176
|
+
self._write_nodal_results(label, self.clusters_model_part, kratos_variable)
|
|
177
|
+
|
|
178
|
+
for var in self.rigid_faces_nodal_results:
|
|
179
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
180
|
+
self._write_nodal_results(label, self.rigid_faces_model_part, kratos_variable)
|
|
181
|
+
|
|
182
|
+
for var in self.contact_gauss_points_results:
|
|
183
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
184
|
+
self._write_gp_results(label, self.contact_model_part, kratos_variable)
|
|
185
|
+
|
|
186
|
+
for var in self.mixed_nodal_results:
|
|
187
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
188
|
+
self._write_nodal_results(label, self.mixed_model_part, kratos_variable)
|
|
189
|
+
|
|
190
|
+
for var in self.structures_gauss_points_results:
|
|
191
|
+
kratos_variable = Kratos.KratosGlobals.GetVariable(var)
|
|
192
|
+
self._write_gp_results(label, self.structures_model_part, kratos_variable)
|
|
193
|
+
|
|
194
|
+
if self.multi_file == MultiFileFlag.MultipleFiles:
|
|
195
|
+
self._finalize_results()
|
|
196
|
+
|
|
197
|
+
with open(self.listfilename, "a") as listfile:
|
|
198
|
+
self.write_step_to_list(label)
|
|
199
|
+
|
|
200
|
+
self.write_step_to_outer_list(label)
|
|
201
|
+
|