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
|
@@ -0,0 +1,1305 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the post-processing functions of BuckPy.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import pandas.io.formats.excel
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from matplotlib.gridspec import GridSpec
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from openpyxl import load_workbook, writer
|
|
13
|
+
|
|
14
|
+
def pp_comb_prob(df_in, df_buckle, col_no, n_sim):
|
|
15
|
+
"""
|
|
16
|
+
Count the number of set combinations based on given set number
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
df_in : pandas DataFrame
|
|
21
|
+
DataFrame containing the set number of combination with buckles along the pipeline.
|
|
22
|
+
df_buckle : pandas DataFrame
|
|
23
|
+
DataFrame containing the count and probability of set number of combination with buckles.
|
|
24
|
+
col_no : String
|
|
25
|
+
Column name of the set number
|
|
26
|
+
n_sim : int
|
|
27
|
+
Number of simulations.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
df_out : pandas DataFrame
|
|
32
|
+
DataFrame containing post-processed statistics about the number of set combination
|
|
33
|
+
with buckles along the pipeline.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def pp_count_comb(row, df, col):
|
|
37
|
+
# Add 1 to the value each time there is a buckle at the current set
|
|
38
|
+
df.iloc[int(row.loc['isim']), int(row.loc[col])] += 1.0
|
|
39
|
+
|
|
40
|
+
# Row number is the total simulation number and column number is the total set number
|
|
41
|
+
n_col = df_in.unique().size
|
|
42
|
+
df_out = pd.DataFrame(0, index = np.arange(int(n_sim)),
|
|
43
|
+
columns = np.arange(int(n_col + 1.0)))
|
|
44
|
+
|
|
45
|
+
# Add 1 to the value in df_out each time there is a buckle
|
|
46
|
+
df_buckle.apply(lambda row: pp_count_comb(row, df_out, col_no), axis = 1)
|
|
47
|
+
|
|
48
|
+
# Delete the all 0 rows and the first column, and add prefix to column names
|
|
49
|
+
df_out = df_out[(df_out.T != 0).any()].iloc[:, 1:].add_prefix('Set_')
|
|
50
|
+
|
|
51
|
+
# Count the number of unique set combinations
|
|
52
|
+
col_list = df_out.columns.values.tolist()
|
|
53
|
+
df_out = df_out.groupby(col_list).size().reset_index().rename(
|
|
54
|
+
columns = {0: 'Number of Simulations'})
|
|
55
|
+
|
|
56
|
+
# Calculate probability and sort values in descending order based on count and reset index
|
|
57
|
+
df_out['Probability of Combination'] = df_out['Number of Simulations'] / n_sim
|
|
58
|
+
df_out = df_out.sort_values(
|
|
59
|
+
by = 'Number of Simulations', ascending = False).reset_index(drop = True)
|
|
60
|
+
|
|
61
|
+
return df_out
|
|
62
|
+
|
|
63
|
+
def pp_rename_columns(df_in, df_out):
|
|
64
|
+
"""
|
|
65
|
+
Rename columns in the post-processing DataFrame.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
df_in : pandas DataFrame
|
|
70
|
+
DataFrame containing the set number of combination with buckles along the pipeline.
|
|
71
|
+
df_out : pandas DataFrame
|
|
72
|
+
DataFrame containing post-processed statistics about the number of set combination
|
|
73
|
+
with buckles along the pipeline.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
df_out : pandas DataFrame
|
|
78
|
+
DataFrame containing post-processed statistics about the number of set combination
|
|
79
|
+
with buckles along the pipeline.
|
|
80
|
+
|
|
81
|
+
Notes
|
|
82
|
+
-----
|
|
83
|
+
Use the Python built-in ``set`` for unique labels, e.g., ``set(labels)``.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# Change column names from 'Set_1' to predefined names
|
|
87
|
+
new_col_list = np.array(df_in['col_name'].values).tolist()
|
|
88
|
+
df_out.columns = np.concatenate(
|
|
89
|
+
np.array([new_col_list, ['Number of Simulations', 'Probability of Combination']],
|
|
90
|
+
dtype = object)).tolist()
|
|
91
|
+
|
|
92
|
+
# Create new column name list sorted by KP values and reorder columns
|
|
93
|
+
df_out['Combination Id'] = df_out.index + 1
|
|
94
|
+
col_list = np.array(df_in.sort_values(by = 'index').loc[:, 'col_name'].values).tolist()
|
|
95
|
+
cols = np.concatenate(
|
|
96
|
+
np.array([['Combination Id', 'Number of Simulations', 'Probability of Combination'],
|
|
97
|
+
col_list], dtype = object)).tolist()
|
|
98
|
+
df_out = df_out[cols]
|
|
99
|
+
|
|
100
|
+
# Create a double header
|
|
101
|
+
header_first_line = [''] * 3 + ['Number of Buckles'] * (len(cols) - 3)
|
|
102
|
+
header_turples = list(zip(header_first_line, cols))
|
|
103
|
+
double_header = pd.MultiIndex.from_tuples(header_turples)
|
|
104
|
+
df_out.columns = double_header
|
|
105
|
+
|
|
106
|
+
return df_out
|
|
107
|
+
|
|
108
|
+
def pp_comb_buckles_per_set(df_pp, df_pp_set, n_sim):
|
|
109
|
+
"""
|
|
110
|
+
Count the number of set combinations and sort based on the most frequent set combinations
|
|
111
|
+
based on post-processing set.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
df_pp : pandas DataFrame
|
|
116
|
+
DataFrame containing pipeline element analysis results.
|
|
117
|
+
df_pp_set : pandas DataFrame
|
|
118
|
+
DataFrame containing the definition of the post-processed sets.
|
|
119
|
+
n_sim : int
|
|
120
|
+
Number of simulations.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
df_set_comb : pandas DataFrame
|
|
125
|
+
DataFrame containing post-processed statistics about the number of set combination
|
|
126
|
+
with buckles along the pipeline.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
# Create index columns for the original index and the sorted pp set value index
|
|
130
|
+
df_pp_set = df_pp_set[['pp_set', 'KP_from', 'KP_to']].sort_values(
|
|
131
|
+
by = ['pp_set', 'KP_from']).reset_index()
|
|
132
|
+
df_pp_set = df_pp_set.reset_index().rename(columns = {'level_0': 'index_sorted'})
|
|
133
|
+
|
|
134
|
+
# Select the number of simulation and post-precessing set number with a buckle
|
|
135
|
+
df_set_buckle_no = df_pp[['isim', 'pp_set']].sort_values(by = ['isim', 'pp_set'])
|
|
136
|
+
|
|
137
|
+
# Count the number of set combinations based on given set number
|
|
138
|
+
df_set_comb = pp_comb_prob(df_pp_set['pp_set'], df_set_buckle_no, 'pp_set', n_sim)
|
|
139
|
+
|
|
140
|
+
# Insert the extra column of duplicated set number into df_set_comb
|
|
141
|
+
df_duplicated = df_pp_set[df_pp_set.duplicated(subset = ['pp_set'])].reset_index(drop = True)
|
|
142
|
+
df_duplicated.apply(lambda row: df_set_comb.insert(
|
|
143
|
+
int(row['index_sorted']), f"Duplicate_{int(row['pp_set'])}",
|
|
144
|
+
df_set_comb.iloc[:, int(row['index_sorted'] - 1)]), axis = 1)
|
|
145
|
+
|
|
146
|
+
# Create new column name using KP from and KP to
|
|
147
|
+
df_pp_set[['KP_from', 'KP_to']] = df_pp_set[['KP_from', 'KP_to']].astype(int).astype(str)
|
|
148
|
+
df_pp_set['col_name'] = 'KP ' + df_pp_set['KP_from'] + ' to ' + df_pp_set['KP_to']
|
|
149
|
+
|
|
150
|
+
# Rename column names from 'Set_' to certain column names
|
|
151
|
+
df_set_comb = pp_rename_columns(df_pp_set, df_set_comb)
|
|
152
|
+
|
|
153
|
+
return df_set_comb
|
|
154
|
+
|
|
155
|
+
def pp_comb_buckles_per_section(df_pp, df_scen, n_sim):
|
|
156
|
+
"""
|
|
157
|
+
Count the number of set combinations and sort based on the most frequent set combinations
|
|
158
|
+
based on section number in the route data.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
df_pp : pandas DataFrame
|
|
163
|
+
DataFrame containing pipeline element analysis results.
|
|
164
|
+
df_scen : DataFrame
|
|
165
|
+
Dataframe containing the design data along the pipeline route (mesh) that remains
|
|
166
|
+
constant among deterministic and Monte-Carlo simulations.
|
|
167
|
+
n_sim : int
|
|
168
|
+
Number of simulations.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
df_set_comb : pandas DataFrame
|
|
173
|
+
DataFrame containing post-processed statistics about the number of set combination
|
|
174
|
+
with buckles along the pipeline.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def pp_section_no(kp, kp_list):
|
|
178
|
+
# Add the current KP to the kp list and sort it
|
|
179
|
+
kp_list = np.append(kp_list, kp)
|
|
180
|
+
kp_list.sort()
|
|
181
|
+
|
|
182
|
+
# Find the index of the current KP
|
|
183
|
+
section_no = np.where(kp_list == kp)[0][0]
|
|
184
|
+
|
|
185
|
+
return section_no
|
|
186
|
+
|
|
187
|
+
# Select the number of simulation and post-precessing KP number with a buckle
|
|
188
|
+
df_buckle_kp = df_pp[['isim', 'KP']].sort_values(by = ['isim', 'KP'])
|
|
189
|
+
|
|
190
|
+
# Use KP range to group KP into sections and rename columns
|
|
191
|
+
df_section = df_scen[['KP From', 'KP To', 'Point ID From', 'Point ID To']].drop_duplicates(
|
|
192
|
+
subset = ['KP From']).reset_index(drop = True)
|
|
193
|
+
df_section.columns = ['KP_from', 'KP_to', 'point_id_from', 'point_id_to']
|
|
194
|
+
|
|
195
|
+
# Find the unique KP value and create section number column in df_buckle_kp
|
|
196
|
+
df_kp = pd.DataFrame({'KP': df_buckle_kp['KP'].unique()})
|
|
197
|
+
df_kp['Section No'] = df_kp.apply(lambda row: pp_section_no(
|
|
198
|
+
row['KP'], df_section['KP_from'].unique()), axis = 1)
|
|
199
|
+
|
|
200
|
+
# Merge the Section Number column to df_buckle_kp
|
|
201
|
+
df_buckle_kp = pd.merge(df_buckle_kp, df_kp, on = 'KP', how = 'left')
|
|
202
|
+
|
|
203
|
+
# Count the number of set combinations based on given set number
|
|
204
|
+
df_set_comb = pp_comb_prob(df_section['KP_from'], df_buckle_kp, 'Section No', n_sim)
|
|
205
|
+
|
|
206
|
+
# Create new column name using Point ID
|
|
207
|
+
df_section = df_section.sort_values(by = 'KP_from').reset_index()
|
|
208
|
+
df_section['col_name'] = df_section['point_id_from'] + ' to ' + df_section['point_id_to']
|
|
209
|
+
|
|
210
|
+
# Rename column names from 'Set_' to certain column names
|
|
211
|
+
df_set_comb = pp_rename_columns(df_section, df_set_comb)
|
|
212
|
+
|
|
213
|
+
return df_set_comb
|
|
214
|
+
|
|
215
|
+
def pp_char_vas(df_pp, df_buckling, df_set):
|
|
216
|
+
"""
|
|
217
|
+
Determine the characteristic VAS.
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
df_pp : pandas DataFrame
|
|
222
|
+
DataFrame containing pipeline element analysis results.
|
|
223
|
+
df_buckling : pandas DataFrame
|
|
224
|
+
DataFrame containing buckling data.
|
|
225
|
+
df_set : pandas DataFrame
|
|
226
|
+
DataFrame containing sets along the pipeline route.
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
df_set : pandas DataFrame
|
|
231
|
+
Updated DataFrame containing characteristic VAS information.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
df_merged = pd.merge(df_pp, df_buckling, on='pp_set')
|
|
235
|
+
df_merged = df_merged.sort_values(by = ['pp_set', 'VAS_op'])
|
|
236
|
+
df_merged['VAS_op'] = df_merged['VAS_op'].round(1)
|
|
237
|
+
|
|
238
|
+
# Dataframe grouping the VAS in ascending order at each set along the pipeline route
|
|
239
|
+
df_char_vas = df_merged.groupby(by = ['pp_set', 'VAS_op', 'prob_buckling'], as_index = False) \
|
|
240
|
+
.agg(VAS_occurrence = ('VAS_op', 'count'), no_buckles = ('no_buckles', 'max'))
|
|
241
|
+
|
|
242
|
+
# Add the probability associated to the characteristic VAS
|
|
243
|
+
df_set_temp = df_set.copy().drop_duplicates(subset = 'pp_set', keep = 'first')
|
|
244
|
+
df_char_vas = df_char_vas.merge(df_set_temp[['pp_set', 'Characteristic VAS Probability']],
|
|
245
|
+
on = 'pp_set', how = 'inner')
|
|
246
|
+
|
|
247
|
+
# Cumulative distributions of the VAS (conditional and unconditional)
|
|
248
|
+
df_char_vas['VAS_prob_cond'] = df_char_vas['VAS_occurrence'] / df_char_vas['no_buckles']
|
|
249
|
+
df_char_vas['VAS_cumsum_prob_cond'] = df_char_vas[['pp_set', 'VAS_prob_cond']] \
|
|
250
|
+
.groupby(by = 'pp_set').cumsum()
|
|
251
|
+
|
|
252
|
+
# Lines below associate VAS=0 to cases not buckling
|
|
253
|
+
df_char_vas['VAS_cumsum_prob_uncond'] = (1.0 - df_char_vas['prob_buckling']) \
|
|
254
|
+
+ df_char_vas['VAS_cumsum_prob_cond'] * df_char_vas['prob_buckling']
|
|
255
|
+
|
|
256
|
+
# Complementary distributions of the VAS (conditional and unconditional)
|
|
257
|
+
df_char_vas['prob_exceedance_cond'] = 1.0 - df_char_vas['VAS_cumsum_prob_cond']
|
|
258
|
+
df_char_vas['prob_exceedance_uncond'] = 1.0 - df_char_vas['VAS_cumsum_prob_uncond']
|
|
259
|
+
|
|
260
|
+
# Difference bewteen the complementary distributions and target probabilities of excedance
|
|
261
|
+
df_char_vas['delta_prob_exceedance_cond'] = \
|
|
262
|
+
(df_char_vas['prob_exceedance_cond'] - \
|
|
263
|
+
df_char_vas['Characteristic VAS Probability']).abs()
|
|
264
|
+
df_char_vas['delta_prob_exceedance_uncond'] = \
|
|
265
|
+
(df_char_vas['prob_exceedance_uncond'] - \
|
|
266
|
+
df_char_vas['Characteristic VAS Probability']).abs()
|
|
267
|
+
|
|
268
|
+
# NumPy array with the rows containing the characteristic VAS of each pp_set
|
|
269
|
+
vas_cond_indices = df_char_vas.groupby(
|
|
270
|
+
by = 'pp_set')['delta_prob_exceedance_cond'].idxmin().to_numpy()
|
|
271
|
+
vas_uncond_indices = df_char_vas.groupby(
|
|
272
|
+
by = 'pp_set')['delta_prob_exceedance_uncond'].idxmin().to_numpy()
|
|
273
|
+
|
|
274
|
+
# Find conditional VAS by pp_set
|
|
275
|
+
df_vas_cond = df_char_vas.loc[vas_cond_indices, ['pp_set', 'VAS_op']]
|
|
276
|
+
df_vas_cond.rename(columns = {'VAS_op': 'VAS_charac_conditional'}, inplace = True)
|
|
277
|
+
|
|
278
|
+
# Find unconditional VAS by pp_set
|
|
279
|
+
df_vas_uncond = df_char_vas.loc[vas_uncond_indices, ['pp_set', 'VAS_op']]
|
|
280
|
+
df_vas_uncond.rename(columns = {'VAS_op': 'VAS_charac_unconditional'}, inplace = True)
|
|
281
|
+
|
|
282
|
+
# Assign conditional and unconditional VAS by pp_set
|
|
283
|
+
df_set = pd.merge(df_set, df_vas_cond, on = 'pp_set', how = 'outer')
|
|
284
|
+
df_set = pd.merge(df_set, df_vas_uncond, on = 'pp_set', how = 'outer')
|
|
285
|
+
df_set.loc[df_set['prob_buckling'] < df_set['Characteristic VAS Probability'],
|
|
286
|
+
'VAS_charac_unconditional'] = 0.0
|
|
287
|
+
|
|
288
|
+
return df_set
|
|
289
|
+
|
|
290
|
+
def pp_char_fric(df_pp, df_buckling, df_set, prob_exceed_char_fric):
|
|
291
|
+
"""
|
|
292
|
+
Determine the characteristic lateral breakout friction.
|
|
293
|
+
|
|
294
|
+
Parameters
|
|
295
|
+
----------
|
|
296
|
+
df_pp : pandas DataFrame
|
|
297
|
+
DataFrame containing pipeline element analysis results.
|
|
298
|
+
df_buckling : pandas DataFrame
|
|
299
|
+
DataFrame containing buckling data.
|
|
300
|
+
df_set : pandas DataFrame
|
|
301
|
+
DataFrame containing sets along the pipeline route.
|
|
302
|
+
prob_exceed_char_fric : float
|
|
303
|
+
Probability of exceeding characteristic lateral breakout friction.
|
|
304
|
+
|
|
305
|
+
Returns
|
|
306
|
+
-------
|
|
307
|
+
df_set : pandas DataFrame
|
|
308
|
+
Updated DataFrame containing characteristic lateral breakout friction information.
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
# Dataframe containing the list of frictions in ascending order at each set
|
|
312
|
+
df_merged = pd.merge(df_pp, df_buckling, on='pp_set')
|
|
313
|
+
df_merged = df_merged.sort_values(by = ['pp_set', 'mulat_op'])
|
|
314
|
+
|
|
315
|
+
# Dataframe grouping the frictions in ascending ordet at each set along the pipeline route
|
|
316
|
+
df_char_fric = df_merged.groupby(
|
|
317
|
+
by = ['pp_set', 'mulat_op', 'prob_buckling'], as_index = False) \
|
|
318
|
+
.agg(mulat_occurrence = ('mulat_op', 'count'), no_buckles = ('no_buckles', 'max'))
|
|
319
|
+
|
|
320
|
+
# Cumulative distributions of the friction (conditional and unconditional)
|
|
321
|
+
df_char_fric['mulat_prob_cond'] = df_char_fric['mulat_occurrence'] / df_char_fric['no_buckles']
|
|
322
|
+
df_char_fric['mulat_cumsum_prob_cond'] = df_char_fric[['pp_set', 'mulat_prob_cond']] \
|
|
323
|
+
.groupby(by = 'pp_set').cumsum()
|
|
324
|
+
|
|
325
|
+
# Lines below associate friction=0 to cases not buckling
|
|
326
|
+
df_char_fric['mulat_cumsum_prob_uncond'] = (1.0 - df_char_fric['prob_buckling']) \
|
|
327
|
+
+ df_char_fric['mulat_cumsum_prob_cond'] * df_char_fric['prob_buckling']
|
|
328
|
+
|
|
329
|
+
# Complementary distributions of the friction (conditional and unconditional)
|
|
330
|
+
df_char_fric['prob_exceedance_cond'] = 1.0 - df_char_fric['mulat_cumsum_prob_cond']
|
|
331
|
+
df_char_fric['prob_exceedance_uncond'] = 1.0 - df_char_fric['mulat_cumsum_prob_uncond']
|
|
332
|
+
|
|
333
|
+
# Difference between the complementary distributions and target probabilities of excedance
|
|
334
|
+
df_char_fric['delta_prob_exceedance_cond'] = (df_char_fric['prob_exceedance_cond']
|
|
335
|
+
- prob_exceed_char_fric).abs()
|
|
336
|
+
df_char_fric['delta_prob_exceedance_uncond'] = (df_char_fric['prob_exceedance_uncond']
|
|
337
|
+
- prob_exceed_char_fric).abs()
|
|
338
|
+
|
|
339
|
+
# NumPy array with the rows containing the characteristic friction of each pp_set
|
|
340
|
+
indices_mulat_cond = df_char_fric.groupby(by = 'pp_set')['delta_prob_exceedance_cond'] \
|
|
341
|
+
.idxmin().to_numpy()
|
|
342
|
+
indices_mulat_uncond = df_char_fric.groupby(by = 'pp_set')['delta_prob_exceedance_uncond'] \
|
|
343
|
+
.idxmin().to_numpy()
|
|
344
|
+
|
|
345
|
+
# Find conditional friction by pp_set
|
|
346
|
+
df_fric_cond = df_char_fric.loc[indices_mulat_cond, ['pp_set', 'prob_buckling', 'mulat_op']]
|
|
347
|
+
df_fric_cond.rename(columns = {'mulat_op': 'mulat_charac_conditional'}, inplace = True)
|
|
348
|
+
|
|
349
|
+
# Find unconditional friction by pp_set
|
|
350
|
+
df_fric_uncond = df_char_fric.loc[indices_mulat_uncond, ['pp_set', 'prob_buckling', 'mulat_op']]
|
|
351
|
+
df_fric_uncond.rename(columns = {'mulat_op': 'mulat_charac_unconditional'}, inplace = True)
|
|
352
|
+
|
|
353
|
+
# Assign conditional and unconditional friction by pp_set
|
|
354
|
+
df_set = pd.merge(df_set, df_fric_cond, on = 'pp_set', how = 'outer')
|
|
355
|
+
df_set = pd.merge(df_set, df_fric_uncond, on = 'pp_set', how = 'outer')
|
|
356
|
+
df_set.loc[df_set['prob_buckling'] < prob_exceed_char_fric,
|
|
357
|
+
'mulat_charac_unconditional'] = 0.0
|
|
358
|
+
|
|
359
|
+
return df_set
|
|
360
|
+
|
|
361
|
+
def pp_elem(df_pp, n_sim):
|
|
362
|
+
"""
|
|
363
|
+
Perform post-processing of the probability of buckling, VAS and lateral breakout
|
|
364
|
+
friction at each element along the pipeline route.
|
|
365
|
+
|
|
366
|
+
Parameters
|
|
367
|
+
----------
|
|
368
|
+
df_pp : pandas DataFrame
|
|
369
|
+
DataFrame containing the results of the analyses.
|
|
370
|
+
n_sim : int
|
|
371
|
+
Total number of simulations.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
df_elem : pandas DataFrame
|
|
376
|
+
DataFrame containing post-processed probabilities, VAS and lateral breakout friction
|
|
377
|
+
for each pipeline element.
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
# Probability of buckling at each element along the pipeline route
|
|
381
|
+
df_buckling = df_pp[['KP', 'isim']].groupby('KP', as_index = False).agg(
|
|
382
|
+
no_buckles = ('isim', 'nunique'))
|
|
383
|
+
df_buckling['prob_buckling'] = df_buckling['no_buckles'] / n_sim
|
|
384
|
+
df_buckling['prob_not_buckling'] = 1.0 - df_buckling['prob_buckling']
|
|
385
|
+
|
|
386
|
+
# VAS at each element along the pipeline route
|
|
387
|
+
df_vas = df_pp[['KP', 'VAS_op']].groupby('KP', as_index = False).agg(
|
|
388
|
+
VAS_mean = ('VAS_op', 'mean'), VAS_std = ('VAS_op', 'std'),
|
|
389
|
+
VAS_min = ('VAS_op', 'min'), VAS_max = ('VAS_op', 'max'))
|
|
390
|
+
|
|
391
|
+
# Lateral breakout friction at each element along the pipeline route
|
|
392
|
+
df_friction = df_pp[['KP', 'mulat_op']].groupby('KP', as_index = False).agg(
|
|
393
|
+
mulat_mean = ('mulat_op', 'mean'), mulat_std = ('mulat_op', 'std'),
|
|
394
|
+
mulat_min = ('mulat_op', 'min'), mulat_max = ('mulat_op', 'max'))
|
|
395
|
+
|
|
396
|
+
# Merge df_buckling and df_vas on 'KP'
|
|
397
|
+
df_elem = pd.merge(df_buckling, df_vas, on = 'KP')
|
|
398
|
+
|
|
399
|
+
# Merge merged_df and df_friction on 'KP'
|
|
400
|
+
df_elem = pd.merge(df_elem, df_friction, on = 'KP')
|
|
401
|
+
|
|
402
|
+
# Change labels for print-out
|
|
403
|
+
df_elem = df_elem.rename(columns = {
|
|
404
|
+
'KP': 'Centroid of the Element (m)',
|
|
405
|
+
'no_buckles': 'Number of Simulations with a Buckle',
|
|
406
|
+
'prob_buckling': 'Probability of Buckling',
|
|
407
|
+
'prob_not_buckling': 'Probability of not Buckling',
|
|
408
|
+
'VAS_mean': 'Mean of the VAS (m)',
|
|
409
|
+
'VAS_std': 'Standard Deviation of the VAS (m)',
|
|
410
|
+
'VAS_min': 'Minimum VAS (m)',
|
|
411
|
+
'VAS_max': 'Maximum VAS (m)',
|
|
412
|
+
'mulat_mean': 'Mean of the Lateral Breakout Friction',
|
|
413
|
+
'mulat_std': 'Standard Deviation of the Lateral Breakout Friction',
|
|
414
|
+
'mulat_min': 'Minimum Lateral Breakout Friction',
|
|
415
|
+
'mulat_max': 'Maximum Lateral Breakout Friction'})
|
|
416
|
+
|
|
417
|
+
df_elem = df_elem.fillna(0.0)
|
|
418
|
+
|
|
419
|
+
return df_elem
|
|
420
|
+
|
|
421
|
+
def pp_no_buckles(df_pp, n_sim):
|
|
422
|
+
"""
|
|
423
|
+
Perform post-processing of the number of buckles along the pipeline.
|
|
424
|
+
|
|
425
|
+
Parameters
|
|
426
|
+
----------
|
|
427
|
+
df_pp : pandas DataFrame
|
|
428
|
+
DataFrame containing pipeline element analysis results.
|
|
429
|
+
n_sim : int
|
|
430
|
+
Total number of simulations.
|
|
431
|
+
|
|
432
|
+
Returns
|
|
433
|
+
-------
|
|
434
|
+
df_no_buckles : pandas DataFrame
|
|
435
|
+
DataFrame containing post-processed statistics about the number of buckles
|
|
436
|
+
along the pipeline.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
# Number of buckles per simulation
|
|
440
|
+
df_grouped = df_pp[['isim', 'KP']].groupby('isim', as_index = False).agg(
|
|
441
|
+
no_buckles = ('KP', 'count'))
|
|
442
|
+
|
|
443
|
+
# Number of simulations as a function of the number of buckles along the pipeline
|
|
444
|
+
df_no_buckles = df_grouped.pivot_table(columns = ['no_buckles'], aggfunc = 'size')
|
|
445
|
+
df_no_buckles = df_no_buckles.reset_index()
|
|
446
|
+
df_no_buckles = df_no_buckles.rename(columns={
|
|
447
|
+
'n_buckle': 'Total Number of Buckles', 0: 'Occurrence'})
|
|
448
|
+
|
|
449
|
+
# Accounting for cases without buckle in cumsum
|
|
450
|
+
new_row = {'no_buckles': 0, 'Occurrence': n_sim - df_no_buckles['Occurrence'].sum()}
|
|
451
|
+
df_no_buckles = pd.concat([df_no_buckles, pd.DataFrame(new_row, index=[0])], ignore_index=True)
|
|
452
|
+
df_no_buckles = df_no_buckles.sort_values(by = ['no_buckles']).reset_index(drop=True)
|
|
453
|
+
|
|
454
|
+
# Distribution of the expected number of buckles along the pipeline
|
|
455
|
+
df_no_buckles['Probability'] = df_no_buckles['Occurrence'] / n_sim
|
|
456
|
+
df_no_buckles['Cumulative Probability'] = df_no_buckles['Probability'].cumsum()
|
|
457
|
+
|
|
458
|
+
# Change labels for print-out
|
|
459
|
+
df_no_buckles = df_no_buckles.rename(columns = {
|
|
460
|
+
'no_buckles': 'Number of Buckles',
|
|
461
|
+
'Occurrence': 'Number of Simulations',
|
|
462
|
+
'Probability': 'Probability of Buckling',
|
|
463
|
+
'Cumulative Probability': 'Cumulative Probability of Buckling'})
|
|
464
|
+
|
|
465
|
+
return df_no_buckles
|
|
466
|
+
|
|
467
|
+
def pp_sets(df_pp, n_sim, prob_exceed_char_fric, df_pp_set, df_scen):
|
|
468
|
+
"""
|
|
469
|
+
Perform post-processing of the probability of buckling, VAS and lateral breakout
|
|
470
|
+
friction at each post-processing set along the pipeline route.
|
|
471
|
+
|
|
472
|
+
Parameters
|
|
473
|
+
----------
|
|
474
|
+
df_pp : pandas DataFrame
|
|
475
|
+
DataFrame containing pipeline element analysis results.
|
|
476
|
+
n_sim : int
|
|
477
|
+
Total number of simulations.
|
|
478
|
+
prob_exceed_char_fric : float
|
|
479
|
+
Probability of exceedance of the characteristic lateral breakout friction.
|
|
480
|
+
df_pp_set : DataFrame
|
|
481
|
+
Definition of element sets for post-processing outputs.
|
|
482
|
+
df_scen : DataFrame
|
|
483
|
+
Dataframe containing the design data along the pipeline
|
|
484
|
+
route (mesh) that remains constant among deterministic and
|
|
485
|
+
Monte-Carlo simulations.
|
|
486
|
+
|
|
487
|
+
Returns
|
|
488
|
+
-------
|
|
489
|
+
df_set : pandas DataFrame
|
|
490
|
+
DataFrame containing post-processed statistics about pipeline sets.
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
# Probability of buckling at each set along the pipeline route
|
|
494
|
+
df_pp_set = df_pp_set[['pp_set', 'KP_from', 'KP_to', 'Characteristic VAS Probability']]
|
|
495
|
+
|
|
496
|
+
# Probability of buckling at each set along the pipeline route
|
|
497
|
+
df_buckling = df_pp[['pp_set', 'KP_from', 'KP_to', 'isim', 'VAS_op']].groupby(
|
|
498
|
+
'pp_set', as_index = False).agg(
|
|
499
|
+
no_simulations_with_buckles = ('isim', 'nunique'), no_buckles = ('VAS_op', 'count'))
|
|
500
|
+
df_buckling['prob_buckling'] = df_buckling['no_simulations_with_buckles'] / n_sim
|
|
501
|
+
df_buckling['prob_not_buckling'] = 1.0 - df_buckling['prob_buckling']
|
|
502
|
+
|
|
503
|
+
# VAS at each set along the pipeline route
|
|
504
|
+
df_vas = df_pp[['pp_set', 'VAS_op']].groupby('pp_set', as_index = False).agg(
|
|
505
|
+
VAS_mean = ('VAS_op', 'mean'), VAS_std = ('VAS_op', 'std'),
|
|
506
|
+
VAS_min = ('VAS_op', 'min'), VAS_max = ('VAS_op', 'max'))
|
|
507
|
+
|
|
508
|
+
# Lateral breakout friction at each set along the pipeline route
|
|
509
|
+
df_friction = df_pp[['pp_set', 'mulat_op']].groupby('pp_set', as_index = False).agg(
|
|
510
|
+
mulat_mean = ('mulat_op', 'mean'), mulat_std = ('mulat_op', 'std'),
|
|
511
|
+
mulat_min = ('mulat_op', 'min'), mulat_max = ('mulat_op', 'max'))
|
|
512
|
+
|
|
513
|
+
# Merge df_buckling and df_vas on 'pp_set'
|
|
514
|
+
df_set = pd.merge(df_pp_set, df_buckling, on = 'pp_set', how = 'outer')
|
|
515
|
+
|
|
516
|
+
# Merge df_buckling and df_vas on 'pp_set'
|
|
517
|
+
df_set = pd.merge(df_set, df_vas, on = 'pp_set', how = 'outer')
|
|
518
|
+
df_set['VAS_mean'] = df_set['VAS_mean'].fillna(0.0)
|
|
519
|
+
df_set['VAS_std'] = df_set['VAS_std'].fillna(0.0)
|
|
520
|
+
df_set['VAS_min'] = df_set['VAS_min'].fillna(0.0)
|
|
521
|
+
df_set['VAS_max'] = df_set['VAS_max'].fillna(0.0)
|
|
522
|
+
|
|
523
|
+
# Determine characteristic VAS
|
|
524
|
+
df_set = pp_char_vas(df_pp, df_buckling, df_set)
|
|
525
|
+
|
|
526
|
+
# Merge merged_df and df_friction on 'pp_set' and determine characteristic friction
|
|
527
|
+
df_set = pd.merge(df_set, df_friction, on = 'pp_set', how = 'outer')
|
|
528
|
+
|
|
529
|
+
# Determine characteristic lateral breakout friction
|
|
530
|
+
df_set = pp_char_fric(df_pp, df_buckling, df_set, prob_exceed_char_fric)
|
|
531
|
+
|
|
532
|
+
# Change labels for print-out
|
|
533
|
+
df_set = df_set.rename(columns = {
|
|
534
|
+
'pp_set': 'Set Label',
|
|
535
|
+
'KP_from': 'KP From (m)',
|
|
536
|
+
'KP_to': 'KP To (m)',
|
|
537
|
+
'no_simulations_with_buckles': 'Number of Simulations with Buckles per Set',
|
|
538
|
+
'no_buckles': 'Number of Buckles per Set',
|
|
539
|
+
'prob_buckling': 'Probability of Buckling',
|
|
540
|
+
'prob_not_buckling': 'Probability of not Buckling',
|
|
541
|
+
'VAS_mean': 'Mean of the VAS (m)',
|
|
542
|
+
'VAS_std': 'Standard Deviation of the VAS (m)',
|
|
543
|
+
'VAS_min': 'Minimum VAS (m)',
|
|
544
|
+
'VAS_max': 'Maximum VAS (m)',
|
|
545
|
+
'VAS_charac_conditional': 'Characteristic VAS, Conditional (m)',
|
|
546
|
+
'VAS_charac_unconditional': 'Characteristic VAS, Unconditional (m)',
|
|
547
|
+
'mulat_mean': 'Mean of the Lateral Breakout Friction',
|
|
548
|
+
'mulat_std': 'Standard Deviation of the Lateral Breakout Friction',
|
|
549
|
+
'mulat_min': 'Minimum Lateral Breakout Friction',
|
|
550
|
+
'mulat_max': 'Maximum Lateral Breakout Friction',
|
|
551
|
+
'mulat_charac_unconditional': 'Characteristic Lateral Breakout Friction, Buckles'})
|
|
552
|
+
|
|
553
|
+
# Drop column for print-out
|
|
554
|
+
df_set = df_set.drop(columns = 'mulat_charac_conditional')
|
|
555
|
+
|
|
556
|
+
# Sort by KP From
|
|
557
|
+
df_set = df_set.sort_values(by = 'KP From (m)')
|
|
558
|
+
|
|
559
|
+
# Fill characteristic frictions at planned buckles with zero
|
|
560
|
+
df_set['Characteristic Lateral Breakout Friction Probability'] = \
|
|
561
|
+
prob_exceed_char_fric
|
|
562
|
+
df_set.loc[df_set['Characteristic Lateral Breakout Friction, Buckles'] == 0.0,
|
|
563
|
+
'Characteristic Lateral Breakout Friction Probability'] = 0.0
|
|
564
|
+
|
|
565
|
+
# Define HE of the geotechnical friction
|
|
566
|
+
df_scen['Lateral Breakout Friction, HE, Geotech'] = \
|
|
567
|
+
df_scen.apply(lambda x: np.interp(1.0 - prob_exceed_char_fric,
|
|
568
|
+
x['mul OP CDF Array'],
|
|
569
|
+
x['mul OP Array']), axis = 1)
|
|
570
|
+
df_set['Lateral Breakout Friction, HE, Geotech'] = \
|
|
571
|
+
df_set.apply(lambda x: np.interp(x['KP From (m)'],
|
|
572
|
+
df_scen['KP'],
|
|
573
|
+
df_scen['Lateral Breakout Friction, HE, Geotech']),
|
|
574
|
+
axis = 1)
|
|
575
|
+
|
|
576
|
+
# Convert route type strings to descriptive representation
|
|
577
|
+
df_scen_temp = df_scen.copy()
|
|
578
|
+
|
|
579
|
+
df_scen_temp.loc[df_scen_temp['Route Type'] == 1, 'Route'] = 'Straight'
|
|
580
|
+
df_scen_temp.loc[df_scen_temp['Route Type'] == 2, 'Route'] = 'Bend'
|
|
581
|
+
df_scen_temp.loc[df_scen_temp['Route Type'] == 3, 'Route'] = 'Sleeper'
|
|
582
|
+
df_scen_temp.loc[df_scen_temp['Route Type'] == 4, 'Route'] = 'RCM'
|
|
583
|
+
|
|
584
|
+
# Assign route type to df_set
|
|
585
|
+
for index, row in df_set.iterrows():
|
|
586
|
+
df_set.loc[index, 'Route'] = df_scen_temp.loc[
|
|
587
|
+
(df_scen_temp['KP'] > row['KP From (m)']) &
|
|
588
|
+
(df_scen_temp['KP'] < row['KP To (m)']),
|
|
589
|
+
'Route'].values[0]
|
|
590
|
+
|
|
591
|
+
df_set.loc[(df_set['Route'] == 'Sleeper') | (df_set['Route'] == 'RCM'),
|
|
592
|
+
'Characteristic Lateral Breakout Friction, Buckles'] = 0.0
|
|
593
|
+
|
|
594
|
+
# Re-arrange columns
|
|
595
|
+
df_set = df_set[['Set Label', 'KP From (m)', 'KP To (m)',
|
|
596
|
+
'Number of Simulations with Buckles per Set',
|
|
597
|
+
'Number of Buckles per Set',
|
|
598
|
+
'Probability of Buckling',
|
|
599
|
+
'Probability of not Buckling',
|
|
600
|
+
'Mean of the VAS (m)', 'Standard Deviation of the VAS (m)',
|
|
601
|
+
'Minimum VAS (m)', 'Maximum VAS (m)',
|
|
602
|
+
'Characteristic VAS Probability',
|
|
603
|
+
'Characteristic VAS, Conditional (m)',
|
|
604
|
+
'Characteristic VAS, Unconditional (m)',
|
|
605
|
+
'Mean of the Lateral Breakout Friction',
|
|
606
|
+
'Standard Deviation of the Lateral Breakout Friction',
|
|
607
|
+
'Minimum Lateral Breakout Friction',
|
|
608
|
+
'Maximum Lateral Breakout Friction',
|
|
609
|
+
'Characteristic Lateral Breakout Friction Probability',
|
|
610
|
+
'Characteristic Lateral Breakout Friction, Buckles',
|
|
611
|
+
'Lateral Breakout Friction, HE, Geotech']]
|
|
612
|
+
|
|
613
|
+
df_set = df_set.fillna(0.0)
|
|
614
|
+
df_set['Probability of not Buckling'] = 1.0 - df_set['Probability of Buckling']
|
|
615
|
+
|
|
616
|
+
return df_set
|
|
617
|
+
|
|
618
|
+
def pp_eaf(df_pp_plot):
|
|
619
|
+
"""
|
|
620
|
+
Converts units and renames columns for pipeline EAF plot DataFrame.
|
|
621
|
+
|
|
622
|
+
Parameters
|
|
623
|
+
----------
|
|
624
|
+
df_pp_plot : pandas DataFrame
|
|
625
|
+
DataFrame containing pipeline plot data.
|
|
626
|
+
|
|
627
|
+
Returns
|
|
628
|
+
-------
|
|
629
|
+
df_pp_plot: pandas DataFrame
|
|
630
|
+
DataFrame with converted units and renamed columns.
|
|
631
|
+
"""
|
|
632
|
+
|
|
633
|
+
# Convert the units of 'df_pp_plot' (N to kN)
|
|
634
|
+
df_pp_plot[['CBF_ht', 'CBF_op', 'EAF_inst', 'EAF_ht',
|
|
635
|
+
'EAF_p_op', 'EAF_op', 'EAF_op_unbuck']] /= 1000.0
|
|
636
|
+
|
|
637
|
+
# Change labels for print-out
|
|
638
|
+
df_pp_plot = df_pp_plot.rename(columns = {
|
|
639
|
+
'KP': 'KP (m)',
|
|
640
|
+
'CBF_ht': 'CBF Hydrotest (kN)',
|
|
641
|
+
'CBF_op': 'CBF Operation (kN)',
|
|
642
|
+
'EAF_inst': 'EAF Installation [RLT] (kN)',
|
|
643
|
+
'EAF_ht': 'EAF Hydrotest (kN)',
|
|
644
|
+
'EAF_p_op': 'EAF Operation [Pressure Only] (kN)',
|
|
645
|
+
'EAF_op': 'EAF Operation (kN)',
|
|
646
|
+
'EAF_op_unbuck': 'EAF Operation [without Buckling] (kN)'
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
# Drop column for print-out
|
|
650
|
+
df_pp_plot = df_pp_plot.drop(columns = 'beta2')
|
|
651
|
+
|
|
652
|
+
return df_pp_plot
|
|
653
|
+
|
|
654
|
+
def pp_raw(df):
|
|
655
|
+
"""
|
|
656
|
+
Converts units and renames columns of the DataFrame containing the raw data
|
|
657
|
+
from the BuckPy simulations.
|
|
658
|
+
|
|
659
|
+
Parameters
|
|
660
|
+
----------
|
|
661
|
+
df : pandas DataFrame
|
|
662
|
+
DataFrame containing raw data from the BuckPy simulations.
|
|
663
|
+
|
|
664
|
+
Returns
|
|
665
|
+
-------
|
|
666
|
+
df : pandas DataFrame
|
|
667
|
+
DataFrame with converted units and renamed columns.
|
|
668
|
+
"""
|
|
669
|
+
|
|
670
|
+
# Change labels for print-out
|
|
671
|
+
df = df.rename(columns = {
|
|
672
|
+
'isim': 'Simulation Number',
|
|
673
|
+
'KP': 'KP (m)',
|
|
674
|
+
'route_type': 'Section Type',
|
|
675
|
+
'muax': 'Axial Residual Friction Factor, Operation',
|
|
676
|
+
'mulat_op': 'Lateral Breakout Friction Factor, Operation',
|
|
677
|
+
'HOOS': 'HOOS Factor',
|
|
678
|
+
'CBF_op': 'CBF Operation (kN)',
|
|
679
|
+
'VAS_op': 'VAS Operation (m)'
|
|
680
|
+
})
|
|
681
|
+
|
|
682
|
+
# Convert units of the CBF (N to kN)
|
|
683
|
+
df['CBF Operation (kN)'] /= 1000.0
|
|
684
|
+
|
|
685
|
+
# Rename section types
|
|
686
|
+
df['Section Type'] = df['Section Type'].astype(object)
|
|
687
|
+
df.loc[df['Section Type'] == 1, 'Section Type'] = 'Straight'
|
|
688
|
+
df.loc[df['Section Type'] == 2, 'Section Type'] = 'Bend'
|
|
689
|
+
df.loc[df['Section Type'] == 3, 'Section Type'] = 'Sleeper'
|
|
690
|
+
df.loc[df['Section Type'] == 4, 'Section Type'] = 'RCM'
|
|
691
|
+
|
|
692
|
+
# Select the first 10000 rows to optimise the size of the Excel file
|
|
693
|
+
#TODO: why? if Excel is limited, let's export it to something else as it could be useful to have all case for separate post-processing
|
|
694
|
+
df = df.iloc[:10000]
|
|
695
|
+
|
|
696
|
+
return df
|
|
697
|
+
|
|
698
|
+
def pp_save(output_combination, output_file_name, *args):
|
|
699
|
+
"""
|
|
700
|
+
Saves DataFrames to an Excel file with specified formatting.
|
|
701
|
+
|
|
702
|
+
Parameters
|
|
703
|
+
----------
|
|
704
|
+
output_combination : Boolean
|
|
705
|
+
Switch to write the most frequent combination set of buckles in the result file.
|
|
706
|
+
output_file_name : str
|
|
707
|
+
Name of the output Excel file.
|
|
708
|
+
df_route : pandas DataFrame
|
|
709
|
+
DataFrame containing route data.
|
|
710
|
+
df_elem : pandas DataFrame
|
|
711
|
+
DataFrame containing element data.
|
|
712
|
+
df_sets : pandas DataFrame
|
|
713
|
+
DataFrame containing set data.
|
|
714
|
+
df_no_buckles : pandas DataFrame
|
|
715
|
+
DataFrame containing data related to the number of buckles.
|
|
716
|
+
df_pp_plot : pandas DataFrame
|
|
717
|
+
DataFrame containing force profile data.
|
|
718
|
+
df_pp_buckle_prop : pandas DataFrame
|
|
719
|
+
DataFrame containing raw data related to buckling properties.
|
|
720
|
+
df_comb_per_set : pandas DataFrame
|
|
721
|
+
DataFrame containing raw data related to KP set combinations based on post-processing set.
|
|
722
|
+
df_comb_per_section : pandas DataFrame
|
|
723
|
+
DataFrame containing raw data related to KP set combinations based on route point id.
|
|
724
|
+
|
|
725
|
+
Returns
|
|
726
|
+
-------
|
|
727
|
+
None
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
# Unpack DataFrames from args based on the output_combination flag
|
|
731
|
+
if output_combination:
|
|
732
|
+
df_route, df_elem, df_sets, df_no_buckles, df_pp_plot, df_pp_buckle_prop,\
|
|
733
|
+
df_comb_per_set, df_comb_per_section = args
|
|
734
|
+
else:
|
|
735
|
+
df_route, df_elem, df_sets, df_no_buckles, df_pp_plot, df_pp_buckle_prop = args
|
|
736
|
+
|
|
737
|
+
writer = pd.ExcelWriter(output_file_name)
|
|
738
|
+
pandas.io.formats.excel.ExcelFormatter.header_style = None
|
|
739
|
+
|
|
740
|
+
# Convert DataFrames to Excel objects
|
|
741
|
+
df_route.to_excel(
|
|
742
|
+
writer, sheet_name = 'Route', index = False, startrow = 1, header = False
|
|
743
|
+
)
|
|
744
|
+
df_elem.to_excel(
|
|
745
|
+
writer, sheet_name = 'Elements', index = False, startrow = 1, header = False
|
|
746
|
+
)
|
|
747
|
+
df_sets.to_excel(
|
|
748
|
+
writer, sheet_name = 'Sets', index = False, startrow = 1, header = False
|
|
749
|
+
)
|
|
750
|
+
df_no_buckles.to_excel(
|
|
751
|
+
writer, sheet_name = 'No Buckles', index = False, startrow = 1, header = False
|
|
752
|
+
)
|
|
753
|
+
df_pp_plot.to_excel(
|
|
754
|
+
writer, sheet_name = 'Force Profiles', index = False, startrow = 1, header = False
|
|
755
|
+
)
|
|
756
|
+
df_pp_buckle_prop.to_excel(
|
|
757
|
+
writer, sheet_name = 'Raw Data', index = False, startrow = 1, header = False
|
|
758
|
+
)
|
|
759
|
+
|
|
760
|
+
if output_combination:
|
|
761
|
+
df_comb_per_set.to_excel(
|
|
762
|
+
writer, sheet_name = 'Comb Buckles per Set', startrow = 1, header = False
|
|
763
|
+
)
|
|
764
|
+
df_comb_per_section.to_excel(
|
|
765
|
+
writer, sheet_name = 'Comb Buckles per Section', startrow = 1, header = False
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
# Get the workbook and worksheet objects.
|
|
769
|
+
workbook = writer.book
|
|
770
|
+
worksheet0 = writer.sheets['Route']
|
|
771
|
+
worksheet1 = writer.sheets['Elements']
|
|
772
|
+
worksheet2 = writer.sheets['Sets']
|
|
773
|
+
worksheet3 = writer.sheets['No Buckles']
|
|
774
|
+
worksheet4 = writer.sheets['Force Profiles']
|
|
775
|
+
worksheet5 = writer.sheets['Raw Data']
|
|
776
|
+
|
|
777
|
+
if output_combination:
|
|
778
|
+
worksheet6 = writer.sheets['Comb Buckles per Set']
|
|
779
|
+
worksheet7 = writer.sheets['Comb Buckles per Section']
|
|
780
|
+
|
|
781
|
+
# Add generic cell formats to Excel file
|
|
782
|
+
formatc1 = workbook.add_format({
|
|
783
|
+
'num_format': '#,##0', 'align': 'center', 'valign': 'vcenter', 'text_wrap': True
|
|
784
|
+
})
|
|
785
|
+
formatc2 = workbook.add_format({
|
|
786
|
+
'num_format': '#,##0.0', 'align': 'center', 'valign': 'vcenter', 'text_wrap': True
|
|
787
|
+
})
|
|
788
|
+
formatc3 = workbook.add_format({
|
|
789
|
+
'num_format': '0.000', 'align': 'center', 'valign': 'vcenter', 'text_wrap': True
|
|
790
|
+
})
|
|
791
|
+
formath1 = workbook.add_format({
|
|
792
|
+
'num_format': '#,###', 'bold': True, 'border': 1, 'bg_color': '#C0C0C0',
|
|
793
|
+
'align': 'center', 'valign': 'vcenter', 'text_wrap': True
|
|
794
|
+
})
|
|
795
|
+
|
|
796
|
+
# Set the column width and format of the Excel worksheets
|
|
797
|
+
worksheet0.set_column('A:J', 12.5, formatc1)
|
|
798
|
+
worksheet0.set_column('K:L', 12.5, formatc2)
|
|
799
|
+
worksheet0.set_column('M:N', 12.5, formatc3)
|
|
800
|
+
worksheet0.set_column('O:V', 12.5, formatc1)
|
|
801
|
+
|
|
802
|
+
worksheet1.set_column('A:B', 12.5, formatc1)
|
|
803
|
+
worksheet1.set_column('C:D', 12.5, formatc3)
|
|
804
|
+
worksheet1.set_column('E:H', 12.5, formatc2)
|
|
805
|
+
worksheet1.set_column('I:L', 12.5, formatc3)
|
|
806
|
+
|
|
807
|
+
worksheet2.set_column('A:E', 12.5, formatc1)
|
|
808
|
+
worksheet2.set_column('F:G', 12.5, formatc3)
|
|
809
|
+
worksheet2.set_column('H:K', 12.5, formatc2)
|
|
810
|
+
worksheet2.set_column('L:L', 12.5, formatc3)
|
|
811
|
+
worksheet2.set_column('M:N', 12.5, formatc2)
|
|
812
|
+
worksheet2.set_column('O:U', 12.5, formatc3)
|
|
813
|
+
|
|
814
|
+
worksheet3.set_column('A:B', 12.5, formatc1)
|
|
815
|
+
worksheet3.set_column('C:D', 12.5, formatc3)
|
|
816
|
+
|
|
817
|
+
worksheet4.set_column('A:A', 12.5, formatc1)
|
|
818
|
+
worksheet4.set_column('B:H', 12.5, formatc2)
|
|
819
|
+
|
|
820
|
+
worksheet5.set_column('A:C', 12.5, formatc1)
|
|
821
|
+
worksheet5.set_column('D:F', 12.5, formatc3)
|
|
822
|
+
worksheet5.set_column('G:H', 12.5, formatc2)
|
|
823
|
+
|
|
824
|
+
if output_combination:
|
|
825
|
+
worksheet6.set_column('A:C', 12.5, formatc1)
|
|
826
|
+
worksheet6.set_column('D:D', 12.5, formatc3)
|
|
827
|
+
worksheet6.set_column('E:AZ', 12.5, formatc1)
|
|
828
|
+
|
|
829
|
+
worksheet7.set_column('A:C', 12.5, formatc1)
|
|
830
|
+
worksheet7.set_column('D:D', 12.5, formatc3)
|
|
831
|
+
worksheet7.set_column('E:AZ', 12.5, formatc1)
|
|
832
|
+
|
|
833
|
+
# Write the column hearders with the defined format
|
|
834
|
+
for col_num, value in enumerate(df_route.columns.values):
|
|
835
|
+
worksheet0.write(0, col_num, value, formath1)
|
|
836
|
+
for col_num, value in enumerate(df_elem.columns.values):
|
|
837
|
+
worksheet1.write(0, col_num, value, formath1)
|
|
838
|
+
for col_num, value in enumerate(df_sets.columns.values):
|
|
839
|
+
worksheet2.write(0, col_num, value, formath1)
|
|
840
|
+
for col_num, value in enumerate(df_no_buckles.columns.values):
|
|
841
|
+
worksheet3.write(0, col_num, value, formath1)
|
|
842
|
+
for col_num, value in enumerate(df_pp_plot.columns.values):
|
|
843
|
+
worksheet4.write(0, col_num, value, formath1)
|
|
844
|
+
for col_num, value in enumerate(df_pp_buckle_prop.columns.values):
|
|
845
|
+
worksheet5.write(0, col_num, value, formath1)
|
|
846
|
+
|
|
847
|
+
if output_combination:
|
|
848
|
+
for col_num, value in enumerate(df_comb_per_set.columns.values):
|
|
849
|
+
worksheet6.write(0, col_num + 1, value[0], formath1)
|
|
850
|
+
worksheet6.write(1, col_num + 1, value[1], formath1)
|
|
851
|
+
# Merge header cells for the 3 columns in the first and second row
|
|
852
|
+
if col_num <= 2:
|
|
853
|
+
worksheet6.merge_range(0, col_num + 1, 1, col_num + 1, value[1], formath1)
|
|
854
|
+
# Merge header cells for the 'Number of Buckles' columns in the first row
|
|
855
|
+
worksheet6.merge_range(
|
|
856
|
+
0, 4, 0, len(df_comb_per_set.columns.values), df_comb_per_set.columns.levels[0][1], formath1
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
for col_num, value in enumerate(df_comb_per_section.columns.values):
|
|
860
|
+
worksheet7.write(0, col_num + 1, value[0], formath1)
|
|
861
|
+
worksheet7.write(1, col_num + 1, value[1], formath1)
|
|
862
|
+
# Merge header cells for the 3 columns in the first and second row
|
|
863
|
+
if col_num <= 2:
|
|
864
|
+
worksheet7.merge_range(0, col_num + 1, 1, col_num + 1, value[1], formath1)
|
|
865
|
+
# Merge header cells for the 'Number of Buckles' columns in the first row
|
|
866
|
+
worksheet7.merge_range(
|
|
867
|
+
0, 4, 0, len(df_comb_per_section.columns.values),
|
|
868
|
+
df_comb_per_section.columns.levels[0][1], formath1
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
# Close the Excel writer and output the Excel file
|
|
872
|
+
writer.close()
|
|
873
|
+
|
|
874
|
+
def pp_outputs(output_file_name, n_sim, output_combination, df_pp_buckle_prop,
|
|
875
|
+
df_pp_set, df_pp_plot, prob_exceed_char_fric, df_scen, df_route):
|
|
876
|
+
"""
|
|
877
|
+
Perform post-processing of analysis outputs.
|
|
878
|
+
|
|
879
|
+
Parameters
|
|
880
|
+
----------
|
|
881
|
+
output_file_name : str
|
|
882
|
+
Name of the output Excel file
|
|
883
|
+
n_sim : int
|
|
884
|
+
Number of simulations.
|
|
885
|
+
output_combination : Boolean
|
|
886
|
+
Switch to write the most frequent combination set of buckles in the result file.
|
|
887
|
+
df_pp_buckle_prop : pandas DataFrame
|
|
888
|
+
DataFrame containing post-processed buckling properties.
|
|
889
|
+
df_pp_set : DataFrame
|
|
890
|
+
Definition of element sets for post-processing outputs.
|
|
891
|
+
df_pp_plot : pandas DataFrame
|
|
892
|
+
DataFrame containing post-processed plot data.
|
|
893
|
+
prob_exceed_char_fric : float
|
|
894
|
+
Probability of exceedance associated with the characteristic lateral breakout friction.
|
|
895
|
+
df_pp_set : DataFrame
|
|
896
|
+
Definition of element sets for post-processing outputs.
|
|
897
|
+
df_scen : DataFrame
|
|
898
|
+
Dataframe containing the design data along the pipeline
|
|
899
|
+
route (mesh) that remains constant among deterministic and
|
|
900
|
+
Monte-Carlo simulations.
|
|
901
|
+
df_route : DataFrame
|
|
902
|
+
Dataframe containing the route data of the pipeline.
|
|
903
|
+
|
|
904
|
+
Returns
|
|
905
|
+
-------
|
|
906
|
+
df_no_buckles : pandas DataFrame
|
|
907
|
+
DataFrame containing post-processed statistics about the number of buckles
|
|
908
|
+
along the pipeline.
|
|
909
|
+
df_sets : pandas DataFrame
|
|
910
|
+
DataFrame containing post-processed statistics grouped by pipeline sets.
|
|
911
|
+
"""
|
|
912
|
+
|
|
913
|
+
# Dataframe containing the raw data
|
|
914
|
+
df_pp_buckle_prop = df_pp_buckle_prop.sort_values(by = ['KP', 'isim'])
|
|
915
|
+
df_pp = pd.merge_asof(left = df_pp_buckle_prop, right = df_pp_set,
|
|
916
|
+
left_on = 'KP', right_on = 'KP_from')
|
|
917
|
+
|
|
918
|
+
# Probability of buckling, VAS and lateral breakout friction sorted by element
|
|
919
|
+
df_elem = pp_elem(df_pp, n_sim)
|
|
920
|
+
|
|
921
|
+
# Distribution of the expected number of buckles along the pipeline
|
|
922
|
+
df_no_buckles = pp_no_buckles(df_pp, n_sim)
|
|
923
|
+
|
|
924
|
+
# Probability of buckling, VAS and lateral breakout friction sorted by post-processing set
|
|
925
|
+
df_sets = pp_sets(df_pp, n_sim, prob_exceed_char_fric, df_pp_set, df_scen)
|
|
926
|
+
|
|
927
|
+
# Post-processing of 'df_pp_plot' for print-out
|
|
928
|
+
df_pp_plot = pp_eaf(df_pp_plot)
|
|
929
|
+
|
|
930
|
+
# Post-processing of 'df_pp_buckle_prop' for print-out
|
|
931
|
+
df_pp_buckle_prop = pp_raw(df_pp_buckle_prop)
|
|
932
|
+
|
|
933
|
+
if output_combination:
|
|
934
|
+
# Calculate the most frequent combination of KP set with buckles
|
|
935
|
+
df_comb_per_set = pp_comb_buckles_per_set(df_pp, df_pp_set, n_sim)
|
|
936
|
+
df_comb_per_section = pp_comb_buckles_per_section(df_pp, df_scen, n_sim)
|
|
937
|
+
|
|
938
|
+
# Save key outputs to Excel file
|
|
939
|
+
pp_save(output_combination, output_file_name, df_route, df_elem, df_sets, df_no_buckles,
|
|
940
|
+
df_pp_plot, df_pp_buckle_prop, df_comb_per_set, df_comb_per_section)
|
|
941
|
+
else:
|
|
942
|
+
# Save key outputs to Excel file
|
|
943
|
+
pp_save(output_combination, output_file_name, df_route, df_elem, df_sets, df_no_buckles,
|
|
944
|
+
df_pp_plot, df_pp_buckle_prop)
|
|
945
|
+
|
|
946
|
+
return df_no_buckles, df_sets
|
|
947
|
+
|
|
948
|
+
def pp_plots(plot_file_name, df_scen, df_plot, df_vap_plot, df_no_buckles, df_sets,
|
|
949
|
+
prob_exceed_char_fric):
|
|
950
|
+
"""
|
|
951
|
+
Plot deterministic and probabilistic results
|
|
952
|
+
|
|
953
|
+
Parameters
|
|
954
|
+
----------
|
|
955
|
+
plot_file_name : str
|
|
956
|
+
Name of the file
|
|
957
|
+
df_scen : DataFrame
|
|
958
|
+
Dataframe containing the design data along the pipeline
|
|
959
|
+
route (mesh) that remains constant among deterministic and
|
|
960
|
+
Monte-Carlo simulations.
|
|
961
|
+
df_plot : DataFrame
|
|
962
|
+
Definition on assessed mesh of CBF and EAF in different conditions.
|
|
963
|
+
for case to plot
|
|
964
|
+
df_vap_plot : DataFrame
|
|
965
|
+
Definition of virtual anchor points for case to plot.
|
|
966
|
+
Columns: ['ielt VAP', 'KP VAP', 'ESF VAP'].
|
|
967
|
+
df_no_buckles : DataFrame
|
|
968
|
+
Probability of number of buckles over pipeline.
|
|
969
|
+
df_sets : DataFrame
|
|
970
|
+
Probability of buckling and characteristic VAS and friction factors by set.
|
|
971
|
+
prob_exceed_char_fric : float
|
|
972
|
+
Probability of exceedance for characteristic friction factors.
|
|
973
|
+
plot_file_name : str
|
|
974
|
+
File name where plots are to be saved.
|
|
975
|
+
"""
|
|
976
|
+
|
|
977
|
+
# Convert the units of 'df_plot', 'df_vap_plot' & 'df_scen' (m to km and N to kN)
|
|
978
|
+
df_plot[['KP']] /= 1000.0
|
|
979
|
+
df_vap_plot[['KP VAP', 'ESF VAP']] /= 1000.0
|
|
980
|
+
df_scen[['KP', 'FRF OP Pressure', 'FRF OP Temperature']] /= 1000.0
|
|
981
|
+
|
|
982
|
+
# Create arrays to plot buckling probability, characteristic VAS and characteristic friction
|
|
983
|
+
np_kp = np.array([df_sets.iloc[0]['KP From (m)'] / 1000.0])
|
|
984
|
+
np_prob = np.array([0.0])
|
|
985
|
+
np_vas_cond = np.array([0.0])
|
|
986
|
+
np_vas_uncond = np.array([0.0])
|
|
987
|
+
np_mul_buckle = np.array([0.0])
|
|
988
|
+
for index, row in df_sets.iterrows():
|
|
989
|
+
np_kp = np.append(np_kp, np.append(
|
|
990
|
+
row['KP From (m)'] / 1000.0,
|
|
991
|
+
row['KP To (m)'] / 1000.0))
|
|
992
|
+
np_prob = np.append(np_prob, np.append(
|
|
993
|
+
100.0 * row['Probability of Buckling'],
|
|
994
|
+
100.0 * row['Probability of Buckling']))
|
|
995
|
+
np_vas_cond = np.append(np_vas_cond, np.append(
|
|
996
|
+
row['Characteristic VAS, Conditional (m)'],
|
|
997
|
+
row['Characteristic VAS, Conditional (m)']))
|
|
998
|
+
np_vas_uncond = np.append(np_vas_uncond, np.append(
|
|
999
|
+
row['Characteristic VAS, Unconditional (m)'],
|
|
1000
|
+
row['Characteristic VAS, Unconditional (m)']))
|
|
1001
|
+
np_mul_buckle = np.append(np_mul_buckle, np.append(
|
|
1002
|
+
row['Characteristic Lateral Breakout Friction, Buckles'],
|
|
1003
|
+
row['Characteristic Lateral Breakout Friction, Buckles']))
|
|
1004
|
+
if index == df_sets.shape[0] - 1:
|
|
1005
|
+
np_kp = np.append(np_kp, row['KP To (m)'] / 1000.0)
|
|
1006
|
+
np_prob = np.append(np_prob, 0.0)
|
|
1007
|
+
np_vas_cond = np.append(np_vas_cond, 0.0)
|
|
1008
|
+
np_vas_uncond = np.append(np_vas_uncond, 0.0)
|
|
1009
|
+
np_mul_buckle = np.append(np_mul_buckle, 0.0)
|
|
1010
|
+
|
|
1011
|
+
# Create an array to plot the HE of the geotechnical lateral breakdown friction
|
|
1012
|
+
np_mul_kp = np.empty(0)
|
|
1013
|
+
np_mul_geotech = np.empty(0)
|
|
1014
|
+
for index, row in df_scen.iterrows():
|
|
1015
|
+
# df_scen has at least 2 points, no need to double the points in append functions
|
|
1016
|
+
np_mul_kp = np.append(np_mul_kp, row['KP'])
|
|
1017
|
+
mul_geotech = np.interp(1.0 - prob_exceed_char_fric,
|
|
1018
|
+
row['mul OP CDF Array'], row['mul OP Array'])
|
|
1019
|
+
np_mul_geotech = np.append(np_mul_geotech, mul_geotech)
|
|
1020
|
+
|
|
1021
|
+
# Generate matplolib figure
|
|
1022
|
+
fig = plt.figure()
|
|
1023
|
+
dpi_size = 110
|
|
1024
|
+
fig.set_size_inches(19.2 * 100 / dpi_size, 10.8 * 100 / dpi_size)
|
|
1025
|
+
gs = GridSpec(nrows = 2, ncols = 3)
|
|
1026
|
+
|
|
1027
|
+
# Plot effective axial force profiles from selected case
|
|
1028
|
+
a1=fig.add_subplot(gs[0, :])
|
|
1029
|
+
a1.plot(df_plot['KP'], df_plot['EAF_inst'],
|
|
1030
|
+
label = 'EAF Installation', color = 'C1')
|
|
1031
|
+
a1.plot(df_plot['KP'], df_plot['EAF_ht'],
|
|
1032
|
+
label = 'EAF Hydrotest', color = 'C2')
|
|
1033
|
+
a1.plot(df_plot['KP'], df_plot['EAF_p_op'],
|
|
1034
|
+
label = 'EAF Operation (Pressure Only)', color = 'C3')
|
|
1035
|
+
a1.plot(df_plot['KP'], df_plot['EAF_op'],
|
|
1036
|
+
label = 'EAF Operation', color = 'C4')
|
|
1037
|
+
a1.plot(df_plot['KP'], df_plot['EAF_op_unbuck'],
|
|
1038
|
+
label = 'EAF Operation (without Buckling)', color = 'C4', linestyle = ':')
|
|
1039
|
+
|
|
1040
|
+
# Plot intermediate force profile during temperature application
|
|
1041
|
+
for i in range(1, 21):
|
|
1042
|
+
# Shouldnt overwrite existing df_plot['EAF_inst'], separate dataframe used instead
|
|
1043
|
+
eaf_interim = df_scen['FRF OP Pressure'] + (i / 20) * df_scen['FRF OP Temperature']
|
|
1044
|
+
eaf_interim=np.where(eaf_interim < df_plot['EAF_op_unbuck'].to_numpy(), eaf_interim, np.nan)
|
|
1045
|
+
a1.plot(df_plot['KP'], eaf_interim, color = 'C4', linestyle = '--', alpha = 0.25)
|
|
1046
|
+
|
|
1047
|
+
#TODO: Indeed, however different sections (routes, straight, sleepers...) can have different ones
|
|
1048
|
+
# and it's interresting to see if area buckle "earlier" than other
|
|
1049
|
+
#? Block commented as all buckling forces per section are constant in the deterministic case
|
|
1050
|
+
# Plot buckling susceptibility areas and actual buckle locations
|
|
1051
|
+
# a1.scatter(df_plot.loc[
|
|
1052
|
+
# df_plot['CBF_op'] < df_plot['EAF_op_unbuck'], 'KP'],
|
|
1053
|
+
# df_plot.loc[
|
|
1054
|
+
# df_plot['CBF_op'] < df_plot['EAF_op_unbuck'], 'CBF_op'],
|
|
1055
|
+
# label = 'CBF operation', marker = '.', color = 'C4')
|
|
1056
|
+
|
|
1057
|
+
# Plot VAP
|
|
1058
|
+
a1.scatter(df_vap_plot['KP VAP'], df_vap_plot['ESF VAP'],
|
|
1059
|
+
marker = '8', c = 'none', edgecolors = 'C3', label = 'VAP')
|
|
1060
|
+
a1.set_xlabel('KP [km]')
|
|
1061
|
+
a1.set_ylabel('Effective Force [kN]')
|
|
1062
|
+
a1.legend()
|
|
1063
|
+
a1.grid()
|
|
1064
|
+
|
|
1065
|
+
# Plot distribution of number of buckles
|
|
1066
|
+
a2 = fig.add_subplot(gs[1, 0])
|
|
1067
|
+
a2.plot(df_no_buckles['Number of Buckles'],
|
|
1068
|
+
100.0 * df_no_buckles['Probability of Buckling'], color = 'C1')
|
|
1069
|
+
a2.set_xlabel('Number of Buckles')
|
|
1070
|
+
a2.set_ylabel('Probability [%]')
|
|
1071
|
+
a2.grid()
|
|
1072
|
+
|
|
1073
|
+
# Plot lateral friction factor versus location
|
|
1074
|
+
a3 = fig.add_subplot(gs[1, 1])
|
|
1075
|
+
a3.plot(np_kp, np_mul_buckle,
|
|
1076
|
+
label = f'P{int(100 * prob_exceed_char_fric)} Buckle Friction', color = 'C1')
|
|
1077
|
+
a3.plot(np_mul_kp, np_mul_geotech,
|
|
1078
|
+
label = f'P{int(100 * prob_exceed_char_fric)} Geotech Friction', color = 'C2')
|
|
1079
|
+
a3.set_xlabel('KP [km]')
|
|
1080
|
+
a3.set_ylabel('Lateral Breakout Friction Factor (Operation)')
|
|
1081
|
+
a3.legend()
|
|
1082
|
+
a3.grid()
|
|
1083
|
+
|
|
1084
|
+
# Plot probability of buckling and characteristic VAS
|
|
1085
|
+
a4 = fig.add_subplot(gs[1, 2])
|
|
1086
|
+
a4_twin = a4.twinx()
|
|
1087
|
+
# a4.plot(np_kp, np_vas_cond, label = 'Conditional VAS',
|
|
1088
|
+
# color = 'C1')
|
|
1089
|
+
a4.plot(np_kp, np_vas_uncond, label = 'Unconditional VAS',
|
|
1090
|
+
color = 'C2')
|
|
1091
|
+
a4_twin.plot(np_kp, np_prob, label = 'Probability of Buckling', linestyle = ':',
|
|
1092
|
+
color = 'C3')
|
|
1093
|
+
a4.set_xlabel('KP [km]')
|
|
1094
|
+
a4.set_ylabel('Characteristic VAS [m]')
|
|
1095
|
+
a4_twin.set_ylabel('Buckling Probability [%]')
|
|
1096
|
+
line4, label4 = a4.get_legend_handles_labels()
|
|
1097
|
+
line4_twin, label4_twin = a4_twin.get_legend_handles_labels()
|
|
1098
|
+
a4.legend(line4 + line4_twin, label4 + label4_twin)
|
|
1099
|
+
a4.grid()
|
|
1100
|
+
|
|
1101
|
+
fig_manager=plt.get_current_fig_manager()
|
|
1102
|
+
try:
|
|
1103
|
+
fig_manager.window.state('zoomed')
|
|
1104
|
+
except AttributeError:
|
|
1105
|
+
pass
|
|
1106
|
+
try:
|
|
1107
|
+
fig_manager.window.showMaximized()
|
|
1108
|
+
except AttributeError:
|
|
1109
|
+
pass
|
|
1110
|
+
plt.subplots_adjust(
|
|
1111
|
+
left = 0.1, bottom = 0.1, right = 0.95, top = 0.925, wspace = 0.225, hspace = 0.2)
|
|
1112
|
+
plt.savefig(plot_file_name, dpi = dpi_size)
|
|
1113
|
+
# plt.show()
|
|
1114
|
+
plt.close()
|
|
1115
|
+
|
|
1116
|
+
def replace_route_sheet(work_dir, input_file_name, df_scen, df_route):
|
|
1117
|
+
"""
|
|
1118
|
+
Replace the Route sheet in the Excel file with a new dataframe.
|
|
1119
|
+
|
|
1120
|
+
Parameters
|
|
1121
|
+
----------
|
|
1122
|
+
work_dir : str
|
|
1123
|
+
Directory where the input file is located.
|
|
1124
|
+
input_file_name : str
|
|
1125
|
+
Name of the input Excel file.
|
|
1126
|
+
df_scen : DataFrame
|
|
1127
|
+
DataFrame containing the design data along the pipeline
|
|
1128
|
+
route (mesh) that remains constant among deterministic and
|
|
1129
|
+
Monte-Carlo simulations.
|
|
1130
|
+
df_route : DataFrame
|
|
1131
|
+
DataFrame containing the new Route data.
|
|
1132
|
+
|
|
1133
|
+
Returns
|
|
1134
|
+
-------
|
|
1135
|
+
None
|
|
1136
|
+
"""
|
|
1137
|
+
|
|
1138
|
+
# Extract key scenario information from 'df_scen'
|
|
1139
|
+
pipeline_id = df_scen["Pipeline"].values[0]
|
|
1140
|
+
scenario_no = df_scen["Scenario"].values[0]
|
|
1141
|
+
route_layout = df_scen["Layout Set"].values[0]
|
|
1142
|
+
|
|
1143
|
+
# Define input and output file paths
|
|
1144
|
+
input_path = Path(work_dir) / input_file_name
|
|
1145
|
+
output_name = f"{Path(input_file_name).stem}_{pipeline_id}_scen{scenario_no}_buckfast.xlsx"
|
|
1146
|
+
output_path = Path(work_dir) / output_name
|
|
1147
|
+
|
|
1148
|
+
# Create the output workbook from the input file, then remove old sheets
|
|
1149
|
+
workbook = load_workbook(input_path)
|
|
1150
|
+
for sheet_name in ["Route", "Mitigation", "Soil Zoning"]:
|
|
1151
|
+
if sheet_name in workbook.sheetnames:
|
|
1152
|
+
del workbook[sheet_name]
|
|
1153
|
+
workbook.save(output_path)
|
|
1154
|
+
|
|
1155
|
+
# Write the new Route sheet
|
|
1156
|
+
with pd.ExcelWriter(
|
|
1157
|
+
output_path,
|
|
1158
|
+
engine="openpyxl",
|
|
1159
|
+
mode="a",
|
|
1160
|
+
if_sheet_exists="replace",
|
|
1161
|
+
) as writer:
|
|
1162
|
+
# Load the original Route sheet to get the first and last rows
|
|
1163
|
+
path = Path(work_dir) / input_file_name
|
|
1164
|
+
df_route_sheet = pd.read_excel(path, sheet_name="Route")
|
|
1165
|
+
df_filtered = df_route_sheet.loc[
|
|
1166
|
+
(df_route_sheet["Pipeline"] == pipeline_id) &
|
|
1167
|
+
(df_route_sheet["Layout Set"] == route_layout)
|
|
1168
|
+
].copy()
|
|
1169
|
+
first_row = df_filtered.iloc[0].reindex(df_route.columns)
|
|
1170
|
+
last_row = df_filtered.iloc[-1].reindex(df_route.columns)
|
|
1171
|
+
df_out = pd.concat(
|
|
1172
|
+
[first_row.to_frame().T, df_route, last_row.to_frame().T],
|
|
1173
|
+
ignore_index=True
|
|
1174
|
+
)
|
|
1175
|
+
df_out.to_excel(writer, sheet_name="Route", index=False)
|
|
1176
|
+
# Apply formatting to the Route sheet using openpyxl
|
|
1177
|
+
from openpyxl.styles import Font, PatternFill, Border, Side, Alignment
|
|
1178
|
+
from openpyxl.utils import get_column_letter
|
|
1179
|
+
# Apply formatting to the Route sheet
|
|
1180
|
+
wb = writer.book
|
|
1181
|
+
ws = wb["Route"]
|
|
1182
|
+
target_index = 1 # 0-based: second tab
|
|
1183
|
+
current_index = wb.worksheets.index(ws)
|
|
1184
|
+
if current_index != target_index:
|
|
1185
|
+
wb.move_sheet(ws, offset=target_index - current_index)
|
|
1186
|
+
# Define cell formats for the header and data cells
|
|
1187
|
+
header_font = Font(bold=True)
|
|
1188
|
+
header_fill = PatternFill(fill_type="solid", fgColor="C0C0C0")
|
|
1189
|
+
header_border = Border(
|
|
1190
|
+
left=Side(style="thin"), right=Side(style="thin"),
|
|
1191
|
+
top=Side(style="thin"), bottom=Side(style="thin")
|
|
1192
|
+
)
|
|
1193
|
+
cell_alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
|
1194
|
+
for cell in ws[1]:
|
|
1195
|
+
cell.font = header_font
|
|
1196
|
+
cell.fill = header_fill
|
|
1197
|
+
cell.border = header_border
|
|
1198
|
+
cell.alignment = cell_alignment
|
|
1199
|
+
# Set the column width and format of the Route sheet
|
|
1200
|
+
def format_cols(start_col, end_col, num_fmt):
|
|
1201
|
+
for col in range(start_col, end_col + 1):
|
|
1202
|
+
col_letter = get_column_letter(col)
|
|
1203
|
+
ws.column_dimensions[col_letter].width = 12
|
|
1204
|
+
for row in range(2, ws.max_row + 1):
|
|
1205
|
+
c = ws.cell(row=row, column=col)
|
|
1206
|
+
c.number_format = num_fmt
|
|
1207
|
+
c.alignment = cell_alignment
|
|
1208
|
+
# Apply specific number formats to columns
|
|
1209
|
+
format_cols(1, 10, "#,##0") # A:J
|
|
1210
|
+
format_cols(11, 12, "#,##0.0") # K:L
|
|
1211
|
+
format_cols(13, 14, "0.000") # M:N
|
|
1212
|
+
format_cols(15, 22, "#,##0") # O:V
|
|
1213
|
+
|
|
1214
|
+
def pp_buckpy(work_dir, input_file_name, df_scen, df_route, df_pp_set, df_pp_plot, df_vap_plot, df_pp_buckle_prop, output_combination, bl_verbose, excel_format):
|
|
1215
|
+
"""
|
|
1216
|
+
Post-processing of probabilistic buckling results.
|
|
1217
|
+
|
|
1218
|
+
Parameters
|
|
1219
|
+
----------
|
|
1220
|
+
work_dir : str
|
|
1221
|
+
Directory where the output files are saved.
|
|
1222
|
+
input_file_name : str
|
|
1223
|
+
Name of the input file.
|
|
1224
|
+
df_scen : DataFrame
|
|
1225
|
+
Dataframe containing the design data along the pipeline
|
|
1226
|
+
route (mesh) that remains constant among deterministic and
|
|
1227
|
+
Monte-Carlo simulations.
|
|
1228
|
+
df_route : DataFrame
|
|
1229
|
+
Dataframe containing the route data of the pipeline.
|
|
1230
|
+
df_pp_set : DataFrame
|
|
1231
|
+
Definition of element sets for post-processing outputs.
|
|
1232
|
+
df_pp_plot : DataFrame
|
|
1233
|
+
DataFrame containing post-processed plot data.
|
|
1234
|
+
df_vap_plot : DataFrame
|
|
1235
|
+
DataFrame containing post-processed virtual anchor point data.
|
|
1236
|
+
df_pp_buckle_prop : pandas DataFrame
|
|
1237
|
+
DataFrame containing post-processed buckling properties.
|
|
1238
|
+
output_combination : Boolean
|
|
1239
|
+
Switch to write the most frequent combination set of buckles in the result file.
|
|
1240
|
+
bl_verbose : Boolean
|
|
1241
|
+
Switch to print in the terminal the time taken to post-process results.
|
|
1242
|
+
excel_format : Boolean
|
|
1243
|
+
Switch to write outputs in Excel format with Legacy or Current.
|
|
1244
|
+
|
|
1245
|
+
Returns
|
|
1246
|
+
-------
|
|
1247
|
+
None
|
|
1248
|
+
"""
|
|
1249
|
+
|
|
1250
|
+
# Convert 'output_combination' to boolean if it is a string
|
|
1251
|
+
if isinstance(output_combination, str):
|
|
1252
|
+
output_combination = output_combination.strip().lower() in {"true", "1", "yes", "y", "on"}
|
|
1253
|
+
else:
|
|
1254
|
+
output_combination = bool(output_combination)
|
|
1255
|
+
|
|
1256
|
+
# Extract key scenario information from 'df_scen'
|
|
1257
|
+
scenario_no = df_scen["Scenario"].values[0]
|
|
1258
|
+
pipeline_id = df_scen["Pipeline"].values[0]
|
|
1259
|
+
prob_exceed_char_fric = df_scen["Char. Friction Prob."].values[0]
|
|
1260
|
+
n_sim = df_scen["Simulations"].values[0]
|
|
1261
|
+
|
|
1262
|
+
# Starting time of the post-processing module
|
|
1263
|
+
start_time = time.time()
|
|
1264
|
+
|
|
1265
|
+
# Print in the terminal that the post-processing of the results has started
|
|
1266
|
+
if bl_verbose:
|
|
1267
|
+
print("4. Post-process results")
|
|
1268
|
+
|
|
1269
|
+
# Calculate probabilistic outputs and save outputs to Excel file
|
|
1270
|
+
output_file_name = (
|
|
1271
|
+
f"{work_dir}/{input_file_name.split('.')[0]}_{pipeline_id}_scen{scenario_no}_outputs.xlsx"
|
|
1272
|
+
)
|
|
1273
|
+
df_prob_n_buckle, df_prob_set = pp_outputs(
|
|
1274
|
+
output_file_name,
|
|
1275
|
+
n_sim,
|
|
1276
|
+
output_combination,
|
|
1277
|
+
df_pp_buckle_prop,
|
|
1278
|
+
df_pp_set,
|
|
1279
|
+
df_pp_plot,
|
|
1280
|
+
prob_exceed_char_fric,
|
|
1281
|
+
df_scen,
|
|
1282
|
+
df_route
|
|
1283
|
+
)
|
|
1284
|
+
|
|
1285
|
+
# Print in the terminal the time taken to post-process results
|
|
1286
|
+
if bl_verbose:
|
|
1287
|
+
print(f' Time taken to post-process results: {time.time() - start_time:.1f}s')
|
|
1288
|
+
|
|
1289
|
+
# Plot post-processed results and save figure to file
|
|
1290
|
+
plot_file_name = (
|
|
1291
|
+
f"{work_dir}/{input_file_name.split('.')[0]}_{pipeline_id}_scen{scenario_no}_plots-1.png"
|
|
1292
|
+
)
|
|
1293
|
+
pp_plots(
|
|
1294
|
+
plot_file_name,
|
|
1295
|
+
df_scen,
|
|
1296
|
+
df_pp_plot,
|
|
1297
|
+
df_vap_plot,
|
|
1298
|
+
df_prob_n_buckle,
|
|
1299
|
+
df_prob_set,
|
|
1300
|
+
prob_exceed_char_fric
|
|
1301
|
+
)
|
|
1302
|
+
|
|
1303
|
+
# Replace the Route sheet in the Excel file with the new dataframe
|
|
1304
|
+
if excel_format == "Current":
|
|
1305
|
+
replace_route_sheet(work_dir, input_file_name, df_scen, df_route)
|