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.
@@ -0,0 +1,1233 @@
1
+ '''
2
+ Script to create the Buckfast input file from the BuckPy input file
3
+ and autorun the Buckfast for all the pipelines and scenarios.
4
+ Note: need to run the script in the folder where buckfast132.exe and input csv files exist.
5
+ '''
6
+
7
+ import pandas as pd
8
+ import numpy as np
9
+ import pysubsea as ss
10
+
11
+ def calc_cbf(route_type, loc_fric, scale_fric, loc_oos, scale_oos, ea, ei, sw, radius, h, rcm_force):
12
+
13
+ '''
14
+ Compute the parameters of a lognormal distribution for CBF
15
+ (STRAIGHT, BEND, SLEEPER or RCM sections).
16
+
17
+ Parameters
18
+ ----------
19
+ route_type : string
20
+ The route type: 'STRAIGHT', 'BEND', 'SLEEPER' or 'RCM'
21
+ loc_fric : float
22
+ The location parameter of the lognormal friction distribution
23
+ scale_fric : float
24
+ The scale paramater of the lognormal friction distribution
25
+ loc_OOS : float
26
+ The location parameter of the lognormal OOS distribution
27
+ scale_OOS : float
28
+ The scale paramater of the lognormal OOS distribution
29
+ ea : float
30
+ Axial stiffness
31
+ ei : float
32
+ Bending stiffness
33
+ sw : float
34
+ Submerged weight
35
+ radius : float
36
+ Bend radius
37
+ h : float
38
+ Sleeper height
39
+ rcm_force : float
40
+ RCM buckling force
41
+
42
+ Returns
43
+ -------
44
+ loc_cbf : float
45
+ Location parameter of the lognormal CBF distribution
46
+ scale_cbf : float
47
+ scale paramater of the lognormal CBF distribution
48
+ mean_cbf : float
49
+ Mean of the lognormal CBF distribution
50
+ std_cbf : float
51
+ Standard deviation of the lognormal CBF distribution
52
+ '''
53
+
54
+ # Calculate loc_cbf and scale_cbf
55
+ if route_type == 'STRAIGHT':
56
+ s_char = 2.26 * ea**0.25 * ei**0.25 * sw**0.5
57
+ loc_cbf = 0.5 * loc_fric + loc_oos + np.log(s_char)
58
+ scale_cbf = np.sqrt((0.5 * scale_fric)**2 + scale_oos**2)
59
+
60
+ elif route_type == 'BEND':
61
+ loc_cbf = loc_fric + loc_oos + np.log(int(radius)) + np.log(sw)
62
+ scale_cbf = np.sqrt(scale_fric**2 + scale_oos**2)
63
+
64
+ elif route_type == 'SLEEPER':
65
+ prop_uhb = 4.0 * np.sqrt(ei * sw / h)
66
+ loc_cbf = loc_oos + np.log(prop_uhb)
67
+ scale_cbf = scale_oos
68
+
69
+ elif route_type == 'RCM':
70
+ loc_cbf = loc_oos + np.log(rcm_force)
71
+ scale_cbf = scale_oos
72
+
73
+ else:
74
+ loc_cbf = loc_oos
75
+ scale_cbf = scale_oos
76
+
77
+ # Calculate mean_cbf and std_cbf
78
+ if route_type == 'SLEEPER':
79
+ mean_oos= np.exp(loc_oos + scale_oos**2 / 2)
80
+ std_oos = np.sqrt((np.exp(scale_oos**2) - 1) * np.exp(2 * loc_oos + scale_oos**2))
81
+ mean_cbf = mean_oos * prop_uhb
82
+ std_cbf = std_oos * prop_uhb
83
+
84
+ else:
85
+ mean_cbf = np.exp(loc_cbf + scale_cbf**2 / 2)
86
+ std_cbf = np.sqrt((np.exp(scale_cbf**2) - 1) * np.exp(2 * loc_cbf + scale_cbf**2))
87
+
88
+ return loc_cbf, scale_cbf, mean_cbf, std_cbf
89
+
90
+ def calc_expand_kp(df, kp_col):
91
+
92
+ '''
93
+ Function to expand the KP array with 1000 intervals from 1000 to nearest maximum KP.
94
+
95
+ Parameters
96
+ ----------
97
+ df : pandas Dataframe
98
+ Dataframe containing the original KP values.
99
+ kp_col : string
100
+ The column name of the KP values to expand.
101
+
102
+ Returns
103
+ -------
104
+ df : pandas Dataframe
105
+ Dataframe containing the expanded KP values.
106
+ '''
107
+
108
+ # Rename kp_col to 'KP From'
109
+ df = df.rename(columns = {kp_col: 'KP From'})
110
+
111
+ # Expand the KP array with 1000 intervals from 1000 to nearest maximum KP
112
+ max_kp = np.floor(df['KP From'].max() / 1000.0) * 1000.0
113
+ kp_array = np.arange(1000, max_kp + 1.0, 1000)
114
+
115
+ # Create a dataframe for the expanded kp
116
+ df_expand = pd.DataFrame({'Point ID From': [np.nan] * len(kp_array), 'KP From': kp_array})
117
+ df = pd.concat([df, df_expand], ignore_index = True).sort_values(
118
+ by = 'KP From').drop_duplicates('KP From').reset_index(drop = True).ffill()
119
+
120
+ # Calculate relative length between KP and KP To
121
+ df['KP To'] = df['KP From'].shift(-1)
122
+ df = df.dropna()
123
+ df['Length'] = df['KP To'] - df['KP From']
124
+
125
+ # Calculate element number and element size
126
+ df['Elem No.'] = np.ceil(df['Length'] / 100.0)
127
+ df['Elem Size'] = df['Length'] / df['Elem No.']
128
+
129
+ return df
130
+
131
+ def calc_element_array(df):
132
+
133
+ '''
134
+ Function to create element array based on KP, KP TO and element number.
135
+
136
+ Parameters
137
+ ----------
138
+ df : pandas Dataframe
139
+ Dataframe containing the expanded KP values.
140
+
141
+ Returns
142
+ -------
143
+ df : pandas Dataframe
144
+ Dataframe containing the elements between each KP value.
145
+ '''
146
+
147
+ # Create the elements between each KP points
148
+ elem_array = np.empty(0)
149
+ elem_array = df.apply(lambda x: pd.Series(np.append(elem_array, np.linspace(
150
+ x['KP From'], x['KP To'], int(x['Elem No.'] + 1.0)))), axis = 1)
151
+
152
+ # Convert the element dataframe to np array and flatten
153
+ elem_array = elem_array.to_numpy().flatten()
154
+
155
+ # Remove duplicated values at 1000*n and np.nan
156
+ elem_array = elem_array.astype(float)
157
+ elem_array = np.unique(elem_array)
158
+ elem_array = elem_array[~np.isnan(elem_array)]
159
+
160
+ return elem_array
161
+
162
+ def calc_kp_interpolation(elem_array, df_oper):
163
+
164
+ '''
165
+ Function to interpolate the RLT, pressure and temperature using KP and operating profile.
166
+
167
+ Parameters
168
+ ----------
169
+ elem_array : np Array
170
+ Array containing the kp value of the elements.
171
+ df_oper : pandas Dataframe
172
+ Dataframe containing the original operating profiles data.
173
+
174
+ Returns
175
+ -------
176
+ df : pandas Dataframe
177
+ Dataframe containing the interpolated operating profiles data.
178
+ '''
179
+
180
+ # Interpolate operating profile based on KP
181
+ df = pd.DataFrame({'KP': elem_array})
182
+ df['Pressure Installation'] = np.interp(
183
+ df['KP'], df_oper['KP'], df_oper['Pressure Installation'])
184
+ df['Pressure Hydrotest'] = np.interp(
185
+ df['KP'], df_oper['KP'], df_oper['Pressure Hydrotest'])
186
+ df['Pressure Operation'] = np.interp(
187
+ df['KP'], df_oper['KP'], df_oper['Pressure Operation'])
188
+ df['Temperature Installation'] = np.interp(
189
+ df['KP'], df_oper['KP'], df_oper['Temperature Installation'])
190
+ df['Temperature Hydrotest'] = np.interp(
191
+ df['KP'], df_oper['KP'], df_oper['Temperature Hydrotest'])
192
+ df['Temperature Operation'] = np.interp(
193
+ df['KP'], df_oper['KP'], df_oper['Temperature Operation'])
194
+ df['RLT'] = np.interp(df['KP'], df_oper['KP'], df_oper['RLT'])
195
+
196
+ return df
197
+
198
+ def calc_operating_profiles(df, df_route, pipeline_set, loadcase_set):
199
+
200
+ """
201
+ Calculate operating profiles data and process it.
202
+
203
+ Parameters
204
+ ----------
205
+ df : pandas.DataFrame
206
+ DataFrame containing the operating profiles data.
207
+ df_route : pandas.DataFrame
208
+ DataFrame containing route data and calculated route data.
209
+ pipeline_set : str
210
+ Identifier of the pipeline set.
211
+ loadcase_set : str
212
+ Identifier of the loadcase set.
213
+
214
+ Returns
215
+ -------
216
+ df : pandas.DataFrame
217
+ DataFrame containing the operating profiles data and calculated operating data.
218
+ """
219
+
220
+ # Filter df DataFrame based on pipeline_set and loadcase_set
221
+ df_profile = df.loc[(df['Pipeline'] == pipeline_set) & (df['Loadcase Set'] == loadcase_set)]
222
+
223
+ # Select the 'Point ID From' and 'KP To' columns
224
+ df_route = df_route[['Point ID From', 'KP To']].reset_index(drop = True)
225
+
226
+ # Add the end row of route and the start KP
227
+ end_row = pd.DataFrame({'Point ID From': 'End', 'KP To': np.nan}, index = [99999])
228
+ df_route = pd.concat([df_route, end_row], ignore_index = True)
229
+
230
+ # Shift KP column 1 downwards and assign 0.0 to the first KP
231
+ df_route['KP To'] = df_route['KP To'].shift().fillna(0.0)
232
+
233
+ # Expand the KP array with 1000 intervals from 1000 to nearest maximum KP
234
+ df_route = calc_expand_kp(df_route, 'KP To')
235
+
236
+ # Create the elements between each KP points
237
+ elem_array = calc_element_array(df_route)
238
+
239
+ # Interpolate the RLT, pressure and temperature using KP and operating profile
240
+ df = calc_kp_interpolation(elem_array, df_profile)
241
+
242
+ # Insert pipeline_set and loadcase_set columns as the first and second columns
243
+ df.insert(0, 'Pipeline', [pipeline_set] * df.shape[0])
244
+ df.insert(1, 'Loadcase Set', [loadcase_set] * df.shape[0])
245
+
246
+ return df
247
+
248
+ def calc_densities(od, wt, coat_wt, steel_density, water_density, sw_empty, sw_inst, sw_oper):
249
+
250
+ '''
251
+ Calculate parameters of coating density, content density during operation and installation.
252
+
253
+ Parameters
254
+ ----------
255
+ od : float
256
+ Outer diameter
257
+ wt : float
258
+ Wall thickness
259
+ coat_wt : float
260
+ Coating wall thickness
261
+ steel_density : float
262
+ Steel density
263
+ water_density : float
264
+ Seawater density
265
+ sw_inst : float
266
+ Submerged weight during installation
267
+ sw_oper : float
268
+ Submerged weight during operation
269
+
270
+ Returns
271
+ -------
272
+ coat_density : float
273
+ Coating density
274
+ inst_density : float
275
+ Content density during installation
276
+ oper_density : float
277
+ Content density during operation
278
+ '''
279
+
280
+ pipe = ss.Pipe(
281
+ outer_diameter=od,
282
+ wall_thickness=wt,
283
+ coating_thickness=coat_wt
284
+ )
285
+
286
+ # Calculate area_inner, area_steel, area_tod and coat_area based on od, wt, coat_wt
287
+ area_inner = pipe.inner_area()
288
+ area_steel = pipe.steel_area()
289
+ area_tod = pipe.total_outer_area()
290
+ coat_area = pipe.coating_area()
291
+
292
+ # Calculate coat_density, inst_density and oper_density based on the given coat_wt,
293
+ # steel_density and water_density using the sw equations
294
+ coat_density = (sw_empty / 9.807 - (
295
+ steel_density * area_steel - water_density * area_tod)) / coat_area
296
+ inst_density = (sw_inst - sw_empty) / 9.807 / area_inner
297
+ oper_density = (sw_oper - sw_empty) / 9.807 / area_inner
298
+
299
+ # The coating density should not be much smaller than sea water
300
+ if coat_density < 0.0:
301
+ print("The coating density is negative. Change the COAT_WT.")
302
+ quit()
303
+
304
+ return coat_density, inst_density, oper_density
305
+
306
+ def calc_sets(df, index_max):
307
+
308
+ '''
309
+ Calculate the length and number of elements of each element set,
310
+ and calculate the property sets.
311
+
312
+ Parameters
313
+ ----------
314
+ df : Dataframe
315
+ Dataframe containing data from the BuckPy input file.
316
+ index_max : int
317
+ Largest index of the Dataframe containing data from
318
+ the BuckPy input file.
319
+
320
+ Returns
321
+ -------
322
+ df : Dataframe
323
+ Dataframe containing the Buckfast input file.
324
+ '''
325
+
326
+ # Calculate length and element number based on KP and index
327
+ df['KP Shift'] = df['KP'].shift(-1).fillna(df['KP To'].max())
328
+ df['Length'] = df['KP Shift'] - df['KP']
329
+ df['index_copy Shift'] = df['index_copy'].shift(-1).fillna(index_max)
330
+ df['No. Elements'] = df['index_copy Shift'] - df['index_copy']
331
+
332
+ # Calculate element and property set
333
+ df = df.reset_index(drop = True).reset_index()
334
+ df['Property Set'] = df['index'] + 1
335
+
336
+ return df
337
+
338
+ def calc_cbf_mean_std(route_type, od, wt, young_modulus, radius, height,
339
+ rcm, sw_hydr, sw_oper, mean_lat_hydr, std_lat_hydr,
340
+ mean_lat_oper, std_lat_oper, mean_oos, std_oos):
341
+
342
+ '''
343
+ Calculate the mean and std of the lognormal CBF distritution
344
+ during hydrotest and operation.
345
+
346
+ Parameters
347
+ ----------
348
+ route_type : string
349
+ Section type: 'STRAIGHT' or 'BEND' or 'SLEEPER'
350
+ od : float
351
+ Outer diameter
352
+ wt : float
353
+ Wall thickness
354
+ young_modulus : float
355
+ Young's modulus
356
+ radius : float
357
+ Bend radius
358
+ height : float
359
+ Sleeper height
360
+ rcm : float
361
+ RCM buckling force
362
+ sw_hydr : float
363
+ Submerged weight during hydrotest
364
+ sw_oper : float
365
+ Submerged weight during operation
366
+ mean_lat_hydr : float
367
+ Mean parameter of the lognormal friction distribution during hydrotest
368
+ std_lat_hydr : float
369
+ Standard deviation paramater of the lognormal friction distribution during hydrotest
370
+ mean_lat_oper : float
371
+ Mean parameter of the lognormal friction distribution during operation
372
+ std_lat_oper : float
373
+ Standard deviation paramater of the lognormal friction distribution during operation
374
+ mean_oos : float
375
+ Mean parameter of the lognormal OOS distribution
376
+ std_oos : float
377
+ Standard deviation paramater of the lognormal OOS distribution
378
+
379
+ Returns
380
+ -------
381
+ mean_cbf_hydr : float
382
+ Mean of the lognormal CBF distribution during hydrotest
383
+ std_cbf_hydr : float
384
+ Standard deviation of the lognormal CBF distribution during hydrotest
385
+ mean_cbf_oper : float
386
+ Mean of the lognormal CBF distribution during operation
387
+ std_cbf_oper : float
388
+ Standard deviation of the lognormal CBF distribution during operation
389
+ '''
390
+
391
+ pipe = ss.Pipe(
392
+ outer_diameter=od,
393
+ wall_thickness=wt,
394
+ youngs_modulus=young_modulus
395
+ )
396
+
397
+ # Calculate EA and EI from od, wt and E
398
+ ax_stiff = pipe.axial_stiffness()
399
+ bend_stiff = pipe.bending_stiffness()
400
+
401
+ # Calculate loc and scale from mean and std of OOS
402
+ loc_oos = np.log(mean_oos**2 / np.sqrt(mean_oos**2 + std_oos**2))
403
+ scale_oos = np.sqrt(np.log(1 + std_oos**2 / mean_oos**2))
404
+
405
+ # Calculate loc and scale from mean and std of hydrotest friction
406
+ loc_lat_hydr = np.log(mean_lat_hydr**2 / np.sqrt(mean_lat_hydr**2 + std_lat_hydr**2))
407
+ scale_lat_hydr = np.sqrt(np.log(1 + std_lat_hydr**2 / mean_lat_hydr**2))
408
+
409
+ # Calculate loc and scale from mean and std of operating friction
410
+ loc_lat_oper = np.log(mean_lat_oper**2 / np.sqrt(mean_lat_oper**2 + std_lat_oper**2))
411
+ scale_lat_oper = np.sqrt(np.log(1 + std_lat_oper**2 / mean_lat_oper**2))
412
+
413
+ # Calculate mean and std
414
+ loc_cbf_hydr, scale_cbf_hydr, mean_cbf_hydr, std_cbf_hydr = calc_cbf(
415
+ route_type, loc_lat_hydr, scale_lat_hydr, loc_oos,
416
+ scale_oos, ax_stiff, bend_stiff, sw_hydr, radius, height, rcm)
417
+ loc_cbf_oper, scale_cbf_oper, mean_cbf_oper, std_cbf_oper = calc_cbf(
418
+ route_type, loc_lat_oper, scale_lat_oper, loc_oos,
419
+ scale_oos, ax_stiff, bend_stiff, sw_oper, radius, height, rcm)
420
+
421
+ return mean_cbf_hydr, std_cbf_hydr, mean_cbf_oper, std_cbf_oper
422
+
423
+ def open_file():
424
+
425
+ '''
426
+ Read the data from the BuckPy input file.
427
+
428
+ Parameters
429
+ ----------
430
+ BUCKPY_EXCEL : string
431
+ File path of the BuckPy input file.
432
+ SCENARIO_NO : int
433
+ Scenario number of current simulation.
434
+
435
+ Returns
436
+ -------
437
+ df : Dataframe
438
+ Dataframe containing data from all the tabs in the BuckPy input file.
439
+ df_route_ends : Dataframe
440
+ Dataframe containing data from layout ends.
441
+ '''
442
+
443
+ # Read all tabs in the BuckPy input file
444
+ all_sheets_dict = pd.read_excel(rf'{WORK_DIR}\{BUCKPY_EXCEL}', sheet_name = None)
445
+
446
+ # Read 'Scenario' tab and select current scenario number
447
+ df_sce = all_sheets_dict['Scenario']
448
+ df_sce = df_sce.loc[(df_sce['Pipeline'] == PIPELINE_ID) &
449
+ (df_sce['Scenario'] == SCENARIO_NO)]
450
+ loadcase_set = df_sce['Loadcase Set'].iloc[0]
451
+
452
+ # Read 'Route' tab and convert KP from int to float to fix merge warning on dtype
453
+ df_route = all_sheets_dict['Route']
454
+ df_route[['KP From', 'KP To']] = df_route[['KP From', 'KP To']].astype(float)
455
+ df_route['Route Type'] = df_route['Route Type'].str.upper()
456
+ df_route = df_route.loc[(df_route['Pipeline'] == PIPELINE_ID) &
457
+ (df_route['Layout Set'].isin(df_sce['Layout Set']))]
458
+ df_route_ends = df_route.loc[((df_route['Route Type'] == 'SPOOL') |
459
+ (df_route['Route Type'] == 'FIXED'))]
460
+ df_route = df_route.loc[~((df_route['Route Type'] == 'SPOOL') |
461
+ (df_route['Route Type'] == 'FIXED'))]
462
+
463
+ # Read 'Pipe' tab
464
+ df_pipe = all_sheets_dict['Pipe']
465
+ df_pipe = df_pipe.loc[(df_pipe['Pipeline'] == PIPELINE_ID) &
466
+ (df_pipe['Pipe Set'].isin(df_route['Pipe Set']))]
467
+
468
+ # Read 'Soils' tab
469
+ df_soil = all_sheets_dict['Soils']
470
+ df_soil = df_soil.loc[(df_soil['Pipeline'] == PIPELINE_ID) &
471
+ (df_soil['Friction Set'].isin(df_route['Friction Set']))].copy()
472
+
473
+ # Calculate the mean and std of soil friction
474
+ # Axial
475
+ df_soil['Axial Mean'], df_soil['Axial STD'] = ss.LBDistributions(
476
+ friction_factor_le=df_soil['Axial LE'],
477
+ friction_factor_be=df_soil['Axial BE'],
478
+ friction_factor_he=df_soil['Axial HE'],
479
+ friction_factor_fit_type=df_soil['Axial Fit Bounds']
480
+ ).friction_distribution()[:2]
481
+ # Lateral Hydrotest
482
+ df_soil['Lateral Hydrotest Mean'], df_soil['Lateral Hydrotest STD'] = ss.LBDistributions(
483
+ friction_factor_le=df_soil['Lateral Hydrotest LE'],
484
+ friction_factor_be=df_soil['Lateral Hydrotest BE'],
485
+ friction_factor_he=df_soil['Lateral Hydrotest HE'],
486
+ friction_factor_fit_type=df_soil['Lateral Hydrotest Fit Bounds']
487
+ ).friction_distribution()[:2]
488
+ # Lateral Operation
489
+ df_soil['Lateral Operation Mean'], df_soil['Lateral Operation STD'] = ss.LBDistributions(
490
+ friction_factor_le=df_soil['Lateral Operation LE'],
491
+ friction_factor_be=df_soil['Lateral Operation BE'],
492
+ friction_factor_he=df_soil['Lateral Operation HE'],
493
+ friction_factor_fit_type=df_soil['Lateral Operation Fit Bounds']
494
+ ).friction_distribution()[:2]
495
+
496
+ # Read 'Operating' tab and filter the operating profile for the current scenario
497
+ df_oper = all_sheets_dict['Operating']
498
+ df_oper = df_oper.loc[(df_oper['Pipeline'] == PIPELINE_ID) &
499
+ (df_oper['Loadcase Set'].isin(df_sce['Loadcase Set']))]
500
+ df_oper = calc_operating_profiles(df_oper, df_route, PIPELINE_ID, loadcase_set)
501
+
502
+ # Read 'Post-Processing' tab
503
+ df_pp = all_sheets_dict['Post-Processing']
504
+ df_pp = df_pp.loc[(df_pp['Pipeline'] == PIPELINE_ID) &
505
+ (df_pp['Layout Set'].isin(df_sce['Layout Set']))]
506
+ df_pp = df_pp[['Pipeline', 'Layout Set', 'Post-Processing Set', 'KP From', 'KP To']]
507
+
508
+ # Merge df_sce and df_route on 'Pipeline' and 'Layout Set'
509
+ df = pd.merge(df_sce, df_route, on = ['Pipeline', 'Layout Set'], how = 'left')
510
+
511
+ # Merge df and df_pipe on 'Pipeline' and 'Pipe Set'
512
+ df = pd.merge(df, df_pipe, on = ['Pipeline', 'Pipe Set'], how = 'left')
513
+
514
+ # Merge df and df_soil on 'Pipeline' and 'Friction Set'
515
+ df = pd.merge(df, df_soil, on = ['Pipeline', 'Friction Set'], how = 'left')
516
+
517
+ # Merge df and df_oper on 'Pipeline', 'Loadcase Set' and 'KP From'/'KP'
518
+ df = pd.merge(df, df_oper, left_on = ['Pipeline', 'Loadcase Set', 'KP From'],
519
+ right_on = ['Pipeline', 'Loadcase Set', 'KP'], how = 'right')
520
+
521
+ # Concatenate df and df_pp
522
+ for index, row in df.iterrows():
523
+ if df_pp.loc[df_pp['KP From'] == row['KP'], 'Post-Processing Set'].size > 0:
524
+ df.loc[index, 'Element Set'] = df_pp.loc[df_pp['KP From'] == row['KP'],
525
+ 'Post-Processing Set'].iloc[0]
526
+ df.loc[index, 'Counter'] = index
527
+ if row['KP From'] > 0.0:
528
+ df.loc[index, 'Counter'] = index
529
+
530
+ # Forward fill df
531
+ df = df.ffill()
532
+
533
+ # Add property values that do not change
534
+ df['water_density'] = WATER_DENSITY
535
+ df['axial_fric_dist'] = AXIAL_FRIC_DIST
536
+ df['coat_wt'] = COAT_WT
537
+ df['steel_density'] = STEEL_DENSITY
538
+ df['coat_layer'] = COAT_LAYER
539
+ df['cbf_no'] = CBF_NO
540
+ df['RLT'] = abs(df['RLT'])
541
+
542
+ # Re-assign to the sets ascending numbers starting from zero, considering duplicates
543
+ df['Layout Set'] = df['Layout Set'].rank(method = 'dense').astype(int)
544
+ df['Pipe Set'] = df['Pipe Set'].rank(method = 'dense').astype(int)
545
+ df['Friction Set'] = df['Friction Set'].rank(method = 'dense').astype(int)
546
+ df['Loadcase Set'] = df['Loadcase Set'].rank(method = 'dense').astype(int)
547
+
548
+ return df, df_route_ends
549
+
550
+ def func_heading(df_in):
551
+
552
+ '''
553
+ Create the Buckfast input file and add the *HEADING section.
554
+
555
+ Parameters
556
+ ----------
557
+ df_in : Dataframe
558
+ Dataframe containing data from the BuckPy input file.
559
+
560
+ Returns
561
+ -------
562
+ df_out : Dataframe
563
+ Dataframe containing the Buckfast input file.
564
+ '''
565
+
566
+ # Create the Buckfast input file and add the *HEADING section
567
+ full_description = (f"{DESCRIPTION} - Pipeline {df_in['Pipeline'].iloc[0]} - "
568
+ f"Scenario {int(df_in['Scenario'].iloc[0])}")
569
+ df_out = pd.DataFrame({
570
+ 'Col_1': np.append('*HEADING', full_description)
571
+ })
572
+
573
+ return df_out
574
+
575
+ def func_simulations(df_in, df_out):
576
+
577
+ '''
578
+ Add the *SIMULATIONS section to the Buckfast input file.
579
+
580
+ Parameters
581
+ ----------
582
+ df_in : Dataframe
583
+ Dataframe containing data from the BuckPy input file.
584
+ df_out : Dataframe
585
+ Dataframe containing the Buckfast input file.
586
+
587
+ Returns
588
+ -------
589
+ df_out : Dataframe
590
+ Dataframe containing the Buckfast input file.
591
+ '''
592
+
593
+ # Create a dataframe for the *SIMULATIONS section
594
+ df_out_temp = pd.DataFrame({
595
+ 'Col_1': np.append('*SIMULATIONS', int(df_in['Simulations'].iloc[0]))
596
+ })
597
+
598
+ # Add the *SIMULATIONS section to the Buckfast input file
599
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
600
+
601
+ return df_out
602
+
603
+ def func_water(df_in, df_out):
604
+
605
+ '''
606
+ Add the *WATER section to the Buckfast input file.
607
+
608
+ Parameters
609
+ ----------
610
+ df_in : Dataframe
611
+ Dataframe containing data from the BuckPy input file.
612
+ df_out : Dataframe
613
+ Dataframe containing the Buckfast input file.
614
+
615
+ Returns
616
+ -------
617
+ df_out : Dataframe
618
+ Dataframe containing the Buckfast input file.
619
+ '''
620
+
621
+ # Create a dataframe for the *WATER section
622
+ df_out_temp = pd.DataFrame({
623
+ 'Col_1': np.append('*WATER', df_in['Temperature Installation'].iloc[0]),
624
+ 'Col_2': np.append(np.nan, df_in['water_density'].iloc[0])
625
+ })
626
+
627
+ # Add the *WATER section to the Buckfast input file
628
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
629
+
630
+ return df_out
631
+
632
+ def func_friction(df_in, df_out):
633
+
634
+ '''
635
+ Add the *AXIALFRICTION section to the Buckfast input file.
636
+
637
+ Parameters
638
+ ----------
639
+ df_in : Dataframe
640
+ Dataframe containing data from the BuckPy input file.
641
+ df_out : Dataframe
642
+ Dataframe containing the Buckfast input file.
643
+
644
+ Returns
645
+ -------
646
+ df_out : Dataframe
647
+ Dataframe containing the Buckfast input file.
648
+ '''
649
+
650
+ # Select the unique 'Friction Set'
651
+ df_in = df_in.dropna(subset = 'Friction Set')
652
+ df_in = df_in.drop_duplicates(subset = 'Friction Set')
653
+
654
+ # Create a dataframe for the title of the *AXIALFRICTION section
655
+ df_out_title = pd.DataFrame({
656
+ 'Col_1': ['*AXIALFRICTION']
657
+ })
658
+
659
+ # Create a dataframe for the first line of the *AXIALFRICTION section
660
+ df_out_first_line = pd.DataFrame({
661
+ 'Col_1': df_in['axial_fric_dist'],
662
+ 'Col_2': df_in['Axial Mean'],
663
+ 'Col_3': df_in['Axial STD'],
664
+ 'Col_4': df_in['Friction Set'].astype(int).astype(str)
665
+ })
666
+
667
+ # Create a dataframe for all the rows of the *AXIALFRICTION section
668
+ df_out_temp = pd.concat([df_out_title, df_out_first_line])
669
+
670
+ # Add the *AXIALFRICTION section to the Buckfast input file
671
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
672
+
673
+ return df_out
674
+
675
+ def func_single(df_in, df_out):
676
+
677
+ '''
678
+ Add the *SINGLE section to the Buckfast input file.
679
+
680
+ Parameters
681
+ ----------
682
+ df_in : Dataframe
683
+ Dataframe containing data from the BuckPy input file.
684
+ df_out : Dataframe
685
+ Dataframe containing the Buckfast input file.
686
+
687
+ Returns
688
+ -------
689
+ df_out : Dataframe
690
+ Dataframe containing the Buckfast input file.
691
+ '''
692
+
693
+ # Select the unique 'Pipe Set'
694
+ df_in = df_in.dropna(subset = 'Pipe Set')
695
+ df_in = df_in.drop_duplicates(subset = 'Pipe Set')
696
+
697
+ # Calculate the coating density, content density during hydrotest and operation
698
+ df_in[['coat_density', 'inst_density', 'oper_density']] = df_in.apply(
699
+ lambda row: pd.Series(calc_densities(
700
+ row['OD'], row['WT'], row['coat_wt'], row['steel_density'], row['water_density'],
701
+ row['sw Empty'], row['sw Installation'], row['sw Operation'])), axis = 1)
702
+
703
+ # Use the equivalent pipe properties of a single pipe for pipe-in-pipe and convert unit to mm
704
+ df_in[['OD', 'WT']] = df_in[['OD', 'WT']] * 1000.0
705
+ df_in['E'] = df_in['E'] / 1.0E+06
706
+
707
+ # Create a dataframe for the title of the *SINGLE section
708
+ df_out_title = pd.DataFrame({
709
+ 'Col_1': ['*SINGLE']
710
+ })
711
+
712
+ # Create a dataframe for the first rows of the *SINGLE section
713
+ df_out_first_line = pd.DataFrame({
714
+ 'Col_1': df_in['OD'],
715
+ 'Col_2': df_in['WT'],
716
+ 'Col_3': df_in['steel_density'],
717
+ 'Col_4': df_in['coat_layer'].astype(int).astype(str),
718
+ 'Col_5': df_in['E'],
719
+ 'Col_6': df_in['Poisson'],
720
+ 'Col_7': df_in['Alpha'],
721
+ 'Col_8': df_in['oper_density'],
722
+ 'Col_9': df_in['inst_density'],
723
+ 'Col_10': df_in['Pipe Set'].astype(int).astype(str)
724
+ })
725
+
726
+ # Create a dataframe for the second rows of the *SINGLE section
727
+ df_out_second_line = pd.DataFrame({
728
+ 'Col_1': 1000.0 * df_in['coat_wt'],
729
+ 'Col_2': df_in['coat_density']
730
+ })
731
+
732
+ # Create a dataframe for all the rows of the *SINGLE section
733
+ df_out_temp = pd.concat([df_out_title, df_out_first_line, df_out_second_line])
734
+ df_out_temp = df_out_temp.sort_index()
735
+
736
+ # Add the *SINGLE section to the Buckfast input file
737
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
738
+
739
+ return df_out
740
+
741
+ def func_installation(df_in, df_out):
742
+
743
+ '''
744
+ Add the *INSTALLATION section to the Buckfast input file.
745
+
746
+ Parameters
747
+ ----------
748
+ df_in : Dataframe
749
+ Dataframe containing data from the BuckPy input file.
750
+ df_out : Dataframe
751
+ Dataframe containing the Buckfast input file.
752
+
753
+ Returns
754
+ -------
755
+ df_out : Dataframe
756
+ Dataframe containing the Buckfast input file.
757
+ '''
758
+
759
+ # Convert unit to N*mm^(-2)
760
+ df_in.loc[:, 'Pressure Installation'] = df_in['Pressure Installation'] / 1.0E+06
761
+
762
+ # Create a dataframe for the title of the *INSTALLATION section
763
+ df_out_title = pd.DataFrame({
764
+ 'Col_1': ['*INSTALLATION']
765
+ })
766
+
767
+ # Create a dataframe for the first row of the *INSTALLATION section
768
+ df_out_first_line = pd.DataFrame({
769
+ 'Col_1': ['LAYTENSION', 'PRESSURE', 'TEMPERATURE'],
770
+ 'Col_2': 'TABULAR',
771
+ 'Col_3': [df_in['RLT'].iloc[0], df_in['Pressure Installation'].iloc[0],
772
+ df_in['Temperature Installation'].iloc[0]],
773
+ 'Col_4': [df_in['RLT'].iloc[-1], df_in['Pressure Installation'].iloc[-1],
774
+ df_in['Temperature Installation'].iloc[-1]]
775
+ })
776
+
777
+ # Create a dataframe for all the rows of the *INSTALLATION section
778
+ df_out_temp = pd.concat([df_out_title, df_out_first_line])
779
+
780
+ # Add the *INSTALLATION section to the Buckfast input file
781
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
782
+
783
+ return df_out
784
+
785
+ def func_hydrotest(df_in, df_out):
786
+
787
+ '''
788
+ Add the *HYDROTEST section to the Buckfast input file.
789
+
790
+ Parameters
791
+ ----------
792
+ df_in : Dataframe
793
+ Dataframe containing data from the BuckPy input file.
794
+ df_out : Dataframe
795
+ Dataframe containing the Buckfast input file.
796
+
797
+ Returns
798
+ -------
799
+ df_out : Dataframe
800
+ Dataframe containing the Buckfast input file.
801
+ '''
802
+
803
+ # Convert unit to N*mm^(-2)
804
+ df_in.loc[:, 'Pressure Hydrotest'] = df_in['Pressure Hydrotest'] / 1.0E+06
805
+
806
+ # Create a dataframe for the title of the *HYDROTEST section
807
+ df_out_title = pd.DataFrame({
808
+ 'Col_1': ['*HYDROTEST']
809
+ })
810
+
811
+ # Create a dataframe for the first row of the *HYDROTEST section
812
+ df_out_first_line = pd.DataFrame({
813
+ 'Col_1': ['PRESSURE', 'TEMPERATURE'],
814
+ 'Col_2': 'TABULAR',
815
+ 'Col_3': [df_in['Pressure Hydrotest'].iloc[0], df_in['Temperature Hydrotest'].iloc[0]],
816
+ 'Col_4': [df_in['Pressure Hydrotest'].iloc[-1], df_in['Temperature Hydrotest'].iloc[-1]]
817
+ })
818
+
819
+ # Create a dataframe for all the rows of the *HYDROTEST section
820
+ df_out_temp = pd.concat([df_out_title, df_out_first_line])
821
+
822
+ # Add the *HYDROTEST section to the Buckfast input file
823
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
824
+
825
+ return df_out
826
+
827
+ def func_operation(df_in, df_out):
828
+
829
+ '''
830
+ Add the *OPERATION section to the Buckfast input file.
831
+
832
+ Parameters
833
+ ----------
834
+ df_in : Dataframe
835
+ Dataframe containing data from the BuckPy input file.
836
+ df_out : Dataframe
837
+ Dataframe containing the Buckfast input file.
838
+
839
+ Returns
840
+ -------
841
+ df_out : Dataframe
842
+ Dataframe containing the Buckfast input file.
843
+ '''
844
+
845
+ # Convert unit to N*mm^(-2)
846
+ df_in.loc[:, 'Pressure Operation'] = df_in['Pressure Operation'] / 1.0E+06
847
+
848
+ # Create a dataframe for the title of the *OPERATION section
849
+ df_out_title = pd.DataFrame({
850
+ 'Col_1': ['*OPERATION']
851
+ })
852
+
853
+ # Create a dataframe for the first row of the *OPERATION section
854
+ df_out_first_line = pd.DataFrame({
855
+ 'Col_1': ['PRESSURE', 'TEMPERATURE'],
856
+ 'Col_2': 'TABULAR',
857
+ 'Col_3': [df_in['Pressure Operation'].iloc[0], df_in['Temperature Operation'].iloc[0]],
858
+ 'Col_4': [df_in['Pressure Operation'].iloc[-1], df_in['Temperature Operation'].iloc[-1]]
859
+ })
860
+
861
+ # Create a dataframe for all the rows of the *OPERATION section
862
+ df_out_temp = pd.concat([df_out_title, df_out_first_line])
863
+
864
+ # Add the *OPERATION section to the Buckfast input file
865
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
866
+
867
+ return df_out
868
+
869
+ def func_route(df_in, df_out):
870
+
871
+ '''
872
+ Add the *ROUTE section to the Buckfast input file.
873
+
874
+ Parameters
875
+ ----------
876
+ df_in : Dataframe
877
+ Dataframe containing data from the BuckPy input file.
878
+ df_out : Dataframe
879
+ Dataframe containing the Buckfast input file.
880
+
881
+ Returns
882
+ -------
883
+ df_out : Dataframe
884
+ Dataframe containing the Buckfast input file.
885
+ '''
886
+
887
+ # Copy the index of the entire input DataFrame
888
+ df_in = df_in.reset_index()
889
+ df_in['index_copy'] = df_in['index']
890
+ df_in = df_in.drop(labels = 'index', axis = 1)
891
+
892
+ # Select rows for the long lines of *ROUTE second line
893
+ df_in_long_line = df_in.copy().drop_duplicates(subset = ['Counter'],
894
+ keep = 'first')
895
+
896
+ index_list = df_in_long_line.index
897
+ df_in_long_line = calc_sets(df_in_long_line, df_in['index_copy'].max())
898
+ df_in_long_line_copy = df_in_long_line.copy()
899
+
900
+ # Replace "RCM" in "Route Type" column to "SLEEPER"
901
+ df_in_long_line['Route Type'] = df_in_long_line['Route Type'].replace("RCM", "SLEEPER")
902
+
903
+ # Select rows for the short line of *ROUTE second line
904
+ df_in_short_line = df_in.loc[~df_in['index_copy'].isin(index_list)].iloc[:-1]
905
+
906
+ # Create a dataframe for the title of the *ROUTE section
907
+ df_out_title = pd.DataFrame({
908
+ 'Col_1': ['*ROUTE']
909
+ })
910
+
911
+ # Create a dataframe for the first line of the *ROUTE section
912
+ df_out_first_line = pd.DataFrame({
913
+ 'Col_1': ['END'],
914
+ 'Col_2': ['0'],
915
+ 'Col_3': ['1'],
916
+ 'Col_4': ['1'],
917
+ 'Col_5': [f"{df_in['Friction Set'].iloc[0]:.0f}"],
918
+ 'Col_6': [f"{df_in['Pipe Set'].iloc[0]:.0f}"],
919
+ 'Col_7': ['0'],
920
+ 'Col_8': [df_in['RLT'].iloc[0]],
921
+ 'Col_9': [df_in['Pressure Installation'].iloc[0]],
922
+ 'Col_10': [df_in['Temperature Installation'].iloc[0]],
923
+ 'Col_11': [df_in['Pressure Hydrotest'].iloc[0]],
924
+ 'Col_12': [df_in['Temperature Hydrotest'].iloc[0]],
925
+ 'Col_13': [df_in['Pressure Operation'].iloc[0]],
926
+ 'Col_14': [df_in['Temperature Operation'].iloc[0]]
927
+ })
928
+
929
+ # Create a dataframe for the first line of the *ROUTE section and use original index
930
+ df_out_second_line_1 = pd.DataFrame({
931
+ 'Col_1': df_in_long_line['Route Type'],
932
+ 'Col_2': df_in_long_line['Length'].astype(int).astype(str),
933
+ 'Col_3': df_in_long_line['No. Elements'].astype(int).astype(str),
934
+ 'Col_4': df_in_long_line['Property Set'].astype(int).astype(str),
935
+ 'Col_5': df_in_long_line['Friction Set'].astype(int).astype(str),
936
+ 'Col_6': df_in_long_line['Pipe Set'].astype(int).astype(str),
937
+ 'Col_7': df_in_long_line['Element Set'].astype(int).astype(str),
938
+ 'Col_8': df_in_long_line['RLT'],
939
+ 'Col_9': df_in_long_line['Pressure Installation'],
940
+ 'Col_10': df_in_long_line['Temperature Installation'],
941
+ 'Col_11': df_in_long_line['Pressure Hydrotest'],
942
+ 'Col_12': df_in_long_line['Temperature Hydrotest'],
943
+ 'Col_13': df_in_long_line['Pressure Operation'],
944
+ 'Col_14': df_in_long_line['Temperature Operation']
945
+ })
946
+ df_out_second_line_1.set_index([pd.Series(df_in_long_line['index_copy'])], inplace = True)
947
+
948
+ # Create a dataframe for the second rows of the *ROUTE section
949
+ df_out_second_line_2 = pd.DataFrame({
950
+ 'Col_1': df_in_short_line['RLT'],
951
+ 'Col_2': df_in_short_line['Pressure Installation'],
952
+ 'Col_3': df_in_short_line['Temperature Installation'],
953
+ 'Col_4': df_in_short_line['Pressure Hydrotest'],
954
+ 'Col_5': df_in_short_line['Temperature Hydrotest'],
955
+ 'Col_6': df_in_short_line['Pressure Operation'],
956
+ 'Col_7': df_in_short_line['Temperature Operation']
957
+ })
958
+
959
+ # Create a dataframe for the first line of the *ROUTE section and set index to a large int
960
+ df_out_last_line = pd.DataFrame({
961
+ 'Col_1': ['END'],
962
+ 'Col_2': ['0'],
963
+ 'Col_3': ['1'],
964
+ 'Col_4': ['2'],
965
+ 'Col_5': [f"{df_in['Friction Set'].iloc[-1]:.0f}"],
966
+ 'Col_6': [f"{df_in['Pipe Set'].iloc[-1]:.0f}"],
967
+ 'Col_7': ['0'],
968
+ 'Col_8': [df_in['RLT'].iloc[-1]],
969
+ 'Col_9': [df_in['Pressure Installation'].iloc[-1]],
970
+ 'Col_10': [df_in['Temperature Installation'].iloc[-1]],
971
+ 'Col_11': [df_in['Pressure Hydrotest'].iloc[-1]],
972
+ 'Col_12': [df_in['Temperature Hydrotest'].iloc[-1]],
973
+ 'Col_13': [df_in['Pressure Operation'].iloc[-1]],
974
+ 'Col_14': [df_in['Temperature Operation'].iloc[-1]]
975
+ })
976
+ df_out_last_line.index = [99999]
977
+
978
+ # Create a dataframe for all the rows of the *ROUTE section
979
+ df_out_temp = pd.concat([df_out_title, df_out_first_line, df_out_second_line_1,
980
+ df_out_second_line_2, df_out_last_line])
981
+ df_out_temp = df_out_temp.sort_index()
982
+
983
+ # Add the *ROUTE section to the Buckfast input file
984
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
985
+
986
+ return df_in_long_line_copy, df_out
987
+
988
+ def func_type(df_in, df_in_end, df_out):
989
+
990
+ '''
991
+ Add the *TYPE section to the Buckfast input file.
992
+
993
+ Parameters
994
+ ----------
995
+ df_in : Dataframe
996
+ Dataframe containing data from the BuckPy input file.
997
+ df_in_end : Dataframe
998
+ Dataframe containing data from the route ends of the BuckPy input file.
999
+ df_out : Dataframe
1000
+ Dataframe containing the Buckfast input file.
1001
+
1002
+ Returns
1003
+ -------
1004
+ df_out : Dataframe
1005
+ Dataframe containing the Buckfast input file.
1006
+ '''
1007
+
1008
+ # Calculate property set
1009
+ # df_in['Route Type'] = df_in['Route Type'].str.capitalize() #! Use UPPER case always
1010
+ df_in_second_line = df_in
1011
+
1012
+ # Calculate cbf mean, cbf std, residual force and residual length
1013
+ df_in_second_line[['mean_cbf_hydr', 'std_cbf_hydr', 'mean_cbf_oper', 'std_cbf_oper']] = \
1014
+ df_in_second_line.apply(lambda row: pd.Series(calc_cbf_mean_std(
1015
+ row['Route Type'], row['OD'], row['WT'], row['E'], row['Bend Radius'],
1016
+ row['Sleeper Height'], row['RCM Buckling Force'], row['sw Hydrotest'],
1017
+ row['sw Operation'], row['Lateral Hydrotest Mean'], row['Lateral Hydrotest STD'],
1018
+ row['Lateral Operation Mean'], row['Lateral Operation STD'], row['HOOS Mean'],
1019
+ row['HOOS STD'])), axis = 1)
1020
+
1021
+ # Replace "RCM" in "Route Type" column to "SLEEPER"
1022
+ df_in_second_line['Route Type'] = df_in_second_line['Route Type'].replace("RCM", "SLEEPER")
1023
+
1024
+ # Create a dataframe for the title of the *TYPE section
1025
+ df_out_title = pd.DataFrame({
1026
+ 'Col_1': ['*TYPE']
1027
+ })
1028
+
1029
+ # Create a dataframe for the first line of the *TYPE section
1030
+ df_out_first_line = pd.DataFrame({
1031
+ 'Col_1': ['END'],
1032
+ 'Col_2': ['1'],
1033
+ 'Col_3': df_in_end['Route Type'].iloc[0],
1034
+ 'Col_4': f"{-1*df_in_end['Reaction Installation'].iloc[0]:.0f}",
1035
+ 'Col_5': f"{-1*df_in_end['Reaction Hydrotest'].iloc[0]:.0f}",
1036
+ 'Col_6': f"{-1*df_in_end['Reaction Operation'].iloc[0]:.0f}"
1037
+ })
1038
+
1039
+ # Create a dataframe for the rows in second line of the *TYPE section
1040
+ df_out_second_line = pd.DataFrame({
1041
+ 'Col_1': df_in_second_line['Route Type'].str.upper(),
1042
+ 'Col_2': df_in_second_line['Property Set'].astype(int).astype(str),
1043
+ 'Col_3': df_in_second_line['cbf_no'].astype(int).astype(str),
1044
+ 'Col_4': CBF_DIST,
1045
+ 'Col_5': -1*df_in_second_line['mean_cbf_hydr'],
1046
+ 'Col_6': df_in_second_line['std_cbf_hydr'],
1047
+ 'Col_7': df_in_second_line['HOOS Reference Length'].astype(int).astype(str),
1048
+ 'Col_8': (-1*df_in_second_line['Residual Buckle Force Hydrotest']
1049
+ ).astype(int).astype(str),
1050
+ 'Col_9': df_in_second_line['Residual Buckle Length Hydrotest'].astype(int).astype(str),
1051
+ 'Col_10': CBF_DIST,
1052
+ 'Col_11': -1*df_in_second_line['mean_cbf_oper'],
1053
+ 'Col_12': df_in_second_line['std_cbf_oper'],
1054
+ 'Col_13': df_in_second_line['HOOS Reference Length'].astype(int).astype(str),
1055
+ 'Col_14': (-1*df_in_second_line['Residual Buckle Force Operation']
1056
+ ).astype(int).astype(str),
1057
+ 'Col_15': df_in_second_line['Residual Buckle Length Operation'].astype(int).astype(str)
1058
+ })
1059
+
1060
+ # Create a dataframe for the last line of the *TYPE section
1061
+ df_out_third_line = pd.DataFrame({
1062
+ 'Col_1': ['END'],
1063
+ 'Col_2': ['2'],
1064
+ 'Col_3': df_in_end['Route Type'].iloc[-1],
1065
+ 'Col_4': f"{-1*df_in_end['Reaction Installation'].iloc[-1]:.0f}",
1066
+ 'Col_5': f"{-1*df_in_end['Reaction Hydrotest'].iloc[-1]:.0f}",
1067
+ 'Col_6': f"{-1*df_in_end['Reaction Operation'].iloc[-1]:.0f}"
1068
+ })
1069
+ df_out_third_line.index = [99999]
1070
+
1071
+ # Create a dataframe for all the rows of the *TYPE section
1072
+ df_out_temp = pd.concat([df_out_title, df_out_first_line,
1073
+ df_out_second_line, df_out_third_line])
1074
+
1075
+ # Add the *TYPE section to the Buckfast input file
1076
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
1077
+
1078
+ return df_out
1079
+
1080
+ def func_output(df_out):
1081
+
1082
+ '''
1083
+ Add the *OUTPUT section to the Buckfast input file.
1084
+
1085
+ Parameters
1086
+ ----------
1087
+ df_out : Dataframe
1088
+ Dataframe containing the Buckfast input file.
1089
+
1090
+ Returns
1091
+ -------
1092
+ df_out : Dataframe
1093
+ Dataframe containing the Buckfast input file.
1094
+ '''
1095
+
1096
+ # Create a dataframe for the title of the *OUTPUT section
1097
+ df_out_title = pd.DataFrame({
1098
+ 'Col_1': ['*OUTPUT']
1099
+ })
1100
+
1101
+ # Create a dataframe for the first line of the *OUTPUT section
1102
+ if DEFAULT_OUTPUT:
1103
+ df_out_first_line = pd.DataFrame({
1104
+ 'Col_1': ['0.01'],
1105
+ 'Col_2': ['0.10'],
1106
+ 'Col_3': ['200'],
1107
+ 'Col_4': ['0'],
1108
+ 'Col_5': ['10000'],
1109
+ 'Col_6': ['-1'],
1110
+ 'Col_7': ['0'],
1111
+ 'Col_8': ['0'],
1112
+ 'Col_9': ['1'],
1113
+ 'Col_10': ['-1.0E+07'],
1114
+ 'Col_11': ['0'],
1115
+ })
1116
+ else: # Self defined values of the *OUTPUT section
1117
+ df_out_first_line = pd.DataFrame({
1118
+ 'Col_1': ['0.01'],
1119
+ 'Col_2': ['0.10'],
1120
+ 'Col_3': ['200'],
1121
+ 'Col_4': ['0'],
1122
+ 'Col_5': ['10000'],
1123
+ 'Col_6': ['-10'],
1124
+ 'Col_7': ['0'],
1125
+ 'Col_8': ['0'],
1126
+ 'Col_9': ['10'],
1127
+ 'Col_10': ['-4.0E+06'],
1128
+ 'Col_11': ['0'],
1129
+ })
1130
+
1131
+ # Create a dataframe for all the rows of the *OUTPUT section
1132
+ df_out_temp = pd.concat([df_out_title, df_out_first_line])
1133
+
1134
+ # Add the *OUTPUT section to the Buckfast input file
1135
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
1136
+ return df_out
1137
+
1138
+ def func_end(df_out):
1139
+
1140
+ '''
1141
+ Add the *END section to the Buckfast input file.
1142
+
1143
+ Parameters
1144
+ ----------
1145
+ df_out : Dataframe
1146
+ Dataframe containing the Buckfast input file.
1147
+
1148
+ Returns
1149
+ -------
1150
+ df_out : Dataframe
1151
+ Dataframe containing the Buckfast input file.
1152
+ '''
1153
+
1154
+ # Create a dataframe for the row of the *END section
1155
+ df_out_temp = pd.DataFrame({
1156
+ 'Col_1': ['*END']
1157
+ })
1158
+
1159
+ # Add the *END section to the Buckfast input file
1160
+ df_out = pd.concat([df_out, df_out_temp], ignore_index = True)
1161
+ return df_out
1162
+
1163
+ #################################################
1164
+ # Main
1165
+ #################################################
1166
+
1167
+ WORK_DIR = r'C:\Users\DIDCOA005681\OneDrive - Saipem\Documents\__Projects\02 - B58\Simulations\Buckfast' # The BuckPy working directory
1168
+ BUCKPY_EXCEL = 'buckpy_B58_current_PR300_scen3_buckfast.xlsx' # The BuckPy Excel template file
1169
+ DESCRIPTION = 'B58' # Description of the BuckPy project
1170
+ PIPELINE_LIST = ['PR300'] # Pipeline IDs, ['A', 'B']
1171
+ SCENARIO_LISTS = [[3]] # Scenario numbers for each pipeline, [[1,2], [1,2]]
1172
+
1173
+ # Switch to use default values of *OUTPUT section
1174
+ DEFAULT_OUTPUT = True # True or False
1175
+
1176
+ # Define essential parameters
1177
+ WATER_DENSITY = 1025 # Unit: kg/m^3
1178
+ AXIAL_FRIC_DIST = 'LOGNORMAL' # Distribution type for axial friction, NORMAL or LOGNORMAL
1179
+ COAT_WT = 0.3 # Thickness of the external coating, unit: mm
1180
+ STEEL_DENSITY = 7850 # Density of steel, unit: kg/m^3
1181
+ COAT_LAYER = 1 # Number of layers of external coating
1182
+ CBF_NO = 2 # Number of critical buckling force distribution, 1 or 2
1183
+ CBF_DIST = 'LOGNORMAL' # Distribution type for critical buckling force, NORMAL or LOGNORMAL
1184
+
1185
+ for index, PIPELINE_ID in enumerate(PIPELINE_LIST):
1186
+
1187
+ SCENARIO_LIST = SCENARIO_LISTS[index]
1188
+ for SCENARIO_NO in SCENARIO_LIST:
1189
+
1190
+ OUTPUT_CSV_NAME = f'buckfast_{PIPELINE_ID}_scen{SCENARIO_NO}.csv'
1191
+ print(f'Writing Buckfast input file: {OUTPUT_CSV_NAME}')
1192
+
1193
+ # Read the BuckPy input file into a dataframe
1194
+ df_input, df_input_ends = open_file()
1195
+
1196
+ # Add the *HEADING section to the Buckfast input file
1197
+ df_output = func_heading(df_input)
1198
+
1199
+ # Add the *SIMULATIONS section to the Buckfast input file
1200
+ df_output = func_simulations(df_input, df_output)
1201
+
1202
+ # Add the *WATER section to the Buckfast input file
1203
+ df_output = func_water(df_input, df_output)
1204
+
1205
+ # Add the *AXIALFRICTION section to the Buckfast input file
1206
+ df_output = func_friction(df_input, df_output)
1207
+
1208
+ # Add the *SINGLE section to the Buckfast input file
1209
+ df_output = func_single(df_input, df_output)
1210
+
1211
+ # Add the *INSTALLATION section to the Buckfast input file
1212
+ df_output = func_installation(df_input, df_output)
1213
+
1214
+ # Add the *HYDROTEST section to the Buckfast input file
1215
+ df_output = func_hydrotest(df_input, df_output)
1216
+
1217
+ # Add the *OPERATION section to the Buckfast input file
1218
+ df_output = func_operation(df_input, df_output)
1219
+
1220
+ # Add the *ROUTE section to the Buckfast input file
1221
+ df_input_type, df_output = func_route(df_input, df_output)
1222
+
1223
+ # Add the *TYPE section to the Buckfast input file
1224
+ df_output = func_type(df_input_type, df_input_ends, df_output)
1225
+
1226
+ # Add the *OUTPUT section to the Buckfast input file
1227
+ df_output = func_output(df_output)
1228
+
1229
+ # Add the *END section to the Buckfast input file
1230
+ df_output = func_end(df_output)
1231
+
1232
+ # Write Buckfast input file
1233
+ df_output.to_csv(rf'{WORK_DIR}\{OUTPUT_CSV_NAME}', index = False, header = False)