buckpy-dev 0.0.1__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.
- buckpy/__init__.py +13 -0
- buckpy/_static/logo.png +0 -0
- buckpy/_static/logo.svg +4 -0
- buckpy/buckfast_input_file_writer_.py +1233 -0
- buckpy/buckpy.py +132 -0
- buckpy/buckpy_gui.py +359 -0
- buckpy/buckpy_postprocessing.py +1305 -0
- buckpy/buckpy_preprocessing_current.py +1142 -0
- buckpy/buckpy_preprocessing_legacy.py +900 -0
- buckpy/buckpy_solver.py +777 -0
- buckpy/buckpy_variables.py +98 -0
- buckpy/buckpy_visualisation.py +419 -0
- buckpy_dev-0.0.1.dist-info/METADATA +51 -0
- buckpy_dev-0.0.1.dist-info/RECORD +18 -0
- buckpy_dev-0.0.1.dist-info/WHEEL +5 -0
- buckpy_dev-0.0.1.dist-info/entry_points.txt +2 -0
- buckpy_dev-0.0.1.dist-info/licenses/LICENSE +674 -0
- buckpy_dev-0.0.1.dist-info/top_level.txt +1 -0
buckpy/buckpy_solver.py
ADDED
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the solver functions of BuckPy.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from multiprocess import Process, Queue, cpu_count
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from numba import jit
|
|
10
|
+
from .buckpy_variables import *
|
|
11
|
+
|
|
12
|
+
def exec_buckpy(np_scen, np_distr, np_ends, n_sim, fric_sampling, bl_verbose):
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
Execute buckpy methodology
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
np_scen : numpy.ndarray
|
|
20
|
+
Array containing the pipeline desing data on assessed mesh.
|
|
21
|
+
np_distr : numpy.ndarray
|
|
22
|
+
3-D array describing the stochastic distributions:
|
|
23
|
+
- dim 1: properties
|
|
24
|
+
- dim 2: elements
|
|
25
|
+
- dim 3: values
|
|
26
|
+
np_ends : numpy.ndarray
|
|
27
|
+
Array containing information about the boundary conditions at the ends of the pipeline.
|
|
28
|
+
n_sim : int
|
|
29
|
+
Number of Monte-Carlo simulations to be run.
|
|
30
|
+
fric_sampling : int
|
|
31
|
+
Switch to select the sampling method of the lateral friction: 0 for 'per Element'
|
|
32
|
+
or 1 'per OOS Reference Length'
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
df_pp_plot : DataFrame
|
|
37
|
+
Definition on assessed mesh of CBF and EAF in different conditions
|
|
38
|
+
for case to plot.
|
|
39
|
+
df_VAP_plot : DataFrame
|
|
40
|
+
Definition of virtual anchor points for case to plot.
|
|
41
|
+
df_pp_buckle_prop : DataFrame
|
|
42
|
+
Results for all buckles triggered.
|
|
43
|
+
|
|
44
|
+
Other Parameters
|
|
45
|
+
----------------
|
|
46
|
+
bl_verbose : boolean, optional
|
|
47
|
+
True if intermediate printouts are required (False by default).
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# Starting time of the solver module
|
|
51
|
+
start_time = time.time()
|
|
52
|
+
|
|
53
|
+
# Run deterministic case
|
|
54
|
+
if bl_verbose:
|
|
55
|
+
print("2. Run the deterministic case")
|
|
56
|
+
np_prob_var_det = np.empty(0)
|
|
57
|
+
np_case_det = preprocess_case(np_prob_var_det, np_scen, np_ends, bl_det = True)
|
|
58
|
+
np_pp_buckle_det, np_case_det_updated, vap_list_det = solve_case(np_scen, np_case_det)
|
|
59
|
+
|
|
60
|
+
# To be discussed: This block has been replaced to enable a like to like comparison with
|
|
61
|
+
# Buckfast.
|
|
62
|
+
|
|
63
|
+
# # Print-out force profiles for graphical display
|
|
64
|
+
# # (Deterministic case if it buckles, or otherwise first random case that buckles)
|
|
65
|
+
# np_pp_plot = np.empty((9, np_scen[KP].size))
|
|
66
|
+
# vap_list = []
|
|
67
|
+
# df_VAP_plot = pd.DataFrame(vap_list, columns = ['ielt VAP', 'KP VAP', 'ESF VAP'])
|
|
68
|
+
# n_buckle = np_pp_buckle_det.shape[0]
|
|
69
|
+
# if n_buckle > 0: # Deterministic case buckled
|
|
70
|
+
# for i_buckle in range(n_buckle):
|
|
71
|
+
# np_pp_buckle_det[i_buckle, SIM_PP] = 1
|
|
72
|
+
# np_pp_plot[P_KP] = np_scen[KP]
|
|
73
|
+
# np_pp_plot[P_CBF_HT] = np_case_det[CBF_HT]
|
|
74
|
+
# np_pp_plot[P_CBF_OP] = np_case_det[CBF_OP]
|
|
75
|
+
# np_pp_plot[P_EAF_INST] = np_case_det[EAF_INST]
|
|
76
|
+
# np_pp_plot[P_EAF_HT] = np_case_det_updated[EAF_HT]
|
|
77
|
+
# np_pp_plot[P_EAF_P_OP] = np_case_det_updated[EAF_P_OP]
|
|
78
|
+
# np_pp_plot[P_EAF_OP] = np_case_det_updated[EAF_OP]
|
|
79
|
+
# np_pp_plot[P_EAF_OP_UNBUCK] = np_case_det[EAF_OP_UNBUCK]
|
|
80
|
+
# df_VAP_plot = pd.DataFrame(vap_list_det, columns = ['ielt VAP', 'KP VAP', 'ESF VAP'])
|
|
81
|
+
# print(' The deterministic case has buckled')
|
|
82
|
+
# if bl_verbose:
|
|
83
|
+
# print(f' Time taken to run the deterministic case: {time.time()-start_time:.1f}s')
|
|
84
|
+
|
|
85
|
+
# # If there is no buckling on deterministic case then for result display
|
|
86
|
+
# # generate a random case until buckling is triggered (max iteration<n_sim)
|
|
87
|
+
# else:
|
|
88
|
+
# for i_sim in range(n_sim):
|
|
89
|
+
# np_prob_var = sample_randomness_case(fric_sampling, np_distr, np_scen)
|
|
90
|
+
# np_case = preprocess_case(np_prob_var, np_scen, np_ends, bl_det = False)
|
|
91
|
+
# np_pp_buckle, np_case_updated, vap_list = solve_case(np_scen, np_case)
|
|
92
|
+
# n_buckle = np_pp_buckle.shape[0]
|
|
93
|
+
# if n_buckle > 0: # Found random case buckling
|
|
94
|
+
# for i_buckle in range(n_buckle):
|
|
95
|
+
# np_pp_buckle[i_buckle, SIM_PP] = i_sim
|
|
96
|
+
# np_pp_plot[P_KP] = np_scen[KP]
|
|
97
|
+
# np_pp_plot[P_CBF_HT] = np_case[CBF_HT]
|
|
98
|
+
# np_pp_plot[P_CBF_OP] = np_case[CBF_OP]
|
|
99
|
+
# np_pp_plot[P_EAF_INST] = np_case[EAF_INST]
|
|
100
|
+
# np_pp_plot[P_EAF_HT] = np_case_updated[EAF_HT]
|
|
101
|
+
# np_pp_plot[P_EAF_P_OP] = np_case_updated[EAF_P_OP]
|
|
102
|
+
# np_pp_plot[P_EAF_OP] = np_case_updated[EAF_OP]
|
|
103
|
+
# np_pp_plot[P_EAF_OP_UNBUCK] = np_case[EAF_OP_UNBUCK]
|
|
104
|
+
# #
|
|
105
|
+
# df_VAP_plot = pd.DataFrame(vap_list, columns = ['ielt VAP', 'KP VAP', 'ESF VAP'])
|
|
106
|
+
# print(f' The random case {i_sim} has buckled')
|
|
107
|
+
# break
|
|
108
|
+
|
|
109
|
+
# Print-out force profiles for graphical display (deterministic simulation only)
|
|
110
|
+
np_pp_plot = np.empty((9, np_scen[KP].size))
|
|
111
|
+
vap_list = []
|
|
112
|
+
df_VAP_plot = pd.DataFrame(vap_list, columns = ['ielt VAP', 'KP VAP', 'ESF VAP'])
|
|
113
|
+
n_buckle = np_pp_buckle_det.shape[0]
|
|
114
|
+
for i_buckle in range(n_buckle):
|
|
115
|
+
np_pp_buckle_det[i_buckle, SIM_PP] = 1
|
|
116
|
+
np_pp_plot[P_KP] = np_scen[KP]
|
|
117
|
+
np_pp_plot[P_CBF_HT] = np_case_det[CBF_HT]
|
|
118
|
+
np_pp_plot[P_CBF_OP] = np_case_det[CBF_OP]
|
|
119
|
+
np_pp_plot[P_EAF_INST] = np_case_det[EAF_INST]
|
|
120
|
+
np_pp_plot[P_EAF_HT] = np_case_det_updated[EAF_HT]
|
|
121
|
+
np_pp_plot[P_EAF_P_OP] = np_case_det_updated[EAF_P_OP]
|
|
122
|
+
np_pp_plot[P_EAF_OP] = np_case_det_updated[EAF_OP]
|
|
123
|
+
np_pp_plot[P_EAF_OP_UNBUCK] = np_case_det[EAF_OP_UNBUCK]
|
|
124
|
+
df_VAP_plot = pd.DataFrame(vap_list_det, columns = ['ielt VAP', 'KP VAP', 'ESF VAP'])
|
|
125
|
+
print(' The deterministic case has buckled')
|
|
126
|
+
if bl_verbose:
|
|
127
|
+
print(f' Time taken to run the deterministic case: {time.time()-start_time:.1f}s')
|
|
128
|
+
|
|
129
|
+
# Run Monte-Carlo loop
|
|
130
|
+
if bl_verbose:
|
|
131
|
+
print("3. Run the Monte-Carlo loop")
|
|
132
|
+
start_time = time.time()
|
|
133
|
+
if n_sim <= 10000:
|
|
134
|
+
N_WORKER = 1
|
|
135
|
+
else:
|
|
136
|
+
N_WORKER = cpu_count()
|
|
137
|
+
list_buckle_prop = run_monte_carlo(N_WORKER, n_sim, np_distr, np_scen,
|
|
138
|
+
np_ends, fric_sampling, bl_verbose = bl_verbose)
|
|
139
|
+
if bl_verbose:
|
|
140
|
+
print(f' Time taken to extract {len(list_buckle_prop)}'
|
|
141
|
+
f' simulations: {time.time()-start_time:.1f}s')
|
|
142
|
+
|
|
143
|
+
# Post-process 'df_pp_buckle_prop' and 'df_pp_buckle_prop'
|
|
144
|
+
column_list = ['isim', 'KP', 'route_type', 'muax', 'mulat_op', 'HOOS', 'CBF_op', 'VAS_op']
|
|
145
|
+
df_pp_buckle_prop = pd.DataFrame(np.concatenate(list_buckle_prop), columns = column_list)
|
|
146
|
+
column_list = ['KP', 'CBF_ht', 'CBF_op', 'EAF_inst', 'EAF_ht',
|
|
147
|
+
'EAF_p_op','EAF_op', 'beta2', 'EAF_op_unbuck']
|
|
148
|
+
df_pp_plot = pd.DataFrame(np.transpose(np_pp_plot), columns = column_list)
|
|
149
|
+
|
|
150
|
+
return df_pp_plot, df_VAP_plot, df_pp_buckle_prop
|
|
151
|
+
|
|
152
|
+
@jit(nopython=True)
|
|
153
|
+
def sample_randomness_case(fric_sampling, np_distr, np_scen):
|
|
154
|
+
|
|
155
|
+
"""
|
|
156
|
+
Samples the stochastic variables (HOOS and friction factors).
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
fric_sampling : int
|
|
161
|
+
Switch to select the sampling method of the lateral friction: 0 for 'per Element'
|
|
162
|
+
or 1 'per OOS Reference Length'
|
|
163
|
+
np_distr : numpy.ndarray
|
|
164
|
+
3-D array describing the stochastic distributions: Dim 1 = Properties, Dim 2 = Elements and
|
|
165
|
+
Dim 3 = values
|
|
166
|
+
np_scen : numpy.ndarray
|
|
167
|
+
Array containing the pipeline desing data on assessed mesh.
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
np_prob_var : numpy.ndarray
|
|
172
|
+
Definition of probabilistic variables on assessed mesh.
|
|
173
|
+
Rows correspond to properties: MUAX = 0, MULAT_HT = 1, MULAT_OP = 2, HOOS = 3
|
|
174
|
+
|
|
175
|
+
Notes
|
|
176
|
+
-----
|
|
177
|
+
The returned `np_prob_var` has values by columns corresponding to mesh elements
|
|
178
|
+
over 4 rows corresponding to properties defined above.
|
|
179
|
+
|
|
180
|
+
| MUAX: Axial friction coefficient
|
|
181
|
+
| MULAT_HT: Lateral friction coefficient for Hydrotest condition
|
|
182
|
+
| MULAT_OP: Lateral friction coefficient for Operation condition
|
|
183
|
+
| HOOS: Soil property indicator
|
|
184
|
+
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
# Number of elements in the assessed mesh
|
|
188
|
+
n_elts = np_scen[KP].size
|
|
189
|
+
# Initialize the array to store probabilistic variables
|
|
190
|
+
np_prob_var = np.empty((4, n_elts))
|
|
191
|
+
|
|
192
|
+
# Sample axial friction coefficient
|
|
193
|
+
muax_rand = np.random.rand()
|
|
194
|
+
|
|
195
|
+
# Sample lateral friction coefficient
|
|
196
|
+
if fric_sampling == 0: # Sample per element
|
|
197
|
+
mul_rand = np.random.rand(n_elts)
|
|
198
|
+
elif fric_sampling == 1: # Sample per OOS Reference Length
|
|
199
|
+
mul_rand = np.full(n_elts, np.random.rand())
|
|
200
|
+
for i in range(2, int(np.amax(np_scen[SECTION_ID])) + 1):
|
|
201
|
+
mul_rand[np_scen[SECTION_ID] == i] = np.random.rand()
|
|
202
|
+
|
|
203
|
+
# Sample HOOS factor
|
|
204
|
+
hoos_rand = np.random.rand(n_elts)
|
|
205
|
+
|
|
206
|
+
# Interpolate sampled values based on CDF arrays to get probabilistic variables
|
|
207
|
+
for i in range(n_elts):
|
|
208
|
+
np_prob_var[MUAX, i] = np.interp(
|
|
209
|
+
muax_rand, np_distr[MUAX_CDF_ARRAY][i], np_distr[MUAX_ARRAY][i])
|
|
210
|
+
np_prob_var[MULAT_HT, i] = np.interp(
|
|
211
|
+
mul_rand[i], np_distr[MULAT_CDF_ARRAY_HT][i], np_distr[MULAT_ARRAY_HT][i])
|
|
212
|
+
np_prob_var[MULAT_OP, i] = np.interp(
|
|
213
|
+
mul_rand[i], np_distr[MULAT_CDF_ARRAY_OP][i], np_distr[MULAT_ARRAY_OP][i])
|
|
214
|
+
np_prob_var[HOOS, i] = np.interp(
|
|
215
|
+
hoos_rand[i], np_distr[HOOS_CDF_ARRAY][i], np_distr[HOOS_ARRAY][i])
|
|
216
|
+
|
|
217
|
+
return np_prob_var
|
|
218
|
+
|
|
219
|
+
def preprocess_case(np_prob_var, np_scen, np_ends, bl_det = False):
|
|
220
|
+
"""
|
|
221
|
+
Preprocess case based on scenario definition and probabilistic variables.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
np_prob_var : numpy.ndarray
|
|
226
|
+
Probabilistic variables for the case (shape: 4 x n_elements).
|
|
227
|
+
np_scen : numpy.ndarray
|
|
228
|
+
Scenario data array (rows = properties, columns = elements).
|
|
229
|
+
np_ends : numpy.ndarray
|
|
230
|
+
End boundary condition array (rows = properties, columns = ends).
|
|
231
|
+
bl_det : bool, optional
|
|
232
|
+
If True, use mean values; if False, use sampled values. Default is False.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
np_case : numpy.ndarray
|
|
237
|
+
Case array (21 x n_elements) with rows:
|
|
238
|
+
- 0 : MUAX
|
|
239
|
+
- 1 : MULAT_HT
|
|
240
|
+
- 2 : MULAT_OP
|
|
241
|
+
- 3 : HOOS
|
|
242
|
+
- 4 : CBF_HT
|
|
243
|
+
- 5 : CBF_OP
|
|
244
|
+
- 6 : LFF_INST
|
|
245
|
+
- 7 : LFF_HT
|
|
246
|
+
- 8 : LFF_OP
|
|
247
|
+
- 9 : RFF_INST
|
|
248
|
+
- 10 : RFF_HT
|
|
249
|
+
- 11 : RFF_OP
|
|
250
|
+
- 12 : EAF_INST
|
|
251
|
+
- 13 : EAF_HT
|
|
252
|
+
- 14 : EAF_P_OP
|
|
253
|
+
- 15 : EAF_OP
|
|
254
|
+
- 16 : EAF_OP_UNBUCK
|
|
255
|
+
- 17 : LDELTAF_HT
|
|
256
|
+
- 18 : RDELTAF_HT
|
|
257
|
+
- 19 : LDELTAF_OP
|
|
258
|
+
- 20 : RDELTAF_OP
|
|
259
|
+
|
|
260
|
+
Notes
|
|
261
|
+
-----
|
|
262
|
+
Computes CBF and frictional forces based on route type and boundary conditions,
|
|
263
|
+
and builds effective axial force (EAF) profiles for installation, hydrotest, and operation.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
# Extracting the number of elements from the scenario array
|
|
267
|
+
n_elts = np_scen[KP].size
|
|
268
|
+
|
|
269
|
+
# Creating an empty array to store processed case-specific data
|
|
270
|
+
np_case = np.empty((21, np_scen.shape[1]))
|
|
271
|
+
|
|
272
|
+
if bl_det: # Alocating mean values to probabilistic variables
|
|
273
|
+
np_case[MUAX] = np_scen[MUAX_MEAN]
|
|
274
|
+
np_case[MULAT_HT] = np_scen[MULAT_HT_MEAN]
|
|
275
|
+
np_case[MULAT_OP] = np_scen[MULAT_OP_MEAN]
|
|
276
|
+
np_case[HOOS] = np.where(np_scen[ROUTE_TYPE] < 4, np_scen[HOOS_MEAN], np_scen[CBF_RCM])
|
|
277
|
+
|
|
278
|
+
else: # Copying probabilistic variables to the case array
|
|
279
|
+
np_case[MUAX] = np_prob_var[MUAX]
|
|
280
|
+
np_case[MULAT_HT] = np_prob_var[MULAT_HT]
|
|
281
|
+
np_case[MULAT_OP] = np_prob_var[MULAT_OP]
|
|
282
|
+
np_case[HOOS] = np_prob_var[HOOS]
|
|
283
|
+
|
|
284
|
+
# Calculating buckling forces based on route types
|
|
285
|
+
for i in range(n_elts):
|
|
286
|
+
if np_scen[ROUTE_TYPE, i] == 1: # Straight section
|
|
287
|
+
np_case[CBF_HT, i] = np_case[HOOS, i] * np_scen[SCHAR_HT, i] \
|
|
288
|
+
* np_case[MULAT_HT, i]**0.5
|
|
289
|
+
np_case[CBF_OP, i] = np_case[HOOS, i] * np_scen[SCHAR_OP, i] \
|
|
290
|
+
* np_case[MULAT_OP, i]**0.5
|
|
291
|
+
elif np_scen[ROUTE_TYPE, i] == 2: # Curve section
|
|
292
|
+
np_case[CBF_HT, i] = np_case[HOOS, i] * np_case[MULAT_HT, i] \
|
|
293
|
+
* np_scen[SW_HT, i] * np_scen[BEND_RADIUS, i]
|
|
294
|
+
np_case[CBF_OP, i] = np_case[HOOS, i] * np_case[MULAT_OP, i] \
|
|
295
|
+
* np_scen[SW_OP, i] * np_scen[BEND_RADIUS, i]
|
|
296
|
+
elif np_scen[ROUTE_TYPE, i] == 3: # Sleeper
|
|
297
|
+
np_case[CBF_HT, i] = np_case[HOOS, i] * np_scen[SV_HT, i]
|
|
298
|
+
np_case[CBF_OP, i] = np_case[HOOS, i] * np_scen[SV_OP, i]
|
|
299
|
+
elif np_scen[ROUTE_TYPE, i] == 4: # RCM
|
|
300
|
+
np_case[CBF_HT, i] = np_case[HOOS, i]
|
|
301
|
+
np_case[CBF_OP, i] = np_case[HOOS, i]
|
|
302
|
+
|
|
303
|
+
# Calculate friction forces accounting for boundary conditions
|
|
304
|
+
np_case[LFF_INST], np_case[RFF_INST], junk1, junk2 = calc_fric_forces(
|
|
305
|
+
-np_case[MUAX] * np_scen[SW_INST] * np_scen[LENGTH],
|
|
306
|
+
np_ends[REAC_INST, 0], np_ends[REAC_INST, 1])
|
|
307
|
+
np_case[LFF_HT], np_case[RFF_HT], np_case[LDELTAF_HT], np_case[RDELTAF_HT] = calc_fric_forces(
|
|
308
|
+
np_case[MUAX] * np_scen[SW_HT] * np_scen[LENGTH],
|
|
309
|
+
np_ends[REAC_HT, 0], np_ends[REAC_HT, 1])
|
|
310
|
+
np_case[LFF_OP], np_case[RFF_OP], np_case[LDELTAF_OP], np_case[RDELTAF_OP] = calc_fric_forces(
|
|
311
|
+
np_case[MUAX] * np_scen[SW_OP] * np_scen[LENGTH],
|
|
312
|
+
np_ends[REAC_OP, 0], np_ends[REAC_OP, 1])
|
|
313
|
+
|
|
314
|
+
# Adjust friction forces based on boundary conditions
|
|
315
|
+
if np_ends[ROUTE_TYPE_BC, 0] == 2: # Fixed BC at "left" end side
|
|
316
|
+
np_case[LFF_INST] = np.full(n_elts, -9.0E+09)
|
|
317
|
+
np_case[LFF_HT] = np.full(n_elts, 9.0E+09)
|
|
318
|
+
np_case[LFF_OP] = np.full(n_elts, 9.0E+09)
|
|
319
|
+
if np_ends[ROUTE_TYPE_BC, 1] == 2: # Fixed BC at "right" end side
|
|
320
|
+
np_case[RFF_INST] = np.full(n_elts, -9.0E+09)
|
|
321
|
+
np_case[RFF_HT] = np.full(n_elts, 9.0E+09)
|
|
322
|
+
np_case[RFF_OP] = np.full(n_elts, 9.0E+09)
|
|
323
|
+
|
|
324
|
+
# Build up frictional effective forces
|
|
325
|
+
np_case[EAF_INST] = np.maximum(
|
|
326
|
+
np.maximum(np_case[LFF_INST], np_case[RFF_INST]), np_scen[RLT])
|
|
327
|
+
np_case[EAF_HT] = np.minimum(
|
|
328
|
+
np.minimum(np_case[LFF_HT], np_case[RFF_HT]), np_scen[FRF_HT])
|
|
329
|
+
np_case[EAF_P_OP] = np.minimum(
|
|
330
|
+
np.minimum(np_case[LFF_OP], np_case[RFF_OP]), np_scen[FRF_P_OP])
|
|
331
|
+
np_case[EAF_OP] = np.minimum(
|
|
332
|
+
np.minimum(np_case[LFF_OP], np_case[RFF_OP]), np_scen[FRF_OP])
|
|
333
|
+
np_case[EAF_OP_UNBUCK] = np.minimum(
|
|
334
|
+
np.minimum(np_case[LFF_OP], np_case[RFF_OP]), np_scen[FRF_OP])
|
|
335
|
+
|
|
336
|
+
return np_case
|
|
337
|
+
|
|
338
|
+
def calc_fric_forces(np_array, restr_left, restr_right):
|
|
339
|
+
|
|
340
|
+
"""
|
|
341
|
+
Accumulate friction forces from each end of the array. The calculated values are at the center
|
|
342
|
+
of each element, accounting for the average increase between the element and its surrounding
|
|
343
|
+
elements.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
np_array : numpy.ndarray
|
|
348
|
+
Array containing the local friction force for each element without accounting for
|
|
349
|
+
surrounding values.
|
|
350
|
+
restr_left : float
|
|
351
|
+
Constant force to be added at the left of the force profile.
|
|
352
|
+
restr_right : float
|
|
353
|
+
Constant force to be added at the right of the force profile.
|
|
354
|
+
|
|
355
|
+
Returns
|
|
356
|
+
-------
|
|
357
|
+
np_cumsum_left: numpy.ndarray
|
|
358
|
+
Cumulated friction force from the left.
|
|
359
|
+
np_cumsum_right: numpy.ndarray
|
|
360
|
+
Cumulated friction force from the right.
|
|
361
|
+
np_rolling_mean_left: numpy.ndarray
|
|
362
|
+
Average friction force increment from the left.
|
|
363
|
+
np_rolling_mean_right: numpy.ndarray
|
|
364
|
+
Average friction force increment from the right.
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
# Cumulate the effective axial friction forces
|
|
368
|
+
ret = np.cumsum(np_array, dtype=float)
|
|
369
|
+
|
|
370
|
+
# Calculate the average increase between each element and its surrounding elements
|
|
371
|
+
ret[2:] = ret[2:] - ret[:-2]
|
|
372
|
+
|
|
373
|
+
# Compute the rolling mean for the left and right ends
|
|
374
|
+
np_rolling_mean_left = np.append(restr_left + np_array[0] / 2.0, ret[1:] / 2.0)
|
|
375
|
+
np_rolling_mean_right = np.append(ret[1:] / 2.0, restr_right + np_array[-1] / 2.0)
|
|
376
|
+
|
|
377
|
+
# Compute the cumulative effective axial forces from the left and right
|
|
378
|
+
np_cumsum_left = np.cumsum(np_rolling_mean_left)
|
|
379
|
+
np_cumsum_right = np.cumsum(np_rolling_mean_right[::-1])[::-1]
|
|
380
|
+
|
|
381
|
+
return np_cumsum_left, np_cumsum_right, np_rolling_mean_left, np_rolling_mean_right
|
|
382
|
+
|
|
383
|
+
@jit(nopython=True)
|
|
384
|
+
def solve_case(np_scen, np_case):
|
|
385
|
+
"""
|
|
386
|
+
Calculate effective force profiles during hydrotest and operation and identify buckle properties.
|
|
387
|
+
|
|
388
|
+
Parameters
|
|
389
|
+
----------
|
|
390
|
+
np_scen : numpy.ndarray
|
|
391
|
+
Scenario array (rows = properties, columns = elements).
|
|
392
|
+
np_case : numpy.ndarray
|
|
393
|
+
Case array (rows = properties, columns = elements).
|
|
394
|
+
|
|
395
|
+
Returns
|
|
396
|
+
-------
|
|
397
|
+
np_pp_buckle : numpy.ndarray
|
|
398
|
+
2D array (n_buckles x 8) with columns:
|
|
399
|
+
- 0 : SIM_PP
|
|
400
|
+
- 1 : KP_PP
|
|
401
|
+
- 2 : ROUTE_TYPE_PP
|
|
402
|
+
- 3 : MUAX_PP
|
|
403
|
+
- 4 : MULAT_OP_PP
|
|
404
|
+
- 5 : HOOS_PP
|
|
405
|
+
- 6 : CBF_OP_PP
|
|
406
|
+
- 7 : VAS_PP
|
|
407
|
+
np_case : numpy.ndarray
|
|
408
|
+
Updated case array (21 x n_elements).
|
|
409
|
+
vap_list : list[list]
|
|
410
|
+
[element_index, KP, ESF_op] for virtual anchor points (sorted by KP).
|
|
411
|
+
|
|
412
|
+
Notes
|
|
413
|
+
-----
|
|
414
|
+
Buckle identification is performed in stages (HT, OP pressure-only, OP pressure+temperature),
|
|
415
|
+
updating EAF profiles after each buckle is found.
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
# Step 1: Get order and location of potential buckles from HT step
|
|
419
|
+
np_beta = (np_case[CBF_HT] - np_case[EAF_INST]) / (np_scen[FRF_HT] - np_scen[RLT])
|
|
420
|
+
np_beta = np.around(np_beta, decimals = 6)
|
|
421
|
+
sorted_beta_array = np.argsort(np_beta, kind = "mergesort")
|
|
422
|
+
|
|
423
|
+
# Step 2: Compare local driving force during HT with CBF to identify actual buckles,
|
|
424
|
+
# in the order of the potential buckles
|
|
425
|
+
np_buckle_id = np.empty(0)
|
|
426
|
+
for i in sorted_beta_array:
|
|
427
|
+
if np_case[EAF_HT, i] >= np_case[CBF_HT, i]:
|
|
428
|
+
np_buckle_id = np.append(np_buckle_id, i)
|
|
429
|
+
np_ff_buckle = calc_friction_force_from_buckle(np_scen, np_case, i, "HT")
|
|
430
|
+
np_case[EAF_HT] = np.minimum(np_ff_buckle, np_case[EAF_HT])
|
|
431
|
+
|
|
432
|
+
# Step 3a: Set up the EAF OP Pressure profile with the buckle locations from HT
|
|
433
|
+
np_ff_buckle = calc_friction_force_from_buckle(np_scen, np_case, i, "OP")
|
|
434
|
+
np_case[EAF_P_OP] = np.minimum(np_ff_buckle, np_case[EAF_P_OP])
|
|
435
|
+
|
|
436
|
+
# Step 5a: Set up the EAF OP profile with the buckle locations from HT
|
|
437
|
+
np_case[EAF_OP] = np.minimum(np_ff_buckle, np_case[EAF_OP])
|
|
438
|
+
|
|
439
|
+
# Step 3b: Identify the location and order of additional potential buckles
|
|
440
|
+
# during OP (Pressure only)
|
|
441
|
+
np_beta = (np_case[CBF_OP] - np_case[EAF_INST]) / (np_scen[FRF_P_OP] - np_scen[RLT])
|
|
442
|
+
np_beta = np.around(np_beta, decimals = 6)
|
|
443
|
+
sorted_beta_array = np.argsort(np_beta, kind = "mergesort")
|
|
444
|
+
|
|
445
|
+
# Step 4: Compare the local driving force with the CBF during OP (pressure only) to identify
|
|
446
|
+
# actual buckles, taking into account the actual buckles from HT
|
|
447
|
+
for i in sorted_beta_array:
|
|
448
|
+
if np_case[EAF_P_OP, i] >= np_case[CBF_OP, i]:
|
|
449
|
+
np_buckle_id = np.append(np_buckle_id, i)
|
|
450
|
+
np_ff_buckle = calc_friction_force_from_buckle(np_scen, np_case, i, "OP")
|
|
451
|
+
np_case[EAF_P_OP] = np.minimum(np_ff_buckle, np_case[EAF_P_OP])
|
|
452
|
+
|
|
453
|
+
# Step 5a: Set up the EAF OP profile with the buckle locations from OP pressure only
|
|
454
|
+
np_case[EAF_OP]=np.minimum(np_ff_buckle, np_case[EAF_OP])
|
|
455
|
+
|
|
456
|
+
# Step 5b: Calculate Beta2 to identify the order and location of the potential buckles from the
|
|
457
|
+
# temperature in operation
|
|
458
|
+
# TODO: Explain in the manual that this calculation assumes linear temperature variations.
|
|
459
|
+
np_beta = (
|
|
460
|
+
np_case[CBF_OP] - np_case[EAF_INST] - (
|
|
461
|
+
np_scen[FRF_P_OP] - np_scen[RLT])) / np_scen[FRF_T_OP]
|
|
462
|
+
np_beta = np.around(np_beta, decimals = 6)
|
|
463
|
+
sorted_beta_array = np.argsort(np_beta, kind = "mergesort")
|
|
464
|
+
|
|
465
|
+
# Step 6: Compare the local driving force with the CBF (pressure + temperature) to find
|
|
466
|
+
# actual buckles
|
|
467
|
+
for i in sorted_beta_array:
|
|
468
|
+
if np_case[EAF_OP, i] >= np_case[CBF_OP, i]:
|
|
469
|
+
np_buckle_id = np.append(np_buckle_id, i)
|
|
470
|
+
np_ff_buckle = calc_friction_force_from_buckle(np_scen, np_case, i, "OP")
|
|
471
|
+
np_case[EAF_OP] = np.minimum(np_ff_buckle, np_case[EAF_OP])
|
|
472
|
+
|
|
473
|
+
# Extract the number of elements from the scenario array
|
|
474
|
+
n_elts = np_scen[KP].size
|
|
475
|
+
|
|
476
|
+
# Drop buckle elements duplicated between hydrotest and operation steps
|
|
477
|
+
# [can happen if the CBF < Buckle residual force]
|
|
478
|
+
np_buckle_id = np.unique(np_buckle_id)
|
|
479
|
+
|
|
480
|
+
# Initiate post-processing outputs array
|
|
481
|
+
np_pp_buckle = np.empty((np_buckle_id.size, 8))
|
|
482
|
+
vap_list = []
|
|
483
|
+
|
|
484
|
+
if len(np_buckle_id) > 0: # At least one buckle detected
|
|
485
|
+
for i_buckle in range(len(np_buckle_id)):
|
|
486
|
+
ielt_buckle = np.sort(np_buckle_id.astype(np.int64))[i_buckle]
|
|
487
|
+
|
|
488
|
+
# Identify possible VAP (surrounding buckling susceptibility areas)
|
|
489
|
+
np_ff_buckle = calc_friction_force_from_buckle(np_scen, np_case, ielt_buckle, "OP")
|
|
490
|
+
np_possible_vap_id = np.where(
|
|
491
|
+
np.isclose(np_case[EAF_OP], np_ff_buckle.astype(np.float64)) == False)[0]
|
|
492
|
+
|
|
493
|
+
# Add first and last elements to possible VAP for fixed end cases
|
|
494
|
+
if not (0 in np_possible_vap_id):
|
|
495
|
+
np_possible_vap_id = np.append(np_possible_vap_id, 0)
|
|
496
|
+
if not (n_elts in np_possible_vap_id):
|
|
497
|
+
np_possible_vap_id = np.append(np_possible_vap_id, n_elts)
|
|
498
|
+
np_possible_vap_id=np.sort(np_possible_vap_id)
|
|
499
|
+
|
|
500
|
+
# For each buckle, look for surrounding VAP and calculate KP
|
|
501
|
+
if ielt_buckle <= np.min(np_possible_vap_id):
|
|
502
|
+
ivap_left = ielt_buckle
|
|
503
|
+
else:
|
|
504
|
+
np_distance_left = np.absolute(
|
|
505
|
+
np_possible_vap_id[np_possible_vap_id < ielt_buckle]-ielt_buckle)
|
|
506
|
+
ivap_left = min(
|
|
507
|
+
ielt_buckle, np_possible_vap_id[
|
|
508
|
+
np_possible_vap_id < ielt_buckle][np_distance_left.argmin()] + 1)
|
|
509
|
+
|
|
510
|
+
if ielt_buckle >= np.max(np_possible_vap_id):
|
|
511
|
+
ivap_right = ielt_buckle
|
|
512
|
+
else:
|
|
513
|
+
np_distance_right = np.absolute(
|
|
514
|
+
np_possible_vap_id[np_possible_vap_id > ielt_buckle]-ielt_buckle)
|
|
515
|
+
ivap_right = max(
|
|
516
|
+
ielt_buckle, np_possible_vap_id[
|
|
517
|
+
np_possible_vap_id > ielt_buckle][np_distance_right.argmin()] - 1)
|
|
518
|
+
|
|
519
|
+
if ivap_left < ivap_right: # Buckle detected
|
|
520
|
+
# TODO: add switch to calculate KP of actual VAP instead of centroid of elements
|
|
521
|
+
# TODO: ivap_left and ivap_right where VAP are located
|
|
522
|
+
if ivap_left == 0:
|
|
523
|
+
kp_vap_left = np_scen[KP][ivap_left] - np_scen[LENGTH][ivap_left]
|
|
524
|
+
else:
|
|
525
|
+
kp_vap_left = np_scen[KP][ivap_left] - np_scen[LENGTH][ivap_left]
|
|
526
|
+
if ivap_right == (n_elts - 1):
|
|
527
|
+
kp_vap_right = np_scen[KP][ivap_right] + np_scen[LENGTH][ivap_right]
|
|
528
|
+
else:
|
|
529
|
+
kp_vap_right = np_scen[KP][ivap_right] + np_scen[LENGTH][ivap_right]
|
|
530
|
+
|
|
531
|
+
# Add new VAP to list if not already identified
|
|
532
|
+
temp_list = [ivap_left, kp_vap_left, np_case[EAF_OP][ivap_left]]
|
|
533
|
+
if temp_list not in vap_list:
|
|
534
|
+
vap_list.append(temp_list)
|
|
535
|
+
temp_list = [ivap_right, kp_vap_right, np_case[EAF_OP][ivap_right]]
|
|
536
|
+
if temp_list not in vap_list:
|
|
537
|
+
vap_list.append(temp_list)
|
|
538
|
+
else: # not really triggered buckle
|
|
539
|
+
kp_vap_right = np_scen[KP, ielt_buckle]
|
|
540
|
+
kp_vap_left = kp_vap_right
|
|
541
|
+
|
|
542
|
+
# Fill up the array of outputs for post-processing
|
|
543
|
+
np_pp_buckle[i_buckle, KP_PP] = np_scen[KP, ielt_buckle]
|
|
544
|
+
np_pp_buckle[i_buckle, ROUTE_TYPE_PP] = np_scen[ROUTE_TYPE, ielt_buckle]
|
|
545
|
+
np_pp_buckle[i_buckle, MUAX_PP] = np_case[MUAX, ielt_buckle]
|
|
546
|
+
np_pp_buckle[i_buckle, MULAT_OP_PP] = np_case[MULAT_OP, ielt_buckle]
|
|
547
|
+
np_pp_buckle[i_buckle, HOOS_PP] = np_case[HOOS, ielt_buckle]
|
|
548
|
+
np_pp_buckle[i_buckle, CBF_OP_PP] = np_case[CBF_OP, ielt_buckle]
|
|
549
|
+
np_pp_buckle[i_buckle, VAS_PP] = kp_vap_right - kp_vap_left
|
|
550
|
+
|
|
551
|
+
# End of condition on presence of buckle
|
|
552
|
+
vap_list = sorted(vap_list, key = lambda x: x[1])
|
|
553
|
+
|
|
554
|
+
return np_pp_buckle, np_case, vap_list
|
|
555
|
+
|
|
556
|
+
@jit(nopython=True)
|
|
557
|
+
def calc_friction_force_from_buckle(np_scen, np_case, ielt_buckle, phase_str):
|
|
558
|
+
|
|
559
|
+
"""
|
|
560
|
+
Calculate the effective axial frictional forces for each element in a scenario.
|
|
561
|
+
|
|
562
|
+
Parameters
|
|
563
|
+
----------
|
|
564
|
+
np_scen : numpy.ndarray
|
|
565
|
+
2D array containing scenario-specific data, where rows represent different parameters and
|
|
566
|
+
columns represent elements.
|
|
567
|
+
np_case : numpy.ndarray
|
|
568
|
+
2D array containing case-specific data, where rows represent different parameters and
|
|
569
|
+
columns represent elements.
|
|
570
|
+
ielt_buckle : int
|
|
571
|
+
Index of the buckle element.
|
|
572
|
+
phase_str : str
|
|
573
|
+
Phase label indicating whether the calculation is for "HT" (hydrotest) or
|
|
574
|
+
"OP" (operational) phase.
|
|
575
|
+
|
|
576
|
+
Returns
|
|
577
|
+
-------
|
|
578
|
+
np_ff_buckle : numpy.ndarray
|
|
579
|
+
1D array containing the computed friction forces for each element in the scenario.
|
|
580
|
+
|
|
581
|
+
"""
|
|
582
|
+
|
|
583
|
+
# Extract the number of elements from the scenario array
|
|
584
|
+
n_elts = np_scen[KP].size
|
|
585
|
+
|
|
586
|
+
if phase_str == "HT":
|
|
587
|
+
cbf = np_case[CBF_HT, ielt_buckle]
|
|
588
|
+
residual_buckle_force = np_scen[EAF_BUCKLE_HT, ielt_buckle]
|
|
589
|
+
residual_buckle_length = np_scen[L_BUCKLE_HT, ielt_buckle]
|
|
590
|
+
i_sw = SW_HT
|
|
591
|
+
i_ldeltaf = LDELTAF_HT
|
|
592
|
+
i_rdeltaf = RDELTAF_HT
|
|
593
|
+
|
|
594
|
+
elif phase_str == "OP":
|
|
595
|
+
cbf = np_case[CBF_OP, ielt_buckle]
|
|
596
|
+
residual_buckle_force = np_scen[EAF_BUCKLE_OP, ielt_buckle]
|
|
597
|
+
residual_buckle_length = np_scen[L_BUCKLE_OP, ielt_buckle]
|
|
598
|
+
i_sw = SW_OP
|
|
599
|
+
i_ldeltaf = LDELTAF_OP
|
|
600
|
+
i_rdeltaf = RDELTAF_OP
|
|
601
|
+
|
|
602
|
+
else:
|
|
603
|
+
print(f'Unrecognised phase label {phase_str}')
|
|
604
|
+
|
|
605
|
+
# The residual buckle force should be capped by the minimum CBF
|
|
606
|
+
residual_buckle_force = min(residual_buckle_force, cbf)
|
|
607
|
+
|
|
608
|
+
# Find the index of elements closer to "left" side of buckle
|
|
609
|
+
kp_flat_left = np_scen[KP, ielt_buckle] - residual_buckle_length / 2.0
|
|
610
|
+
np_distance_left = np.absolute(np_scen[KP] - kp_flat_left)
|
|
611
|
+
ielt_left = np_distance_left.argmin()
|
|
612
|
+
if np_scen[KP,ielt_left] > kp_flat_left:
|
|
613
|
+
ielt_left = max(0, ielt_left-1)
|
|
614
|
+
|
|
615
|
+
# Find the index of elements closer to "right" side of buckle
|
|
616
|
+
kp_flat_right = np_scen[KP, ielt_buckle] + residual_buckle_length / 2.0
|
|
617
|
+
np_distance_right = np.absolute(np_scen[KP] - kp_flat_right)
|
|
618
|
+
ielt_right = np_distance_right.argmin()
|
|
619
|
+
if np_scen[KP, ielt_right] < kp_flat_right:
|
|
620
|
+
ielt_right = min(ielt_right + 1, n_elts - 1)
|
|
621
|
+
|
|
622
|
+
# Calculate the incremental effective axial frictional forces
|
|
623
|
+
eaf_left_centroid = residual_buckle_force + np_case[MUAX, ielt_left] \
|
|
624
|
+
* np_scen[i_sw, ielt_left] * (kp_flat_left - np_scen[KP, ielt_left])
|
|
625
|
+
eaf_right_centroid = residual_buckle_force + np_case[MUAX, ielt_right] \
|
|
626
|
+
* np_scen[i_sw, ielt_right] * (np_scen[KP, ielt_right] - kp_flat_right)
|
|
627
|
+
|
|
628
|
+
# Compute rolling means for the left and right sections around the buckle
|
|
629
|
+
np_rolling_mean_left = np.append(np.zeros(ielt_right+1-1), eaf_right_centroid)
|
|
630
|
+
np_rolling_mean_left = np.append(np_rolling_mean_left, np_case[i_ldeltaf][(ielt_right+1):])
|
|
631
|
+
np_rolling_mean_right = np.append(np_case[i_rdeltaf][:ielt_left], eaf_left_centroid)
|
|
632
|
+
np_rolling_mean_right = np.append(np_rolling_mean_right, np.zeros(n_elts - (ielt_left+1)))
|
|
633
|
+
|
|
634
|
+
# Compute left and right cumulative sums of the effective axial forces for each element
|
|
635
|
+
np_lff_buckle = np.cumsum(np_rolling_mean_left)
|
|
636
|
+
np_rff_buckle = np.cumsum(np_rolling_mean_right[::-1])[::-1]
|
|
637
|
+
|
|
638
|
+
# Determine the maximum effective axial frictional force for each element
|
|
639
|
+
np_ff_buckle = np.maximum(np.maximum(np_lff_buckle,residual_buckle_force), np_rff_buckle)
|
|
640
|
+
|
|
641
|
+
return np_ff_buckle
|
|
642
|
+
|
|
643
|
+
def run_monte_carlo(n_worker, n_sim, np_distr, np_scen, np_ends, fric_sampling, bl_verbose):
|
|
644
|
+
|
|
645
|
+
"""
|
|
646
|
+
Set to run the Monte-Carlo simulations using multiple workers and gather the properties of
|
|
647
|
+
the buckles that have triggered.
|
|
648
|
+
|
|
649
|
+
Parameters
|
|
650
|
+
----------
|
|
651
|
+
n_worker : int
|
|
652
|
+
Number of worker processes spawned in the multiprocess.
|
|
653
|
+
n_sim : int
|
|
654
|
+
Number of Monte-Carlo simulations to be run.
|
|
655
|
+
np_distr: NumPy array
|
|
656
|
+
3-D numpy array containing the stochastic distributions
|
|
657
|
+
(dim 1: properties, dim 2: elements, dim 3: values).
|
|
658
|
+
np_scen : NumPy array
|
|
659
|
+
Numpy array containing the design data along the pipeline
|
|
660
|
+
route (mesh) that remains constant among deterministic and
|
|
661
|
+
Monte-Carlo simulations (except the stochastic distributions).
|
|
662
|
+
np_ends : NumPy array
|
|
663
|
+
Returns a numpy array with the definition of the tie-ins at
|
|
664
|
+
the pipeline ends.
|
|
665
|
+
fric_sampling : int
|
|
666
|
+
Switch to select the sampling method of the soil lateral friction
|
|
667
|
+
factor (0 for 'per Element' or 1 'per OOS Reference Length').
|
|
668
|
+
|
|
669
|
+
Returns
|
|
670
|
+
----------
|
|
671
|
+
list_buckle_prop : List[np.ndarray]
|
|
672
|
+
Array containing for each simulation the properties of
|
|
673
|
+
the buckle(s) that has(ve) triggered.
|
|
674
|
+
|
|
675
|
+
Other Parameters
|
|
676
|
+
----------------
|
|
677
|
+
bl_verbose : boolean, optional
|
|
678
|
+
True if intermediate printouts are required (False by default).
|
|
679
|
+
"""
|
|
680
|
+
|
|
681
|
+
mp_output = Queue()
|
|
682
|
+
processes = []
|
|
683
|
+
if bl_verbose:
|
|
684
|
+
start_time = time.time()
|
|
685
|
+
|
|
686
|
+
# Distribute simulations across worker processes
|
|
687
|
+
for i_worker in range(n_worker):
|
|
688
|
+
if i_worker < (n_worker - 1):
|
|
689
|
+
processes.append(Process(target=exec_worker_stack,
|
|
690
|
+
args=(int(i_worker*int(n_sim/n_worker)),
|
|
691
|
+
int((i_worker+1)*int(n_sim/n_worker)),
|
|
692
|
+
np_distr, np_scen, np_ends, fric_sampling, mp_output)))
|
|
693
|
+
else:
|
|
694
|
+
processes.append(Process(target=exec_worker_stack,
|
|
695
|
+
args=(int(i_worker*int(n_sim/n_worker)),
|
|
696
|
+
int(n_sim), np_distr, np_scen, np_ends, fric_sampling, mp_output)))
|
|
697
|
+
|
|
698
|
+
# Start worker processes
|
|
699
|
+
for p in processes:
|
|
700
|
+
p.start()
|
|
701
|
+
|
|
702
|
+
if bl_verbose:
|
|
703
|
+
print(f' Time taken to start the queue and {n_worker} worker process: {time.time() - start_time:.1f}s')
|
|
704
|
+
|
|
705
|
+
# Wait for output from worker processes
|
|
706
|
+
while mp_output.qsize() == 0:
|
|
707
|
+
time.sleep(1)
|
|
708
|
+
|
|
709
|
+
buckle_prop = []
|
|
710
|
+
|
|
711
|
+
# Collect buckle properties from the output queue
|
|
712
|
+
if bl_verbose:
|
|
713
|
+
n_sim_display_list = [10**i for i in range(1+round(np.log10(n_sim)))]
|
|
714
|
+
|
|
715
|
+
while mp_output:
|
|
716
|
+
try:
|
|
717
|
+
buckle_prop.append(mp_output.get(timeout=10))
|
|
718
|
+
except:
|
|
719
|
+
break
|
|
720
|
+
|
|
721
|
+
if bl_verbose:
|
|
722
|
+
for n_sim_display in n_sim_display_list:
|
|
723
|
+
if len(buckle_prop) >= n_sim_display:
|
|
724
|
+
print(f' Time taken to solve {n_sim_display:.0f} / {n_sim:.0f} simulations: {time.time() - start_time:.1f}s')
|
|
725
|
+
n_sim_display_list.remove(n_sim_display)
|
|
726
|
+
|
|
727
|
+
return buckle_prop
|
|
728
|
+
|
|
729
|
+
def exec_worker_stack(n_sim_start, n_sim_end, np_distr, np_scen, np_ends, fric_sampling, mp_output):
|
|
730
|
+
|
|
731
|
+
"""
|
|
732
|
+
Run a stack of random simulations using a single worker and add the results to the
|
|
733
|
+
post-processing queue mp_output.
|
|
734
|
+
|
|
735
|
+
Parameters
|
|
736
|
+
----------
|
|
737
|
+
n_sim_start : int
|
|
738
|
+
Number of the first simulation to be executed by the current worker.
|
|
739
|
+
n_sim_end : int
|
|
740
|
+
Number of the last simulation to be executed by the current worker (i.e., this simulation
|
|
741
|
+
number is not executed in this call to the function).
|
|
742
|
+
np_distr: NumPy array
|
|
743
|
+
3-D numpy array containing the stochastic distributions
|
|
744
|
+
(dim 1: properties, dim 2: elements, dim 3: values).
|
|
745
|
+
np_scen : NumPy array
|
|
746
|
+
Numpy array containing the design data along the pipeline route (mesh) that remains
|
|
747
|
+
constant among deterministic and Monte-Carlo simulations
|
|
748
|
+
(except the stochastic distributions).
|
|
749
|
+
np_ends : NumPy array
|
|
750
|
+
Returns a numpy array with the definition of the tie-ins at the pipeline ends.
|
|
751
|
+
fric_sampling : int
|
|
752
|
+
Switch to select the sampling method of the soil lateral friction factor
|
|
753
|
+
(0 for 'per Element' or 1 'per OOS Reference Length').
|
|
754
|
+
mp_output: Queue
|
|
755
|
+
Results are added to this Queue for subsequent post-processing.
|
|
756
|
+
"""
|
|
757
|
+
|
|
758
|
+
# Iterate over the range of simulations assigned to the worker
|
|
759
|
+
for i_sim in range(n_sim_start, n_sim_end):
|
|
760
|
+
|
|
761
|
+
# Sample randomness for the current simulation
|
|
762
|
+
np_prob_var = sample_randomness_case(fric_sampling, np_distr, np_scen)
|
|
763
|
+
|
|
764
|
+
# Preprocess the simulation case
|
|
765
|
+
np_case = preprocess_case(np_prob_var, np_scen, np_ends, bl_det = False)
|
|
766
|
+
|
|
767
|
+
# Solve the simulation case to find potential buckle properties
|
|
768
|
+
np_pp_buckle, junk1, junk2 = solve_case(np_scen, np_case)
|
|
769
|
+
|
|
770
|
+
# Get the number of buckles triggered in the simulation
|
|
771
|
+
n_buckle = np_pp_buckle.shape[0]
|
|
772
|
+
|
|
773
|
+
# If buckles triggered, adjust the simulation number of the buckle and add to the queue
|
|
774
|
+
if n_buckle > 0:
|
|
775
|
+
for i_buckle in range(n_buckle):
|
|
776
|
+
np_pp_buckle[i_buckle, SIM_PP] = i_sim
|
|
777
|
+
mp_output.put(np_pp_buckle)
|