completor 0.1.3__py3-none-any.whl → 1.0.0__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.
- completor/completion.py +152 -542
- completor/constants.py +223 -150
- completor/create_output.py +559 -431
- completor/exceptions/exceptions.py +6 -6
- completor/get_version.py +8 -0
- completor/hook_implementations/jobs.py +2 -3
- completor/input_validation.py +53 -41
- completor/launch_args_parser.py +7 -12
- completor/logger.py +3 -3
- completor/main.py +102 -360
- completor/parse.py +104 -93
- completor/prepare_outputs.py +593 -457
- completor/read_casefile.py +248 -197
- completor/read_schedule.py +317 -14
- completor/utils.py +256 -25
- completor/visualization.py +1 -14
- completor/visualize_well.py +29 -27
- completor/wells.py +273 -0
- {completor-0.1.3.dist-info → completor-1.0.0.dist-info}/METADATA +10 -11
- completor-1.0.0.dist-info/RECORD +27 -0
- completor/create_wells.py +0 -314
- completor/pvt_model.py +0 -14
- completor-0.1.3.dist-info/RECORD +0 -27
- {completor-0.1.3.dist-info → completor-1.0.0.dist-info}/LICENSE +0 -0
- {completor-0.1.3.dist-info → completor-1.0.0.dist-info}/WHEEL +0 -0
- {completor-0.1.3.dist-info → completor-1.0.0.dist-info}/entry_points.txt +0 -0
completor/prepare_outputs.py
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import math
|
|
4
|
-
from collections.abc import
|
|
4
|
+
from collections.abc import MutableMapping
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import numpy.typing as npt
|
|
9
9
|
import pandas as pd
|
|
10
10
|
|
|
11
|
-
from completor.
|
|
12
|
-
from completor.constants import Headers, Keywords
|
|
11
|
+
from completor.constants import Content, Headers, Keywords
|
|
13
12
|
from completor.exceptions import CompletorError
|
|
14
13
|
from completor.logger import logger
|
|
15
|
-
from completor.
|
|
16
|
-
from completor.
|
|
14
|
+
from completor.utils import check_width_lines
|
|
15
|
+
from completor.wells import Lateral, Well
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
def trim_pandas(df_temp: pd.DataFrame) -> pd.DataFrame:
|
|
@@ -46,7 +45,7 @@ def add_columns_first_last(df_temp: pd.DataFrame, add_first: bool = True, add_la
|
|
|
46
45
|
"""Add the first and last column of DataFrame.
|
|
47
46
|
|
|
48
47
|
Args:
|
|
49
|
-
df_temp: E.g.
|
|
48
|
+
df_temp: E.g. WELL_SPECIFICATION, COMPLETION_SEGMENTS, COMPLETION_DATA, WELL_SEGMENTS, etc.
|
|
50
49
|
add_first: Add the first column.
|
|
51
50
|
add_last: Add the last column.
|
|
52
51
|
|
|
@@ -68,20 +67,22 @@ def dataframe_tostring(
|
|
|
68
67
|
format_column: bool = False,
|
|
69
68
|
trim_df: bool = True,
|
|
70
69
|
header: bool = True,
|
|
71
|
-
|
|
70
|
+
keep_header: bool = True,
|
|
71
|
+
limit: int = 128,
|
|
72
72
|
) -> str:
|
|
73
73
|
"""Convert DataFrame to string.
|
|
74
74
|
|
|
75
75
|
Args:
|
|
76
|
-
df_temp:
|
|
76
|
+
df_temp: COMPLETION_DATA, COMPLETION_SEGMENTS, etc.
|
|
77
77
|
format_column: If columns are to be formatted.
|
|
78
78
|
trim_df: To trim or not to trim. Default: True.
|
|
79
|
-
formatters: Dictionary of the column format. Default: None.
|
|
80
79
|
header: Keep header (True) or not (False).
|
|
80
|
+
limit: Limit width of DataFrame.
|
|
81
81
|
|
|
82
82
|
Returns:
|
|
83
83
|
Text string of the DataFrame.
|
|
84
84
|
"""
|
|
85
|
+
number_of_levels = 1
|
|
85
86
|
if df_temp.empty:
|
|
86
87
|
return ""
|
|
87
88
|
# check if the dataframe has first = "--" and last column ""
|
|
@@ -94,44 +95,123 @@ def dataframe_tostring(
|
|
|
94
95
|
if columns[0] != "--":
|
|
95
96
|
# then add first column
|
|
96
97
|
df_temp = add_columns_first_last(df_temp, add_first=True, add_last=False)
|
|
97
|
-
|
|
98
|
+
|
|
99
|
+
# Add single quotes around well names in an output file.
|
|
98
100
|
if Headers.WELL in df_temp.columns:
|
|
99
101
|
df_temp[Headers.WELL] = "'" + df_temp[Headers.WELL].astype(str) + "'"
|
|
100
|
-
|
|
102
|
+
|
|
103
|
+
formatters: MutableMapping[Any, Any] = {}
|
|
101
104
|
if format_column:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
105
|
+
formatters = {
|
|
106
|
+
Headers.STRENGTH: "{:.10g}".format,
|
|
107
|
+
Headers.SCALE_FACTOR: "{:.10g}".format,
|
|
108
|
+
Headers.ROUGHNESS: "{:.10g}".format,
|
|
109
|
+
Headers.CONNECTION_FACTOR: "{:.10g}".format,
|
|
110
|
+
"CONNECTION_FACTOR": "{:.10g}".format,
|
|
111
|
+
Headers.FORMATION_PERMEABILITY_THICKNESS: "{:.10g}".format,
|
|
112
|
+
"FORMATION_PERMEABILITY_THICKNESS": "{:.10g}".format,
|
|
113
|
+
Headers.MEASURED_DEPTH: "{:.3f}".format,
|
|
114
|
+
"MD": "{:.3f}".format,
|
|
115
|
+
Headers.TRUE_VERTICAL_DEPTH: "{:.3f}".format,
|
|
116
|
+
"TVD": "{:.3f}".format,
|
|
117
|
+
Headers.START_MEASURED_DEPTH: "{:.3f}".format,
|
|
118
|
+
"START_MD": "{:.3f}".format,
|
|
119
|
+
Headers.END_MEASURED_DEPTH: "{:.3f}".format,
|
|
120
|
+
"END_MD": "{:.3f}".format,
|
|
121
|
+
Headers.FLOW_COEFFICIENT: "{:.10g}".format,
|
|
122
|
+
"CV": "{:.10g}".format,
|
|
123
|
+
Headers.FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
124
|
+
"FLOW_CROSS_SECTIONAL_AREA": "{:.3e}".format,
|
|
125
|
+
Headers.OIL_FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
126
|
+
Headers.GAS_FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
127
|
+
Headers.WATER_FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
128
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
129
|
+
Headers.DEFAULTS: "{:.10s}".format,
|
|
130
|
+
Headers.WATER_HOLDUP_FRACTION_LOW_CUTOFF: "{:.10g}".format,
|
|
131
|
+
Headers.WATER_HOLDUP_FRACTION_HIGH_CUTOFF: "{:.10g}".format,
|
|
132
|
+
Headers.GAS_HOLDUP_FRACTION_LOW_CUTOFF: "{:.10g}".format,
|
|
133
|
+
Headers.GAS_HOLDUP_FRACTION_HIGH_CUTOFF: "{:.10g}".format,
|
|
134
|
+
Headers.ALPHA_MAIN: "{:.10g}".format,
|
|
135
|
+
Headers.ALPHA_PILOT: "{:.10g}".format,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if header:
|
|
139
|
+
# Modify headers to reduce width.
|
|
140
|
+
column_splits = [tuple(column.split("_")) for column in df_temp.columns]
|
|
141
|
+
number_of_levels = max([len(tup) for tup in column_splits])
|
|
142
|
+
if number_of_levels > 1:
|
|
143
|
+
formatters.update(
|
|
144
|
+
{
|
|
145
|
+
("SCALE", "FACTOR"): "{:.10g}".format,
|
|
146
|
+
("CONNECTION", "FACTOR"): "{:.10g}".format,
|
|
147
|
+
("FORMATION", "PERMEABILITY", "THICKNESS"): "{:.10g}".format,
|
|
148
|
+
("MEASURED", "DEPTH"): "{:.3f}".format,
|
|
149
|
+
("TRUE", "VERTICAL", "DEPTH"): "{:.3f}".format,
|
|
150
|
+
("START", "MEASURED", "DEPTH"): "{:.3f}".format,
|
|
151
|
+
("START", "MD"): "{:.3f}".format,
|
|
152
|
+
("END", "MEASURED", "DEPTH"): "{:.3f}".format,
|
|
153
|
+
("END", "MD"): "{:.3f}".format,
|
|
154
|
+
("FLOW", "COEFFICIENT"): "{:.10g}".format,
|
|
155
|
+
("FLOW", "CROSS", "SECTIONAL", "AREA"): "{:.3e}".format,
|
|
156
|
+
("OIL", "FLOW", "CROSS", "SECTIONAL", "AREA"): "{:.3e}".format,
|
|
157
|
+
("GAS", "FLOW", "CROSS", "SECTIONAL", "AREA"): "{:.3e}".format,
|
|
158
|
+
("WATER", "FLOW", "CROSS", "SECTIONAL", "AREA"): "{:.3e}".format,
|
|
159
|
+
("MAX", "FLOW", "CROSS", "SECTIONAL", "AREA"): "{:.3e}".format,
|
|
160
|
+
("WATER", "HOLDUP", "FRACTION", "LOW", "CUTOFF"): "{:.10g}".format,
|
|
161
|
+
("WATER", "HOLDUP", "FRACTION", "HIGH", "CUTOFF"): "{:.10g}".format,
|
|
162
|
+
("GAS", "HOLDUP", "FRACTION", "LOW", "CUTOFF"): "{:.10g}".format,
|
|
163
|
+
("GAS", "HOLDUP", "FRACTION", "HIGH", "CUTOFF"): "{:.10g}".format,
|
|
164
|
+
("ALPHA", "MAIN"): "{:.10g}".format,
|
|
165
|
+
("ALPHA", "PILOT"): "{:.10g}".format,
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
if column_splits[0][0].startswith("--"):
|
|
169
|
+
# Make sure each level is commented out!
|
|
170
|
+
column_splits[0] = tuple(["--"] * number_of_levels)
|
|
171
|
+
# Replace nan with empty for printing purposes.
|
|
172
|
+
new_cols = pd.DataFrame(column_splits).fillna("")
|
|
173
|
+
df_temp.columns = pd.MultiIndex.from_frame(new_cols)
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
output_string = df_temp.to_string(
|
|
177
|
+
index=False, justify="justify", formatters=formatters, header=header, sparsify=False
|
|
178
|
+
)
|
|
179
|
+
except ValueError:
|
|
180
|
+
if df_temp.isnull().values.any():
|
|
181
|
+
raise CompletorError("Got NaN values in table, please report if encountered!")
|
|
182
|
+
df_temp = df_temp.replace("*", "1*", inplace=False)
|
|
183
|
+
columns_with_1_star = df_temp.columns[df_temp.eq("1*").any()]
|
|
184
|
+
df_temp = df_temp.replace("1*", np.nan, inplace=False)
|
|
185
|
+
# Probably find columns where this is the case and cast to numeric after replacing with nan?
|
|
186
|
+
df_temp[columns_with_1_star] = df_temp[columns_with_1_star].astype(np.float64, errors="ignore")
|
|
187
|
+
output_string = df_temp.to_string(
|
|
188
|
+
index=False, justify="justify", formatters=formatters, header=header, sparsify=False, na_rep="1*"
|
|
189
|
+
)
|
|
190
|
+
|
|
132
191
|
if output_string is None:
|
|
133
192
|
return ""
|
|
134
|
-
|
|
193
|
+
|
|
194
|
+
too_long_lines = check_width_lines(output_string, limit)
|
|
195
|
+
if too_long_lines:
|
|
196
|
+
output_string = df_temp.to_string(
|
|
197
|
+
index=False, justify="left", formatters=formatters, header=header, sparsify=False
|
|
198
|
+
)
|
|
199
|
+
if output_string is None:
|
|
200
|
+
return ""
|
|
201
|
+
too_long_lines2 = check_width_lines(output_string, limit)
|
|
202
|
+
if too_long_lines2:
|
|
203
|
+
# Still, some issues. Reporting on the original errors.
|
|
204
|
+
number_of_lines = len(too_long_lines)
|
|
205
|
+
logger.error(
|
|
206
|
+
f"Some data-lines in the output are wider than limit of {limit} characters for some reservoir "
|
|
207
|
+
f"simulators!\nThis is concerning line-numbers: {[tup[0] for tup in too_long_lines]}\n"
|
|
208
|
+
f"{'An excerpt of the five first' if number_of_lines > 5 else 'The'} lines:\n"
|
|
209
|
+
+ "\n".join([tup[1] for tup in too_long_lines[: min(number_of_lines, 5)]])
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
if keep_header:
|
|
213
|
+
return output_string
|
|
214
|
+
return "\n".join(output_string.splitlines()[number_of_levels:])
|
|
135
215
|
|
|
136
216
|
|
|
137
217
|
def get_outlet_segment(
|
|
@@ -152,14 +232,17 @@ def get_outlet_segment(
|
|
|
152
232
|
Returns:
|
|
153
233
|
The outlet segments.
|
|
154
234
|
"""
|
|
155
|
-
df_target_md = pd.DataFrame(target_md, columns=[Headers.
|
|
235
|
+
df_target_md = pd.DataFrame(target_md, columns=[Headers.MEASURED_DEPTH])
|
|
156
236
|
df_reference = pd.DataFrame(
|
|
157
|
-
np.column_stack((reference_md, reference_segment_number)),
|
|
237
|
+
np.column_stack((reference_md, reference_segment_number)),
|
|
238
|
+
columns=[Headers.MEASURED_DEPTH, Headers.START_SEGMENT_NUMBER],
|
|
158
239
|
)
|
|
159
|
-
df_reference[Headers.
|
|
160
|
-
df_reference.sort_values(by=[Headers.
|
|
240
|
+
df_reference[Headers.START_SEGMENT_NUMBER] = df_reference[Headers.START_SEGMENT_NUMBER].astype(np.int64)
|
|
241
|
+
df_reference.sort_values(by=[Headers.MEASURED_DEPTH], inplace=True)
|
|
161
242
|
return (
|
|
162
|
-
pd.merge_asof(left=df_target_md, right=df_reference, on=[Headers.
|
|
243
|
+
pd.merge_asof(left=df_target_md, right=df_reference, on=[Headers.MEASURED_DEPTH], direction="nearest")[
|
|
244
|
+
Headers.START_SEGMENT_NUMBER
|
|
245
|
+
]
|
|
163
246
|
.to_numpy()
|
|
164
247
|
.flatten()
|
|
165
248
|
)
|
|
@@ -185,7 +268,7 @@ def get_header(well_name: str, keyword: str, lat: int, layer: str, nchar: int =
|
|
|
185
268
|
|
|
186
269
|
Args:
|
|
187
270
|
well_name: Well name.
|
|
188
|
-
keyword: Table keyword e.g.
|
|
271
|
+
keyword: Table keyword e.g. WELL_SEGMENTS, COMPLETION_SEGMENTS, COMPLETION_DATA, etc.
|
|
189
272
|
lat: Lateral number.
|
|
190
273
|
layer: Layer description e.g. tubing, device and annulus.
|
|
191
274
|
nchar: Number of characters for the line boundary. Default 100.
|
|
@@ -193,29 +276,23 @@ def get_header(well_name: str, keyword: str, lat: int, layer: str, nchar: int =
|
|
|
193
276
|
Returns:
|
|
194
277
|
String header.
|
|
195
278
|
"""
|
|
196
|
-
if keyword == Keywords.
|
|
197
|
-
header = f"
|
|
279
|
+
if keyword == Keywords.WELL_SEGMENTS:
|
|
280
|
+
header = f"Well: {well_name}, Lateral: {lat}, {layer} layer"
|
|
198
281
|
else:
|
|
199
|
-
header = f"
|
|
200
|
-
|
|
282
|
+
header = f"Well: {well_name}, Lateral: {lat}"
|
|
283
|
+
|
|
284
|
+
pad = max((nchar - len(header)) // 2, 2)
|
|
285
|
+
return f"{'-' * pad} {header} {'-' * pad}\n"
|
|
201
286
|
|
|
202
287
|
|
|
203
288
|
def prepare_tubing_layer(
|
|
204
|
-
|
|
205
|
-
well_name: str,
|
|
206
|
-
lateral: int,
|
|
207
|
-
df_well: pd.DataFrame,
|
|
208
|
-
start_segment: int,
|
|
209
|
-
branch_no: int,
|
|
210
|
-
completion_table: pd.DataFrame,
|
|
289
|
+
well: Well, lateral: Lateral, start_segment: int, branch_no: int, completion_table: pd.DataFrame
|
|
211
290
|
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
212
291
|
"""Prepare tubing layer data frame.
|
|
213
292
|
|
|
214
293
|
Args:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
lateral: Lateral number.
|
|
218
|
-
df_well: Must contain column LATERAL, TUB_MD, TUB_TVD, INNER_DIAMETER, ROUGHNESS.
|
|
294
|
+
well: Well object.
|
|
295
|
+
lateral: Lateral object.
|
|
219
296
|
start_segment: Start number of the first tubing segment.
|
|
220
297
|
branch_no: Branch number for this tubing layer.
|
|
221
298
|
completion_table: DataFrame with completion data.
|
|
@@ -223,47 +300,51 @@ def prepare_tubing_layer(
|
|
|
223
300
|
Returns:
|
|
224
301
|
DataFrame for tubing layer.
|
|
225
302
|
"""
|
|
226
|
-
|
|
227
|
-
Headers.
|
|
228
|
-
Headers.
|
|
229
|
-
Headers.TUBING_INNER_DIAMETER: Headers.
|
|
303
|
+
alias_rename = {
|
|
304
|
+
Headers.TUBING_MEASURED_DEPTH: Headers.MEASURED_DEPTH,
|
|
305
|
+
Headers.TRUE_VERTICAL_DEPTH: Headers.TRUE_VERTICAL_DEPTH,
|
|
306
|
+
Headers.TUBING_INNER_DIAMETER: Headers.WELL_BORE_DIAMETER,
|
|
230
307
|
Headers.TUBING_ROUGHNESS: Headers.ROUGHNESS,
|
|
231
308
|
}
|
|
232
|
-
cols = list(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
309
|
+
cols = list(alias_rename.values())
|
|
310
|
+
df_tubing_in_reservoir = pd.DataFrame(
|
|
311
|
+
{
|
|
312
|
+
Headers.MEASURED_DEPTH: lateral.df_well[Headers.TUBING_MEASURED_DEPTH],
|
|
313
|
+
Headers.TRUE_VERTICAL_DEPTH: lateral.df_well[Headers.TRUE_VERTICAL_DEPTH],
|
|
314
|
+
Headers.WELL_BORE_DIAMETER: lateral.df_well[Headers.INNER_DIAMETER],
|
|
315
|
+
Headers.ROUGHNESS: lateral.df_well[Headers.ROUGHNESS],
|
|
316
|
+
}
|
|
240
317
|
)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
md_input_welsegs =
|
|
244
|
-
md_welsegs_in_reservoir = df_tubing_in_reservoir[Headers.
|
|
245
|
-
overburden =
|
|
246
|
-
if
|
|
247
|
-
overburden = overburden.rename(index=str, columns=rnm)
|
|
248
|
-
overburden_fixed = fix_tubing_inner_diam_roughness(well_name, overburden, completion_table)
|
|
249
|
-
df_tubing_with_overburden = pd.concat([overburden_fixed[cols], df_tubing_in_reservoir])
|
|
250
|
-
else:
|
|
318
|
+
|
|
319
|
+
# Handle overburden.
|
|
320
|
+
md_input_welsegs = lateral.df_welsegs_content[Headers.TUBING_MEASURED_DEPTH]
|
|
321
|
+
md_welsegs_in_reservoir = df_tubing_in_reservoir[Headers.MEASURED_DEPTH]
|
|
322
|
+
overburden = lateral.df_welsegs_content[(md_welsegs_in_reservoir[0] - md_input_welsegs) > 1.0]
|
|
323
|
+
if overburden.empty:
|
|
251
324
|
df_tubing_with_overburden = df_tubing_in_reservoir
|
|
252
|
-
|
|
253
|
-
|
|
325
|
+
else:
|
|
326
|
+
overburden = overburden.rename(index=str, columns=alias_rename)
|
|
327
|
+
overburden_fixed = fix_tubing_inner_diam_roughness(well.well_name, overburden, completion_table)
|
|
328
|
+
df_tubing_with_overburden = pd.concat([overburden_fixed[cols], df_tubing_in_reservoir])
|
|
329
|
+
|
|
330
|
+
df_tubing_with_overburden[Headers.START_SEGMENT_NUMBER] = start_segment + np.arange(
|
|
331
|
+
df_tubing_with_overburden.shape[0]
|
|
332
|
+
)
|
|
333
|
+
df_tubing_with_overburden[Headers.END_SEGMENT_NUMBER] = df_tubing_with_overburden[Headers.START_SEGMENT_NUMBER]
|
|
254
334
|
df_tubing_with_overburden[Headers.BRANCH] = branch_no
|
|
255
335
|
df_tubing_with_overburden.reset_index(drop=True, inplace=True)
|
|
256
|
-
#
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# make sure order is correct
|
|
336
|
+
# Set the out-segments to be successive, the first item will be updated in connect_lateral.
|
|
337
|
+
df_tubing_with_overburden[Headers.OUT] = df_tubing_with_overburden[Headers.START_SEGMENT_NUMBER] - 1
|
|
338
|
+
# Make sure the order is correct.
|
|
260
339
|
df_tubing_with_overburden = df_tubing_with_overburden.reindex(
|
|
261
|
-
columns=[Headers.
|
|
340
|
+
columns=[Headers.START_SEGMENT_NUMBER, Headers.END_SEGMENT_NUMBER, Headers.BRANCH, Headers.OUT] + cols
|
|
262
341
|
)
|
|
263
|
-
df_tubing_with_overburden[Headers.EMPTY] = "/" #
|
|
264
|
-
#
|
|
265
|
-
|
|
266
|
-
|
|
342
|
+
df_tubing_with_overburden[Headers.EMPTY] = "/" # For printing.
|
|
343
|
+
# Locate where it's attached to (the top segment). Can be empty!
|
|
344
|
+
top = well.df_welsegs_content_all_laterals[
|
|
345
|
+
well.df_welsegs_content_all_laterals[Headers.TUBING_SEGMENT]
|
|
346
|
+
== lateral.df_welsegs_content.iloc[0][Headers.TUBING_OUTLET]
|
|
347
|
+
]
|
|
267
348
|
|
|
268
349
|
return df_tubing_with_overburden, top
|
|
269
350
|
|
|
@@ -273,35 +354,35 @@ def fix_tubing_inner_diam_roughness(
|
|
|
273
354
|
) -> pd.DataFrame:
|
|
274
355
|
"""Ensure roughness and inner diameter of the overburden segments are from the case and not the schedule file.
|
|
275
356
|
|
|
276
|
-
Overburden segments are
|
|
357
|
+
Overburden segments are WELL_SEGMENTS segments located above the top COMPLETION_SEGMENTS segment.
|
|
277
358
|
|
|
278
359
|
Args:
|
|
279
360
|
well_name: Well name.
|
|
280
|
-
overburden: Input schedule
|
|
361
|
+
overburden: Input schedule WELL_SEGMENTS segments in the overburden.
|
|
281
362
|
completion_table: Completion table from the case file, ReadCasefile object.
|
|
282
363
|
|
|
283
364
|
Returns:
|
|
284
365
|
Corrected overburden DataFrame with inner diameter and roughness taken from the ReadCasefile object.
|
|
285
366
|
|
|
286
367
|
Raises:
|
|
287
|
-
ValueError: If the well completion
|
|
368
|
+
ValueError: If the well completion is not found in overburden at overburden_md.
|
|
288
369
|
"""
|
|
289
370
|
overburden_out = overburden.copy(deep=True)
|
|
290
371
|
completion_table_well = completion_table.loc[completion_table[Headers.WELL] == well_name]
|
|
291
372
|
completion_table_well = completion_table_well.loc[
|
|
292
|
-
completion_table_well[Headers.BRANCH] == overburden_out[Headers.
|
|
373
|
+
completion_table_well[Headers.BRANCH] == overburden_out[Headers.TUBING_BRANCH].iloc[0]
|
|
293
374
|
]
|
|
294
375
|
overburden_found_in_completion = False
|
|
295
376
|
overburden_md = None
|
|
296
377
|
|
|
297
378
|
for idx_overburden in range(overburden_out.shape[0]):
|
|
298
|
-
overburden_md = overburden_out[Headers.
|
|
379
|
+
overburden_md = overburden_out[Headers.MEASURED_DEPTH].iloc[idx_overburden]
|
|
299
380
|
overburden_found_in_completion = False
|
|
300
381
|
for idx_completion_table_well in range(completion_table_well.shape[0]):
|
|
301
382
|
completion_table_start = completion_table_well[Headers.START_MEASURED_DEPTH].iloc[idx_completion_table_well]
|
|
302
383
|
completion_table_end = completion_table_well[Headers.END_MEASURED_DEPTH].iloc[idx_completion_table_well]
|
|
303
384
|
if (completion_table_end >= overburden_md >= completion_table_start) and not overburden_found_in_completion:
|
|
304
|
-
overburden_out.iloc[idx_overburden, overburden_out.columns.get_loc(Headers.
|
|
385
|
+
overburden_out.iloc[idx_overburden, overburden_out.columns.get_loc(Headers.WELL_BORE_DIAMETER)] = (
|
|
305
386
|
completion_table_well[Headers.INNER_DIAMETER].iloc[idx_completion_table_well]
|
|
306
387
|
)
|
|
307
388
|
overburden_out.iloc[idx_overburden, overburden_out.columns.get_loc(Headers.ROUGHNESS)] = (
|
|
@@ -318,129 +399,63 @@ def fix_tubing_inner_diam_roughness(
|
|
|
318
399
|
raise ValueError(f"Cannot find {well_name} in completion overburden; it is empty") from err
|
|
319
400
|
|
|
320
401
|
|
|
321
|
-
def
|
|
322
|
-
well_name: str,
|
|
323
|
-
lateral: int,
|
|
324
|
-
data: dict[int, tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]],
|
|
325
|
-
case: ReadCasefile,
|
|
326
|
-
) -> None:
|
|
327
|
-
"""Connect lateral to main wellbore/branch.
|
|
328
|
-
|
|
329
|
-
The main branch can either have a tubing- or device-layer connected.
|
|
330
|
-
By default, the lateral will be connected to tubing-layer, but if connect_to_tubing is False,
|
|
331
|
-
it will be connected to device-layer.
|
|
332
|
-
Abort if it cannot find device layer at junction depth.
|
|
333
|
-
|
|
334
|
-
Args:
|
|
335
|
-
well_name: Well name.
|
|
336
|
-
lateral: Lateral number.
|
|
337
|
-
data: Dict with integer key 'lateral' containing:.
|
|
338
|
-
df_tubing: DataFrame tubing layer.
|
|
339
|
-
df_device: DataFrame device layer.
|
|
340
|
-
df_annulus: DataFrame annulus layer.
|
|
341
|
-
df_wseglink: DataFrame WSEGLINK.
|
|
342
|
-
top: DataFrame of first connection.
|
|
343
|
-
case: ReadCasefile object.
|
|
344
|
-
|
|
345
|
-
Raises:
|
|
346
|
-
CompletorError: If there is no device layer at junction of lateral.
|
|
347
|
-
"""
|
|
348
|
-
df_tubing, _, _, _, top = data[lateral]
|
|
349
|
-
if not top.empty:
|
|
350
|
-
lateral0 = top.TUBINGBRANCH.to_numpy()[0]
|
|
351
|
-
md_junct = top.TUBINGMD.to_numpy()[0]
|
|
352
|
-
if md_junct > df_tubing[Headers.MD][0]:
|
|
353
|
-
logger.warning(
|
|
354
|
-
"Found a junction above the start of the tubing layer, well %s, "
|
|
355
|
-
"branch %s. Check the depth of segments pointing at the main stem "
|
|
356
|
-
"in schedule-file",
|
|
357
|
-
well_name,
|
|
358
|
-
lateral,
|
|
359
|
-
)
|
|
360
|
-
if case.connect_to_tubing(well_name, lateral):
|
|
361
|
-
df_segm0 = data[lateral0][0] # df_tubing
|
|
362
|
-
else:
|
|
363
|
-
df_segm0 = data[lateral0][1] # df_device
|
|
364
|
-
try:
|
|
365
|
-
if case.connect_to_tubing(well_name, lateral):
|
|
366
|
-
# Since md_junct (top.TUBINGMD) has segment tops and
|
|
367
|
-
# segm0.MD has grid block midpoints, a junction at the top of the
|
|
368
|
-
# well may not be found. Therefore, we try the following:
|
|
369
|
-
if (~(df_segm0.MD <= md_junct)).all():
|
|
370
|
-
md_junct = df_segm0.MD.iloc[0]
|
|
371
|
-
idx = np.where(df_segm0.MD <= md_junct)[0][-1]
|
|
372
|
-
else:
|
|
373
|
-
idx = np.where(df_segm0.MD <= md_junct)[0][-1]
|
|
374
|
-
else:
|
|
375
|
-
# Add 0.1 to md_junct since md_junct refers to the tubing layer
|
|
376
|
-
# junction md and the device layer md is shifted 0.1 m to the
|
|
377
|
-
# tubing layer.
|
|
378
|
-
idx = np.where(df_segm0.MD <= md_junct + 0.1)[0][-1]
|
|
379
|
-
except IndexError as err:
|
|
380
|
-
raise CompletorError(f"Cannot find a device layer at junction of lateral {lateral} in {well_name}") from err
|
|
381
|
-
outsegm = df_segm0.at[idx, Headers.SEG]
|
|
382
|
-
else:
|
|
383
|
-
outsegm = 1 # default
|
|
384
|
-
df_tubing.at[0, Headers.OUT] = outsegm
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
def prepare_device_layer(
|
|
388
|
-
well_name: str, lateral: int, df_well: pd.DataFrame, df_tubing: pd.DataFrame, device_length: float = 0.1
|
|
389
|
-
) -> pd.DataFrame:
|
|
402
|
+
def prepare_device_layer(df_well: pd.DataFrame, df_tubing: pd.DataFrame, device_length: float = 0.1) -> pd.DataFrame:
|
|
390
403
|
"""Prepare device layer dataframe.
|
|
391
404
|
|
|
392
405
|
Args:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
df_well: Must contain LATERAL, TUB_MD, TUB_TVD, INNER_DIAMETER, ROUGHNESS, DEVICETYPE and NDEVICES.
|
|
406
|
+
df_well: Must contain LATERAL, TUBING_MEASURED_DEPTH, TRUE_VERTICAL_DEPTH,
|
|
407
|
+
INNER_DIAMETER, ROUGHNESS, DEVICE_TYPE and NDEVICES.
|
|
396
408
|
df_tubing: Data frame from function prepare_tubing_layer for this well and this lateral.
|
|
397
409
|
device_length: Segment length. Default to 0.1.
|
|
398
410
|
|
|
399
411
|
Returns:
|
|
400
412
|
DataFrame for device layer.
|
|
401
413
|
"""
|
|
402
|
-
start_segment = max(df_tubing[Headers.
|
|
414
|
+
start_segment = max(df_tubing[Headers.START_SEGMENT_NUMBER].to_numpy()) + 1
|
|
403
415
|
start_branch = max(df_tubing[Headers.BRANCH].to_numpy()) + 1
|
|
404
|
-
|
|
405
|
-
df_well = df_well[df_well[Headers.LATERAL] == lateral]
|
|
416
|
+
|
|
406
417
|
# device segments are only created if:
|
|
407
418
|
# 1. the device type is PERF
|
|
408
419
|
# 2. if it is not PERF then it must have number of device > 0
|
|
409
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] ==
|
|
420
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
410
421
|
if df_well.empty:
|
|
411
422
|
# return blank dataframe
|
|
412
423
|
return pd.DataFrame()
|
|
413
424
|
# now create dataframe for device layer
|
|
414
425
|
df_device = pd.DataFrame()
|
|
415
|
-
df_device[Headers.
|
|
416
|
-
df_device[Headers.
|
|
426
|
+
df_device[Headers.START_SEGMENT_NUMBER] = start_segment + np.arange(df_well.shape[0])
|
|
427
|
+
df_device[Headers.END_SEGMENT_NUMBER] = df_device[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
417
428
|
df_device[Headers.BRANCH] = start_branch + np.arange(df_well.shape[0])
|
|
418
429
|
df_device[Headers.OUT] = get_outlet_segment(
|
|
419
|
-
df_well[Headers.
|
|
430
|
+
df_well[Headers.TUBING_MEASURED_DEPTH].to_numpy(),
|
|
431
|
+
df_tubing[Headers.MEASURED_DEPTH].to_numpy(),
|
|
432
|
+
df_tubing[Headers.START_SEGMENT_NUMBER].to_numpy(),
|
|
420
433
|
)
|
|
421
|
-
df_device[Headers.
|
|
422
|
-
df_device[Headers.
|
|
423
|
-
df_device[Headers.
|
|
434
|
+
df_device[Headers.MEASURED_DEPTH] = df_well[Headers.TUBING_MEASURED_DEPTH].to_numpy() + device_length
|
|
435
|
+
df_device[Headers.TRUE_VERTICAL_DEPTH] = df_well[Headers.TRUE_VERTICAL_DEPTH].to_numpy()
|
|
436
|
+
df_device[Headers.WELL_BORE_DIAMETER] = df_well[Headers.INNER_DIAMETER].to_numpy()
|
|
424
437
|
df_device[Headers.ROUGHNESS] = df_well[Headers.ROUGHNESS].to_numpy()
|
|
425
438
|
device_comment = np.where(
|
|
426
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
439
|
+
df_well[Headers.DEVICE_TYPE] == Content.PERFORATED,
|
|
427
440
|
"/ -- Open Perforation",
|
|
428
441
|
np.where(
|
|
429
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
442
|
+
df_well[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_DEVICE,
|
|
430
443
|
"/ -- AICD types",
|
|
431
444
|
np.where(
|
|
432
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
445
|
+
df_well[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_DEVICE,
|
|
433
446
|
"/ -- ICD types",
|
|
434
447
|
np.where(
|
|
435
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
448
|
+
df_well[Headers.DEVICE_TYPE] == Content.VALVE,
|
|
436
449
|
"/ -- Valve types",
|
|
437
450
|
np.where(
|
|
438
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
451
|
+
df_well[Headers.DEVICE_TYPE] == Content.DENSITY_ACTIVATED_RECOVERY,
|
|
439
452
|
"/ -- DAR types",
|
|
440
453
|
np.where(
|
|
441
|
-
df_well[Headers.DEVICE_TYPE] ==
|
|
454
|
+
df_well[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_VALVE,
|
|
442
455
|
"/ -- AICV types",
|
|
443
|
-
np.where(
|
|
456
|
+
np.where(
|
|
457
|
+
df_well[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_VALVE, "/ -- ICV types", ""
|
|
458
|
+
),
|
|
444
459
|
),
|
|
445
460
|
),
|
|
446
461
|
),
|
|
@@ -452,14 +467,13 @@ def prepare_device_layer(
|
|
|
452
467
|
|
|
453
468
|
|
|
454
469
|
def prepare_annulus_layer(
|
|
455
|
-
well_name: str,
|
|
470
|
+
well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame, annulus_length: float = 0.1
|
|
456
471
|
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
457
472
|
"""Prepare annulus layer and wseglink dataframe.
|
|
458
473
|
|
|
459
474
|
Args:
|
|
460
475
|
well_name: Well name.
|
|
461
|
-
|
|
462
|
-
df_well: Must contain LATERAL, ANNULUS_ZONE, TUB_MD, TUB_TVD, OUTER_DIAMETER,
|
|
476
|
+
df_well: Must contain LATERAL, ANNULUS_ZONE, TUBING_MEASURED_DEPTH, TRUE_VERTICAL_DEPTH, OUTER_DIAMETER,
|
|
463
477
|
ROUGHNESS, DEVICETYPE and NDEVICES.
|
|
464
478
|
df_device: DataFrame from function prepare_device_layer for this well and this lateral.
|
|
465
479
|
annulus_length: Annulus segment length increment. Default to 0.1.
|
|
@@ -472,36 +486,34 @@ def prepare_annulus_layer(
|
|
|
472
486
|
|
|
473
487
|
"""
|
|
474
488
|
# filter for this lateral
|
|
475
|
-
df_well = df_well[df_well[Headers.WELL] == well_name]
|
|
476
|
-
df_well = df_well[df_well[Headers.LATERAL] == lateral]
|
|
477
489
|
# filter segments which have annular zones
|
|
478
490
|
df_well = df_well[df_well[Headers.ANNULUS_ZONE] > 0]
|
|
479
491
|
# loop through all annular zones
|
|
480
492
|
# initiate annulus and wseglink dataframe
|
|
481
493
|
df_annulus = pd.DataFrame()
|
|
482
|
-
|
|
494
|
+
df_well_segments_link = pd.DataFrame()
|
|
483
495
|
for izone, zone in enumerate(df_well[Headers.ANNULUS_ZONE].unique()):
|
|
484
496
|
# filter only that annular zone
|
|
485
497
|
df_branch = df_well[df_well[Headers.ANNULUS_ZONE] == zone]
|
|
486
498
|
df_active = df_branch[
|
|
487
499
|
(df_branch[Headers.NUMBER_OF_DEVICES].to_numpy() > 0)
|
|
488
|
-
| (df_branch[Headers.DEVICE_TYPE].to_numpy() ==
|
|
500
|
+
| (df_branch[Headers.DEVICE_TYPE].to_numpy() == Content.PERFORATED)
|
|
489
501
|
]
|
|
490
502
|
# setting the start segment number and start branch number
|
|
491
503
|
if izone == 0:
|
|
492
|
-
start_segment = max(df_device[Headers.
|
|
504
|
+
start_segment = max(df_device[Headers.START_SEGMENT_NUMBER]) + 1
|
|
493
505
|
start_branch = max(df_device[Headers.BRANCH]) + 1
|
|
494
506
|
else:
|
|
495
|
-
start_segment = max(df_annulus[Headers.
|
|
507
|
+
start_segment = max(df_annulus[Headers.START_SEGMENT_NUMBER]) + 1
|
|
496
508
|
start_branch = max(df_annulus[Headers.BRANCH]) + 1
|
|
497
509
|
# now find the most downstream connection of the annulus zone
|
|
498
510
|
idx_connection = np.argwhere(
|
|
499
511
|
(df_branch[Headers.NUMBER_OF_DEVICES].to_numpy() > 0)
|
|
500
|
-
| (df_branch[Headers.DEVICE_TYPE].to_numpy() ==
|
|
512
|
+
| (df_branch[Headers.DEVICE_TYPE].to_numpy() == Content.PERFORATED)
|
|
501
513
|
)
|
|
502
514
|
if idx_connection[0] == 0:
|
|
503
515
|
# If the first connection then everything is easy
|
|
504
|
-
df_annulus_upstream,
|
|
516
|
+
df_annulus_upstream, df_well_segments_link_upstream = calculate_upstream(
|
|
505
517
|
df_branch, df_active, df_device, start_branch, annulus_length, start_segment, well_name
|
|
506
518
|
)
|
|
507
519
|
else:
|
|
@@ -519,25 +531,31 @@ def prepare_annulus_layer(
|
|
|
519
531
|
)
|
|
520
532
|
# downstream part
|
|
521
533
|
df_annulus_downstream = pd.DataFrame()
|
|
522
|
-
df_annulus_downstream[Headers.
|
|
523
|
-
|
|
534
|
+
df_annulus_downstream[Headers.START_SEGMENT_NUMBER] = start_segment + np.arange(
|
|
535
|
+
df_branch_downstream.shape[0]
|
|
536
|
+
)
|
|
537
|
+
df_annulus_downstream[Headers.END_SEGMENT_NUMBER] = df_annulus_downstream[Headers.START_SEGMENT_NUMBER]
|
|
524
538
|
df_annulus_downstream[Headers.BRANCH] = start_branch
|
|
525
|
-
df_annulus_downstream[Headers.OUT] = df_annulus_downstream[Headers.
|
|
526
|
-
df_annulus_downstream[Headers.
|
|
527
|
-
|
|
528
|
-
|
|
539
|
+
df_annulus_downstream[Headers.OUT] = df_annulus_downstream[Headers.START_SEGMENT_NUMBER] + 1
|
|
540
|
+
df_annulus_downstream[Headers.MEASURED_DEPTH] = (
|
|
541
|
+
df_branch_downstream[Headers.TUBING_MEASURED_DEPTH].to_numpy() + annulus_length
|
|
542
|
+
)
|
|
543
|
+
df_annulus_downstream[Headers.TRUE_VERTICAL_DEPTH] = df_branch_downstream[
|
|
544
|
+
Headers.TRUE_VERTICAL_DEPTH
|
|
545
|
+
].to_numpy()
|
|
546
|
+
df_annulus_downstream[Headers.WELL_BORE_DIAMETER] = df_branch_downstream[Headers.OUTER_DIAMETER].to_numpy()
|
|
529
547
|
df_annulus_downstream[Headers.ROUGHNESS] = df_branch_downstream[Headers.ROUGHNESS].to_numpy()
|
|
530
548
|
|
|
531
|
-
# no
|
|
549
|
+
# no WELL_SEGMENTS_LINK in the downstream part because
|
|
532
550
|
# no annulus segment have connection to
|
|
533
551
|
# the device segment. in case you wonder why :)
|
|
534
552
|
|
|
535
553
|
# upstream part
|
|
536
554
|
# update the start segment and start branch
|
|
537
|
-
start_segment = max(df_annulus_downstream[Headers.
|
|
555
|
+
start_segment = max(df_annulus_downstream[Headers.START_SEGMENT_NUMBER]) + 1
|
|
538
556
|
start_branch = max(df_annulus_downstream[Headers.BRANCH]) + 1
|
|
539
557
|
# create dataframe for upstream part
|
|
540
|
-
df_annulus_upstream,
|
|
558
|
+
df_annulus_upstream, df_well_segments_link_upstream = calculate_upstream(
|
|
541
559
|
df_branch_upstream, df_active, df_device, start_branch, annulus_length, start_segment, well_name
|
|
542
560
|
)
|
|
543
561
|
# combine the two dataframe upstream and downstream
|
|
@@ -546,20 +564,20 @@ def prepare_annulus_layer(
|
|
|
546
564
|
# combine annulus and wseglink dataframe
|
|
547
565
|
if izone == 0:
|
|
548
566
|
df_annulus = df_annulus_upstream.copy(deep=True)
|
|
549
|
-
|
|
567
|
+
df_well_segments_link = df_well_segments_link_upstream.copy(deep=True)
|
|
550
568
|
else:
|
|
551
569
|
df_annulus = pd.concat([df_annulus, df_annulus_upstream])
|
|
552
|
-
|
|
570
|
+
df_well_segments_link = pd.concat([df_well_segments_link, df_well_segments_link_upstream])
|
|
553
571
|
|
|
554
|
-
if
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
572
|
+
if df_well_segments_link.shape[0] > 0:
|
|
573
|
+
df_well_segments_link = df_well_segments_link[[Headers.WELL, Headers.ANNULUS, Headers.DEVICE]]
|
|
574
|
+
df_well_segments_link[Headers.ANNULUS] = df_well_segments_link[Headers.ANNULUS].astype(np.int64)
|
|
575
|
+
df_well_segments_link[Headers.DEVICE] = df_well_segments_link[Headers.DEVICE].astype(np.int64)
|
|
576
|
+
df_well_segments_link[Headers.EMPTY] = "/"
|
|
559
577
|
|
|
560
578
|
if df_annulus.shape[0] > 0:
|
|
561
579
|
df_annulus[Headers.EMPTY] = "/"
|
|
562
|
-
return df_annulus,
|
|
580
|
+
return df_annulus, df_well_segments_link
|
|
563
581
|
|
|
564
582
|
|
|
565
583
|
def calculate_upstream(
|
|
@@ -586,74 +604,83 @@ def calculate_upstream(
|
|
|
586
604
|
Annulus upstream and wseglink upstream.
|
|
587
605
|
"""
|
|
588
606
|
df_annulus_upstream = pd.DataFrame()
|
|
589
|
-
df_annulus_upstream[Headers.
|
|
590
|
-
df_annulus_upstream[Headers.
|
|
607
|
+
df_annulus_upstream[Headers.START_SEGMENT_NUMBER] = start_segment + np.arange(df_branch.shape[0])
|
|
608
|
+
df_annulus_upstream[Headers.END_SEGMENT_NUMBER] = df_annulus_upstream[Headers.START_SEGMENT_NUMBER]
|
|
591
609
|
df_annulus_upstream[Headers.BRANCH] = start_branch
|
|
592
|
-
out_segment = df_annulus_upstream[Headers.
|
|
610
|
+
out_segment = df_annulus_upstream[Headers.START_SEGMENT_NUMBER].to_numpy() - 1
|
|
593
611
|
# determining the outlet segment of the annulus segment
|
|
594
612
|
# if the annulus segment is not the most downstream which has connection
|
|
595
613
|
# then the outlet is its adjacent annulus segment
|
|
596
614
|
device_segment = get_outlet_segment(
|
|
597
|
-
df_branch[Headers.
|
|
615
|
+
df_branch[Headers.TUBING_MEASURED_DEPTH].to_numpy(),
|
|
616
|
+
df_device[Headers.MEASURED_DEPTH].to_numpy(),
|
|
617
|
+
df_device[Headers.START_SEGMENT_NUMBER].to_numpy(),
|
|
598
618
|
)
|
|
599
619
|
# but for the most downstream annulus segment
|
|
600
620
|
# its outlet is the device segment
|
|
601
621
|
out_segment[0] = device_segment[0]
|
|
602
622
|
# determining segment position
|
|
603
|
-
md_ = df_branch[Headers.
|
|
623
|
+
md_ = df_branch[Headers.TUBING_MEASURED_DEPTH].to_numpy() + annulus_length
|
|
604
624
|
md_[0] = md_[0] + annulus_length
|
|
605
625
|
df_annulus_upstream[Headers.OUT] = out_segment
|
|
606
|
-
df_annulus_upstream[Headers.
|
|
607
|
-
df_annulus_upstream[Headers.
|
|
608
|
-
df_annulus_upstream[Headers.
|
|
626
|
+
df_annulus_upstream[Headers.MEASURED_DEPTH] = md_
|
|
627
|
+
df_annulus_upstream[Headers.TRUE_VERTICAL_DEPTH] = df_branch[Headers.TRUE_VERTICAL_DEPTH].to_numpy()
|
|
628
|
+
df_annulus_upstream[Headers.WELL_BORE_DIAMETER] = df_branch[Headers.OUTER_DIAMETER].to_numpy()
|
|
609
629
|
df_annulus_upstream[Headers.ROUGHNESS] = df_branch[Headers.ROUGHNESS].to_numpy()
|
|
610
630
|
device_segment = get_outlet_segment(
|
|
611
|
-
df_active[Headers.
|
|
631
|
+
df_active[Headers.TUBING_MEASURED_DEPTH].to_numpy(),
|
|
632
|
+
df_device[Headers.MEASURED_DEPTH].to_numpy(),
|
|
633
|
+
df_device[Headers.START_SEGMENT_NUMBER].to_numpy(),
|
|
612
634
|
)
|
|
613
635
|
annulus_segment = get_outlet_segment(
|
|
614
|
-
df_active[Headers.
|
|
615
|
-
df_annulus_upstream[Headers.
|
|
616
|
-
df_annulus_upstream[Headers.
|
|
636
|
+
df_active[Headers.TUBING_MEASURED_DEPTH].to_numpy(),
|
|
637
|
+
df_annulus_upstream[Headers.MEASURED_DEPTH].to_numpy(),
|
|
638
|
+
df_annulus_upstream[Headers.START_SEGMENT_NUMBER].to_numpy(),
|
|
617
639
|
)
|
|
618
640
|
outlet_segment = get_outlet_segment(
|
|
619
|
-
df_active[Headers.
|
|
620
|
-
df_annulus_upstream[Headers.
|
|
641
|
+
df_active[Headers.TUBING_MEASURED_DEPTH].to_numpy(),
|
|
642
|
+
df_annulus_upstream[Headers.MEASURED_DEPTH].to_numpy(),
|
|
621
643
|
df_annulus_upstream[Headers.OUT].to_numpy(),
|
|
622
644
|
)
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
645
|
+
df_well_segments_link_upstream = pd.DataFrame(
|
|
646
|
+
{
|
|
647
|
+
Headers.WELL: [well_name] * device_segment.shape[0],
|
|
648
|
+
Headers.ANNULUS: annulus_segment,
|
|
649
|
+
Headers.DEVICE: device_segment,
|
|
650
|
+
Headers.OUT: outlet_segment,
|
|
651
|
+
}
|
|
628
652
|
)
|
|
629
|
-
#
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
653
|
+
# WELL_SEGMENTS_LINK is only for those segments whose outlet segment is not a device segment.
|
|
654
|
+
df_well_segments_link_upstream = df_well_segments_link_upstream[
|
|
655
|
+
df_well_segments_link_upstream[Headers.DEVICE] != df_well_segments_link_upstream[Headers.OUT]
|
|
656
|
+
]
|
|
657
|
+
return df_annulus_upstream, df_well_segments_link_upstream
|
|
633
658
|
|
|
634
659
|
|
|
635
660
|
def connect_compseg_icv(
|
|
636
|
-
df_reservoir: pd.DataFrame, df_device: pd.DataFrame, df_annulus: pd.DataFrame,
|
|
661
|
+
df_reservoir: pd.DataFrame, df_device: pd.DataFrame, df_annulus: pd.DataFrame, df_completion: pd.DataFrame
|
|
637
662
|
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
638
|
-
"""Connect
|
|
663
|
+
"""Connect COMPLETION_SEGMENTS with the correct depth due to ICV segmenting combination.
|
|
639
664
|
|
|
640
665
|
Args:
|
|
641
|
-
df_reservoir:
|
|
642
|
-
df_device:
|
|
643
|
-
df_annulus:
|
|
644
|
-
|
|
666
|
+
df_reservoir: Reservoir data.
|
|
667
|
+
df_device: Device data for this well and lateral.
|
|
668
|
+
df_annulus: Annulus data for this well and lateral.
|
|
669
|
+
df_completion: Completion data.
|
|
645
670
|
|
|
646
671
|
Returns:
|
|
647
|
-
|
|
672
|
+
Completion segments for devices and completion segments for annulus.
|
|
648
673
|
"""
|
|
649
674
|
_MARKER_MEASURED_DEPTH = "TEMPORARY_MARKER_MEASURED_DEPTH"
|
|
650
|
-
df_temp =
|
|
651
|
-
(
|
|
675
|
+
df_temp = df_completion[
|
|
676
|
+
(df_completion[Headers.VALVES_PER_JOINT] > 0.0) | (df_completion[Headers.DEVICE_TYPE] == Content.PERFORATED)
|
|
677
|
+
]
|
|
678
|
+
df_completion_table_clean = df_temp[
|
|
679
|
+
(df_temp[Headers.ANNULUS] != Content.PACKER) & (df_temp[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_VALVE)
|
|
652
680
|
]
|
|
653
|
-
df_completion_table_clean = df_temp[(df_temp[Headers.ANNULUS] != "PA") & (df_temp[Headers.DEVICE_TYPE] == "ICV")]
|
|
654
681
|
df_res = df_reservoir.copy(deep=True)
|
|
655
682
|
|
|
656
|
-
df_res[_MARKER_MEASURED_DEPTH] = df_res[Headers.
|
|
683
|
+
df_res[_MARKER_MEASURED_DEPTH] = df_res[Headers.MEASURED_DEPTH]
|
|
657
684
|
starts = df_completion_table_clean[Headers.START_MEASURED_DEPTH].apply(
|
|
658
685
|
lambda x: max(x, df_res[Headers.START_MEASURED_DEPTH].iloc[0])
|
|
659
686
|
)
|
|
@@ -661,23 +688,34 @@ def connect_compseg_icv(
|
|
|
661
688
|
lambda x: min(x, df_res[Headers.END_MEASURED_DEPTH].iloc[-1])
|
|
662
689
|
)
|
|
663
690
|
for start, end in zip(starts, ends):
|
|
664
|
-
condition =
|
|
691
|
+
condition = (
|
|
692
|
+
f"@df_res.{Headers.MEASURED_DEPTH} >= {start} and @df_res.{Headers.MEASURED_DEPTH} <= {end} "
|
|
693
|
+
f"and @df_res.{Headers.DEVICE_TYPE} == 'ICV'"
|
|
694
|
+
)
|
|
665
695
|
func = float(start + end) / 2
|
|
666
696
|
column_index = df_res.query(condition).index
|
|
667
697
|
df_res.loc[column_index, _MARKER_MEASURED_DEPTH] = func
|
|
668
698
|
|
|
669
699
|
df_compseg_device = pd.merge_asof(
|
|
670
|
-
left=df_res,
|
|
700
|
+
left=df_res,
|
|
701
|
+
right=df_device,
|
|
702
|
+
left_on=_MARKER_MEASURED_DEPTH,
|
|
703
|
+
right_on=Headers.MEASURED_DEPTH,
|
|
704
|
+
direction="nearest",
|
|
671
705
|
)
|
|
672
706
|
df_compseg_annulus = pd.DataFrame()
|
|
673
|
-
if (
|
|
707
|
+
if (df_completion[Headers.ANNULUS] == Content.OPEN_ANNULUS).any():
|
|
674
708
|
df_compseg_annulus = pd.merge_asof(
|
|
675
|
-
left=df_res,
|
|
709
|
+
left=df_res,
|
|
710
|
+
right=df_annulus,
|
|
711
|
+
left_on=_MARKER_MEASURED_DEPTH,
|
|
712
|
+
right_on=Headers.MEASURED_DEPTH,
|
|
713
|
+
direction="nearest",
|
|
676
714
|
).drop(_MARKER_MEASURED_DEPTH, axis=1)
|
|
677
715
|
return df_compseg_device.drop(_MARKER_MEASURED_DEPTH, axis=1), df_compseg_annulus
|
|
678
716
|
|
|
679
717
|
|
|
680
|
-
def
|
|
718
|
+
def prepare_completion_segments(
|
|
681
719
|
well_name: str,
|
|
682
720
|
lateral: int,
|
|
683
721
|
df_reservoir: pd.DataFrame,
|
|
@@ -686,19 +724,19 @@ def prepare_compsegs(
|
|
|
686
724
|
df_completion_table: pd.DataFrame,
|
|
687
725
|
segment_length: float | str,
|
|
688
726
|
) -> pd.DataFrame:
|
|
689
|
-
"""Prepare output for
|
|
727
|
+
"""Prepare output for COMPLETION_SEGMENTS.
|
|
690
728
|
|
|
691
729
|
Args:
|
|
692
730
|
well_name: Well name.
|
|
693
731
|
lateral: Lateral number.
|
|
694
|
-
df_reservoir: The
|
|
695
|
-
df_device:
|
|
696
|
-
df_annulus:
|
|
732
|
+
df_reservoir: The reservoir data.
|
|
733
|
+
df_device: Device data for this well and lateral.
|
|
734
|
+
df_annulus: Annulus data for this well and lateral.
|
|
697
735
|
df_completion_table: DataFrame.
|
|
698
736
|
segment_length: Segment length.
|
|
699
737
|
|
|
700
738
|
Returns:
|
|
701
|
-
|
|
739
|
+
COMPLETION_SEGMENTS DataFrame.
|
|
702
740
|
"""
|
|
703
741
|
df_reservoir = df_reservoir[df_reservoir[Headers.WELL] == well_name]
|
|
704
742
|
df_reservoir = df_reservoir[df_reservoir[Headers.LATERAL] == lateral]
|
|
@@ -709,18 +747,18 @@ def prepare_compsegs(
|
|
|
709
747
|
df_reservoir = df_reservoir[
|
|
710
748
|
(df_reservoir[Headers.ANNULUS_ZONE] > 0)
|
|
711
749
|
| (df_reservoir[Headers.NUMBER_OF_DEVICES] > 0)
|
|
712
|
-
| (df_reservoir[Headers.DEVICE_TYPE] ==
|
|
750
|
+
| (df_reservoir[Headers.DEVICE_TYPE] == Content.PERFORATED)
|
|
713
751
|
]
|
|
714
|
-
# sort device dataframe by
|
|
752
|
+
# sort device dataframe by MEASURED_DEPTH to be used for pd.merge_asof
|
|
715
753
|
if df_reservoir.shape[0] == 0:
|
|
716
754
|
return pd.DataFrame()
|
|
717
|
-
df_device = df_device.sort_values(by=[Headers.
|
|
755
|
+
df_device = df_device.sort_values(by=[Headers.MEASURED_DEPTH])
|
|
718
756
|
if isinstance(segment_length, str):
|
|
719
757
|
if segment_length.upper() == "USER":
|
|
720
758
|
segment_length = -1.0
|
|
721
759
|
icv_segmenting = (
|
|
722
760
|
df_reservoir[Headers.DEVICE_TYPE].nunique() > 1
|
|
723
|
-
and (df_reservoir[Headers.DEVICE_TYPE] ==
|
|
761
|
+
and (df_reservoir[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_VALVE).any()
|
|
724
762
|
and not df_reservoir[Headers.NUMBER_OF_DEVICES].empty
|
|
725
763
|
)
|
|
726
764
|
if df_annulus.empty:
|
|
@@ -728,7 +766,7 @@ def prepare_compsegs(
|
|
|
728
766
|
if isinstance(segment_length, float):
|
|
729
767
|
if segment_length >= 0:
|
|
730
768
|
df_compseg_device = pd.merge_asof(
|
|
731
|
-
left=df_reservoir, right=df_device, on=[Headers.
|
|
769
|
+
left=df_reservoir, right=df_device, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
732
770
|
)
|
|
733
771
|
else:
|
|
734
772
|
# Ensure that tubing segment boundaries as described in the case
|
|
@@ -739,7 +777,9 @@ def prepare_compsegs(
|
|
|
739
777
|
df_reservoir, df_device, df_annulus, df_completion_table
|
|
740
778
|
)
|
|
741
779
|
else:
|
|
742
|
-
df_compseg_device = pd.merge_asof(
|
|
780
|
+
df_compseg_device = pd.merge_asof(
|
|
781
|
+
left=df_reservoir, right=df_device, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
782
|
+
)
|
|
743
783
|
if icv_segmenting:
|
|
744
784
|
df_compseg_device, _ = connect_compseg_icv(df_reservoir, df_device, df_annulus, df_completion_table)
|
|
745
785
|
compseg = pd.DataFrame()
|
|
@@ -750,20 +790,20 @@ def prepare_compsegs(
|
|
|
750
790
|
compseg[Headers.BRANCH] = df_compseg_device[Headers.BRANCH].to_numpy()
|
|
751
791
|
compseg[Headers.START_MEASURED_DEPTH] = df_compseg_device[Headers.START_MEASURED_DEPTH].to_numpy()
|
|
752
792
|
compseg[Headers.END_MEASURED_DEPTH] = df_compseg_device[Headers.END_MEASURED_DEPTH].to_numpy()
|
|
753
|
-
compseg[Headers.
|
|
793
|
+
compseg[Headers.COMPSEGS_DIRECTION] = df_compseg_device[Headers.COMPSEGS_DIRECTION].to_numpy()
|
|
754
794
|
compseg[Headers.DEF] = "3*"
|
|
755
|
-
compseg[Headers.
|
|
795
|
+
compseg[Headers.START_SEGMENT_NUMBER] = df_compseg_device[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
756
796
|
else:
|
|
757
797
|
# sort the df_annulus and df_device
|
|
758
|
-
df_annulus = df_annulus.sort_values(by=[Headers.
|
|
798
|
+
df_annulus = df_annulus.sort_values(by=[Headers.MEASURED_DEPTH])
|
|
759
799
|
if isinstance(segment_length, float):
|
|
760
800
|
# SEGMENTLENGTH = FIXED
|
|
761
801
|
if segment_length >= 0:
|
|
762
802
|
df_compseg_annulus = pd.merge_asof(
|
|
763
|
-
left=df_reservoir, right=df_annulus, on=[Headers.
|
|
803
|
+
left=df_reservoir, right=df_annulus, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
764
804
|
)
|
|
765
805
|
df_compseg_device = pd.merge_asof(
|
|
766
|
-
left=df_reservoir, right=df_device, on=[Headers.
|
|
806
|
+
left=df_reservoir, right=df_device, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
767
807
|
)
|
|
768
808
|
else:
|
|
769
809
|
# Ensure that tubing segment boundaries as described in the case
|
|
@@ -780,27 +820,36 @@ def prepare_compsegs(
|
|
|
780
820
|
df_compseg_annulus.drop([Headers.MARKER], axis=1, inplace=True)
|
|
781
821
|
else:
|
|
782
822
|
df_compseg_annulus = pd.merge_asof(
|
|
783
|
-
left=df_reservoir, right=df_annulus, on=[Headers.
|
|
823
|
+
left=df_reservoir, right=df_annulus, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
824
|
+
)
|
|
825
|
+
df_compseg_device = pd.merge_asof(
|
|
826
|
+
left=df_reservoir, right=df_device, on=[Headers.MEASURED_DEPTH], direction="nearest"
|
|
784
827
|
)
|
|
785
|
-
df_compseg_device = pd.merge_asof(left=df_reservoir, right=df_device, on=[Headers.MD], direction="nearest")
|
|
786
828
|
if icv_segmenting:
|
|
787
829
|
df_compseg_device, df_compseg_annulus = connect_compseg_icv(
|
|
788
830
|
df_reservoir, df_device, df_annulus, df_completion_table
|
|
789
831
|
)
|
|
790
832
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
833
|
+
compseg = pd.DataFrame(
|
|
834
|
+
{
|
|
835
|
+
Headers.I: choose_layer(df_reservoir, df_compseg_annulus, df_compseg_device, Headers.I),
|
|
836
|
+
Headers.J: choose_layer(df_reservoir, df_compseg_annulus, df_compseg_device, Headers.J),
|
|
837
|
+
Headers.K: choose_layer(df_reservoir, df_compseg_annulus, df_compseg_device, Headers.K),
|
|
838
|
+
Headers.BRANCH: choose_layer(df_reservoir, df_compseg_annulus, df_compseg_device, Headers.BRANCH),
|
|
839
|
+
Headers.START_MEASURED_DEPTH: choose_layer(
|
|
840
|
+
df_reservoir, df_compseg_annulus, df_compseg_device, Headers.START_MEASURED_DEPTH
|
|
841
|
+
),
|
|
842
|
+
Headers.END_MEASURED_DEPTH: choose_layer(
|
|
843
|
+
df_reservoir, df_compseg_annulus, df_compseg_device, Headers.END_MEASURED_DEPTH
|
|
844
|
+
),
|
|
845
|
+
Headers.COMPSEGS_DIRECTION: choose_layer(
|
|
846
|
+
df_reservoir, df_compseg_annulus, df_compseg_device, Headers.COMPSEGS_DIRECTION
|
|
847
|
+
),
|
|
848
|
+
Headers.DEF: "3*",
|
|
849
|
+
Headers.START_SEGMENT_NUMBER: choose_layer(
|
|
850
|
+
df_reservoir, df_compseg_annulus, df_compseg_device, Headers.START_SEGMENT_NUMBER
|
|
851
|
+
),
|
|
852
|
+
}
|
|
804
853
|
)
|
|
805
854
|
compseg[Headers.EMPTY] = "/"
|
|
806
855
|
return compseg
|
|
@@ -809,27 +858,28 @@ def prepare_compsegs(
|
|
|
809
858
|
def connect_compseg_usersegment(
|
|
810
859
|
df_reservoir: pd.DataFrame, df_device: pd.DataFrame, df_annulus: pd.DataFrame, df_completion_table: pd.DataFrame
|
|
811
860
|
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
812
|
-
"""Connect
|
|
861
|
+
"""Connect COMPLETION_SEGMENTS with user segmentation.
|
|
813
862
|
|
|
814
863
|
This method will connect df_reservoir with df_device and df_annulus in accordance with its
|
|
815
|
-
depth in the
|
|
864
|
+
depth in the df_completion due to user segmentation method.
|
|
816
865
|
|
|
817
866
|
Args:
|
|
818
|
-
df_reservoir: The
|
|
819
|
-
df_device:
|
|
820
|
-
df_annulus:
|
|
821
|
-
df_completion_table:
|
|
867
|
+
df_reservoir: The reservoir data.
|
|
868
|
+
df_device: Device data for this well and lateral.
|
|
869
|
+
df_annulus: Annulus data for this well and lateral.
|
|
870
|
+
df_completion_table: Completion data.
|
|
822
871
|
|
|
823
872
|
Returns:
|
|
824
|
-
|
|
873
|
+
Completion segments for devices and completion segments for annulus.
|
|
825
874
|
"""
|
|
826
875
|
# check on top of df_res if the completion table is feasible
|
|
827
876
|
df_temp = df_completion_table[
|
|
828
|
-
(df_completion_table[Headers.VALVES_PER_JOINT] > 0.0)
|
|
877
|
+
(df_completion_table[Headers.VALVES_PER_JOINT] > 0.0)
|
|
878
|
+
| (df_completion_table[Headers.DEVICE_TYPE] == Content.PERFORATED)
|
|
829
879
|
]
|
|
830
|
-
df_completion_table_clean = df_temp[(df_temp[Headers.ANNULUS] !=
|
|
880
|
+
df_completion_table_clean = df_temp[(df_temp[Headers.ANNULUS] != Content.PACKER)]
|
|
831
881
|
if not df_annulus.empty:
|
|
832
|
-
df_completion_table_clean = df_completion_table[df_completion_table[Headers.ANNULUS] ==
|
|
882
|
+
df_completion_table_clean = df_completion_table[df_completion_table[Headers.ANNULUS] == Content.OPEN_ANNULUS]
|
|
833
883
|
df_completion_table_clean = df_completion_table_clean[
|
|
834
884
|
(df_completion_table_clean[Headers.END_MEASURED_DEPTH] > df_reservoir[Headers.START_MEASURED_DEPTH].iloc[0])
|
|
835
885
|
]
|
|
@@ -845,7 +895,7 @@ def connect_compseg_usersegment(
|
|
|
845
895
|
)
|
|
846
896
|
func = 1
|
|
847
897
|
for start, end in zip(starts, ends):
|
|
848
|
-
condition = f"@df_res.
|
|
898
|
+
condition = f"@df_res.{Headers.MEASURED_DEPTH} >= {start} and @df_res.{Headers.MEASURED_DEPTH} <= {end}"
|
|
849
899
|
column_to_modify = Headers.MARKER
|
|
850
900
|
column_index = df_res.query(condition).index
|
|
851
901
|
df_res.loc[column_index, column_to_modify] = func
|
|
@@ -877,8 +927,8 @@ def connect_compseg_usersegment(
|
|
|
877
927
|
|
|
878
928
|
def choose_layer(
|
|
879
929
|
df_reservoir: pd.DataFrame, df_compseg_annulus: pd.DataFrame, df_compseg_device: pd.DataFrame, parameter: str
|
|
880
|
-
) -> np.
|
|
881
|
-
"""Choose relevant parameters from either
|
|
930
|
+
) -> npt.NDArray[np.float64 | np.int64]:
|
|
931
|
+
"""Choose relevant parameters from either completion segments annulus or completion segments device.
|
|
882
932
|
|
|
883
933
|
Args:
|
|
884
934
|
df_reservoir:
|
|
@@ -895,24 +945,24 @@ def choose_layer(
|
|
|
895
945
|
return np.where(
|
|
896
946
|
branch_num > 0,
|
|
897
947
|
df_compseg_annulus[parameter].to_numpy(),
|
|
898
|
-
np.where((ndevice > 0) | (dev_type ==
|
|
948
|
+
np.where((ndevice > 0) | (dev_type == Content.PERFORATED), df_compseg_device[parameter].to_numpy(), -1),
|
|
899
949
|
)
|
|
900
950
|
|
|
901
951
|
|
|
902
952
|
def fix_well_id(df_reservoir: pd.DataFrame, df_completion: pd.DataFrame) -> pd.DataFrame:
|
|
903
|
-
"""Ensure that well/casing inner diameter in the
|
|
953
|
+
"""Ensure that well/casing inner diameter in the COMPLETION_DATA section is in agreement with
|
|
904
954
|
the case/config file and not the input schedule file.
|
|
905
955
|
|
|
906
956
|
Args:
|
|
907
|
-
df_reservoir: Reservoir
|
|
908
|
-
|
|
957
|
+
df_reservoir: Reservoir data.
|
|
958
|
+
df_completion: Completion data for current well/lateral.
|
|
909
959
|
|
|
910
960
|
Returns:
|
|
911
|
-
Corrected DataFrame for current well/lateral with inner diameter taken from the
|
|
961
|
+
Corrected DataFrame for current well/lateral with inner diameter taken from the casefile object.
|
|
912
962
|
"""
|
|
913
963
|
df_reservoir = df_reservoir.copy(deep=True)
|
|
914
964
|
completion_diameters = []
|
|
915
|
-
for md_reservoir in df_reservoir[Headers.
|
|
965
|
+
for md_reservoir in df_reservoir[Headers.MEASURED_DEPTH]:
|
|
916
966
|
for start_completion, outer_inner_diameter_completion, end_completion in zip(
|
|
917
967
|
df_completion[Headers.START_MEASURED_DEPTH],
|
|
918
968
|
df_completion[Headers.OUTER_DIAMETER],
|
|
@@ -921,31 +971,31 @@ def fix_well_id(df_reservoir: pd.DataFrame, df_completion: pd.DataFrame) -> pd.D
|
|
|
921
971
|
if start_completion <= md_reservoir <= end_completion:
|
|
922
972
|
completion_diameters.append(outer_inner_diameter_completion)
|
|
923
973
|
break
|
|
924
|
-
df_reservoir[Headers.
|
|
974
|
+
df_reservoir[Headers.WELL_BORE_DIAMETER] = completion_diameters
|
|
925
975
|
return df_reservoir
|
|
926
976
|
|
|
927
977
|
|
|
928
|
-
def
|
|
929
|
-
well_name: str, lateral: int, df_reservoir: pd.DataFrame,
|
|
978
|
+
def prepare_completion_data(
|
|
979
|
+
well_name: str, lateral: int, df_reservoir: pd.DataFrame, df_completion: pd.DataFrame
|
|
930
980
|
) -> pd.DataFrame:
|
|
931
|
-
"""Prepare
|
|
981
|
+
"""Prepare COMPLETION_DATA data frame.
|
|
932
982
|
|
|
933
983
|
Args:
|
|
934
984
|
well_name: Well name.
|
|
935
985
|
lateral: Lateral number.
|
|
936
|
-
df_reservoir:
|
|
937
|
-
|
|
986
|
+
df_reservoir: Reservoir data.
|
|
987
|
+
df_completion: Completion data.
|
|
938
988
|
|
|
939
989
|
Returns:
|
|
940
|
-
|
|
990
|
+
COMPLETION_DATA.
|
|
941
991
|
"""
|
|
942
992
|
df_reservoir = df_reservoir[df_reservoir[Headers.WELL] == well_name]
|
|
943
993
|
df_reservoir = df_reservoir[df_reservoir[Headers.LATERAL] == lateral]
|
|
944
994
|
df_reservoir = df_reservoir[
|
|
945
995
|
(df_reservoir[Headers.ANNULUS_ZONE] > 0)
|
|
946
|
-
| ((df_reservoir[Headers.NUMBER_OF_DEVICES] > 0) | (df_reservoir[Headers.DEVICE_TYPE] ==
|
|
996
|
+
| ((df_reservoir[Headers.NUMBER_OF_DEVICES] > 0) | (df_reservoir[Headers.DEVICE_TYPE] == Content.PERFORATED))
|
|
947
997
|
]
|
|
948
|
-
if df_reservoir.
|
|
998
|
+
if df_reservoir.empty:
|
|
949
999
|
return pd.DataFrame()
|
|
950
1000
|
compdat = pd.DataFrame()
|
|
951
1001
|
compdat[Headers.WELL] = [well_name] * df_reservoir.shape[0]
|
|
@@ -954,15 +1004,19 @@ def prepare_compdat(
|
|
|
954
1004
|
compdat[Headers.K] = df_reservoir[Headers.K].to_numpy()
|
|
955
1005
|
compdat[Headers.K2] = df_reservoir[Headers.K2].to_numpy()
|
|
956
1006
|
compdat[Headers.FLAG] = df_reservoir[Headers.STATUS].to_numpy()
|
|
957
|
-
compdat[Headers.
|
|
1007
|
+
compdat[Headers.SATURATION_FUNCTION_REGION_NUMBERS] = df_reservoir[
|
|
1008
|
+
Headers.SATURATION_FUNCTION_REGION_NUMBERS
|
|
1009
|
+
].to_numpy()
|
|
958
1010
|
compdat[Headers.CONNECTION_FACTOR] = df_reservoir[Headers.CONNECTION_FACTOR].to_numpy()
|
|
959
|
-
compdat[Headers.
|
|
960
|
-
|
|
961
|
-
|
|
1011
|
+
compdat[Headers.WELL_BORE_DIAMETER] = fix_well_id(df_reservoir, df_completion)[
|
|
1012
|
+
Headers.WELL_BORE_DIAMETER
|
|
1013
|
+
].to_numpy()
|
|
1014
|
+
compdat[Headers.FORMATION_PERMEABILITY_THICKNESS] = df_reservoir[
|
|
1015
|
+
Headers.FORMATION_PERMEABILITY_THICKNESS
|
|
962
1016
|
].to_numpy()
|
|
963
1017
|
compdat[Headers.SKIN] = df_reservoir[Headers.SKIN].to_numpy()
|
|
964
|
-
compdat[Headers.
|
|
965
|
-
compdat[Headers.
|
|
1018
|
+
compdat[Headers.D_FACTOR] = df_reservoir[Headers.D_FACTOR].to_numpy()
|
|
1019
|
+
compdat[Headers.COMPDAT_DIRECTION] = df_reservoir[Headers.COMPDAT_DIRECTION].to_numpy()
|
|
966
1020
|
compdat[Headers.RO] = df_reservoir[Headers.RO].to_numpy()
|
|
967
1021
|
# remove default columns
|
|
968
1022
|
compdat = trim_pandas(compdat)
|
|
@@ -970,36 +1024,39 @@ def prepare_compdat(
|
|
|
970
1024
|
return compdat
|
|
971
1025
|
|
|
972
1026
|
|
|
973
|
-
def
|
|
974
|
-
|
|
1027
|
+
def prepare_autonomous_inflow_control_device(
|
|
1028
|
+
well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame
|
|
1029
|
+
) -> pd.DataFrame:
|
|
1030
|
+
"""Prepare AUTONOMOUS_INFLOW_CONTROL_DEVICE data frame.
|
|
975
1031
|
|
|
976
1032
|
Args:
|
|
977
1033
|
well_name: Well name.
|
|
978
|
-
|
|
979
|
-
df_well: df_well from class CreateWells.
|
|
1034
|
+
df_well: Well data.
|
|
980
1035
|
df_device: From function prepare_device_layer for this well and this lateral.
|
|
981
1036
|
|
|
982
1037
|
Returns:
|
|
983
|
-
|
|
1038
|
+
AUTONOMOUS_INFLOW_CONTROL_DEVICE.
|
|
984
1039
|
"""
|
|
985
|
-
df_well = df_well[df_well[Headers.
|
|
986
|
-
df_well = df_well[df_well[Headers.LATERAL] == lateral]
|
|
987
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1040
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
988
1041
|
if df_well.shape[0] == 0:
|
|
989
1042
|
return pd.DataFrame()
|
|
990
1043
|
df_merge = pd.merge_asof(
|
|
991
|
-
left=df_device,
|
|
1044
|
+
left=df_device,
|
|
1045
|
+
right=df_well,
|
|
1046
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1047
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1048
|
+
direction="nearest",
|
|
992
1049
|
)
|
|
993
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1050
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_DEVICE]
|
|
994
1051
|
wsegaicd = pd.DataFrame()
|
|
995
1052
|
if df_merge.shape[0] > 0:
|
|
996
1053
|
wsegaicd[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
997
|
-
wsegaicd[Headers.
|
|
998
|
-
wsegaicd[Headers.
|
|
999
|
-
wsegaicd[Headers.
|
|
1000
|
-
wsegaicd[Headers.
|
|
1001
|
-
wsegaicd[Headers.
|
|
1002
|
-
wsegaicd[Headers.
|
|
1054
|
+
wsegaicd[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1055
|
+
wsegaicd[Headers.END_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1056
|
+
wsegaicd[Headers.STRENGTH] = df_merge[Headers.STRENGTH].to_numpy()
|
|
1057
|
+
wsegaicd[Headers.SCALE_FACTOR] = df_merge[Headers.SCALE_FACTOR].to_numpy()
|
|
1058
|
+
wsegaicd[Headers.CALIBRATION_FLUID_DENSITY] = df_merge[Headers.AICD_CALIBRATION_FLUID_DENSITY].to_numpy()
|
|
1059
|
+
wsegaicd[Headers.CALIBRATION_FLUID_VISCOSITY] = df_merge[Headers.AICD_FLUID_VISCOSITY].to_numpy()
|
|
1003
1060
|
wsegaicd[Headers.DEF] = ["5*"] * df_merge.shape[0]
|
|
1004
1061
|
wsegaicd[Headers.X] = df_merge[Headers.X].to_numpy()
|
|
1005
1062
|
wsegaicd[Headers.Y] = df_merge[Headers.Y].to_numpy()
|
|
@@ -1014,75 +1071,80 @@ def prepare_wsegaicd(well_name: str, lateral: int, df_well: pd.DataFrame, df_dev
|
|
|
1014
1071
|
return wsegaicd
|
|
1015
1072
|
|
|
1016
1073
|
|
|
1017
|
-
def
|
|
1018
|
-
"""Prepare
|
|
1074
|
+
def prepare_inflow_control_device(well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
|
|
1075
|
+
"""Prepare INFLOW_CONTROL_DEVICE data frame.
|
|
1019
1076
|
|
|
1020
1077
|
Args:
|
|
1021
1078
|
well_name: Well name.
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
df_device: From function prepare_device_layer for this well and this lateral.
|
|
1079
|
+
df_well: Well data.
|
|
1080
|
+
df_device: Device data for this well and lateral.
|
|
1025
1081
|
|
|
1026
1082
|
Returns:
|
|
1027
|
-
|
|
1083
|
+
INFLOW_CONTROL_DEVICE.
|
|
1028
1084
|
"""
|
|
1029
|
-
df_well = df_well[df_well[Headers.
|
|
1030
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1085
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1031
1086
|
if df_well.shape[0] == 0:
|
|
1032
1087
|
return pd.DataFrame()
|
|
1033
1088
|
df_merge = pd.merge_asof(
|
|
1034
|
-
left=df_device,
|
|
1089
|
+
left=df_device,
|
|
1090
|
+
right=df_well,
|
|
1091
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1092
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1093
|
+
direction="nearest",
|
|
1035
1094
|
)
|
|
1036
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1095
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_DEVICE]
|
|
1037
1096
|
wsegsicd = pd.DataFrame()
|
|
1038
1097
|
if df_merge.shape[0] > 0:
|
|
1039
1098
|
wsegsicd[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1040
|
-
wsegsicd[Headers.
|
|
1041
|
-
wsegsicd[Headers.
|
|
1042
|
-
wsegsicd[Headers.
|
|
1043
|
-
wsegsicd[Headers.
|
|
1044
|
-
wsegsicd[Headers.
|
|
1045
|
-
wsegsicd[Headers.
|
|
1099
|
+
wsegsicd[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1100
|
+
wsegsicd[Headers.END_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1101
|
+
wsegsicd[Headers.STRENGTH] = df_merge[Headers.STRENGTH].to_numpy()
|
|
1102
|
+
wsegsicd[Headers.SCALE_FACTOR] = df_merge[Headers.SCALE_FACTOR].to_numpy()
|
|
1103
|
+
wsegsicd[Headers.CALIBRATION_FLUID_DENSITY] = df_merge[Headers.CALIBRATION_FLUID_DENSITY].to_numpy()
|
|
1104
|
+
wsegsicd[Headers.CALIBRATION_FLUID_VISCOSITY] = df_merge[Headers.CALIBRATION_FLUID_VISCOSITY].to_numpy()
|
|
1046
1105
|
wsegsicd[Headers.WATER_CUT] = df_merge[Headers.WATER_CUT].to_numpy()
|
|
1047
1106
|
wsegsicd[Headers.EMPTY] = "/"
|
|
1048
1107
|
return wsegsicd
|
|
1049
1108
|
|
|
1050
1109
|
|
|
1051
|
-
def
|
|
1052
|
-
"""Prepare
|
|
1110
|
+
def prepare_valve(well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
|
|
1111
|
+
"""Prepare WELL_SEGMENTS_VALVE data frame.
|
|
1053
1112
|
|
|
1054
1113
|
Args:
|
|
1055
1114
|
well_name: Well name.
|
|
1056
|
-
|
|
1057
|
-
df_well: df_well from class CreateWells.
|
|
1115
|
+
df_well: Well data.
|
|
1058
1116
|
df_device: From function prepare_device_layer for this well and this lateral.
|
|
1059
1117
|
|
|
1060
1118
|
Returns:
|
|
1061
|
-
|
|
1119
|
+
WELL_SEGMENTS_VALVE.
|
|
1062
1120
|
"""
|
|
1063
|
-
df_well = df_well[df_well[Headers.
|
|
1064
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1121
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1065
1122
|
if df_well.shape[0] == 0:
|
|
1066
1123
|
return pd.DataFrame()
|
|
1067
1124
|
df_merge = pd.merge_asof(
|
|
1068
|
-
left=df_device,
|
|
1125
|
+
left=df_device,
|
|
1126
|
+
right=df_well,
|
|
1127
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1128
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1129
|
+
direction="nearest",
|
|
1069
1130
|
)
|
|
1070
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1131
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.VALVE].reset_index(drop=True)
|
|
1071
1132
|
wsegvalv = pd.DataFrame()
|
|
1072
1133
|
if df_merge.shape[0] > 0:
|
|
1073
1134
|
wsegvalv[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1074
|
-
wsegvalv[Headers.
|
|
1135
|
+
wsegvalv[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1075
1136
|
# the Cv is already corrected by the scaling factor
|
|
1076
|
-
wsegvalv[Headers.
|
|
1077
|
-
wsegvalv[Headers.
|
|
1078
|
-
wsegvalv[Headers.
|
|
1079
|
-
wsegvalv[Headers.
|
|
1080
|
-
|
|
1137
|
+
wsegvalv[Headers.FLOW_COEFFICIENT] = df_merge[Headers.FLOW_COEFFICIENT].to_numpy()
|
|
1138
|
+
wsegvalv[Headers.FLOW_CROSS_SECTIONAL_AREA] = df_merge[Headers.FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1139
|
+
wsegvalv[Headers.ADDITIONAL_PIPE_LENGTH_FRICTION_PRESSURE_DROP] = "5*"
|
|
1140
|
+
wsegvalv[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA] = df_merge[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA].fillna(
|
|
1141
|
+
df_merge[Headers.FLOW_CROSS_SECTIONAL_AREA]
|
|
1142
|
+
)
|
|
1081
1143
|
wsegvalv[Headers.EMPTY] = "/"
|
|
1082
1144
|
return wsegvalv
|
|
1083
1145
|
|
|
1084
1146
|
|
|
1085
|
-
def
|
|
1147
|
+
def prepare_inflow_control_valve(
|
|
1086
1148
|
well_name: str,
|
|
1087
1149
|
lateral: int,
|
|
1088
1150
|
df_well: pd.DataFrame,
|
|
@@ -1091,39 +1153,59 @@ def prepare_wsegicv(
|
|
|
1091
1153
|
df_icv_tubing: pd.DataFrame,
|
|
1092
1154
|
df_icv: pd.DataFrame,
|
|
1093
1155
|
) -> pd.DataFrame:
|
|
1094
|
-
"""Prepare
|
|
1156
|
+
"""Prepare INFLOW_CONTROL_VALVE DataFrame with WELL_SEGMENTS_VALVE format. Include ICVs in device and tubing layer.
|
|
1095
1157
|
|
|
1096
1158
|
Args:
|
|
1097
1159
|
well_name: Well name.
|
|
1098
1160
|
lateral: Lateral number.
|
|
1099
|
-
df_well:
|
|
1161
|
+
df_well: Well data.
|
|
1100
1162
|
df_device: From function prepare_device_layer for this well and this lateral.
|
|
1101
1163
|
df_tubing: From function prepare_tubing_layer for this well and this lateral.
|
|
1102
1164
|
df_icv_tubing: df_icv_tubing completion from class ReadCaseFile.
|
|
1103
|
-
df_icv: df_icv for
|
|
1165
|
+
df_icv: df_icv for INFLOW_CONTROL_VALVE keyword from class ReadCaseFile.
|
|
1104
1166
|
|
|
1105
1167
|
Returns:
|
|
1106
1168
|
Dataframe for ICV.
|
|
1107
1169
|
"""
|
|
1108
1170
|
df_well = df_well[
|
|
1109
1171
|
(df_well[Headers.LATERAL] == lateral)
|
|
1110
|
-
& ((df_well[Headers.DEVICE_TYPE] ==
|
|
1172
|
+
& ((df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0))
|
|
1111
1173
|
]
|
|
1112
1174
|
if df_well.empty:
|
|
1113
1175
|
return df_well
|
|
1114
1176
|
df_merge = pd.merge_asof(
|
|
1115
|
-
left=df_device,
|
|
1177
|
+
left=df_device,
|
|
1178
|
+
right=df_well,
|
|
1179
|
+
left_on=Headers.MEASURED_DEPTH,
|
|
1180
|
+
right_on=Headers.TUBING_MEASURED_DEPTH,
|
|
1181
|
+
direction="nearest",
|
|
1116
1182
|
)
|
|
1117
1183
|
wsegicv = pd.DataFrame()
|
|
1118
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1184
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_VALVE]
|
|
1119
1185
|
if not df_merge.empty:
|
|
1120
1186
|
wsegicv = df_merge.copy()
|
|
1121
|
-
wsegicv = wsegicv[
|
|
1187
|
+
wsegicv = wsegicv[
|
|
1188
|
+
[
|
|
1189
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1190
|
+
Headers.FLOW_COEFFICIENT,
|
|
1191
|
+
Headers.FLOW_CROSS_SECTIONAL_AREA,
|
|
1192
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1193
|
+
]
|
|
1194
|
+
]
|
|
1122
1195
|
wsegicv[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1123
1196
|
wsegicv[Headers.DEFAULTS] = "5*"
|
|
1124
|
-
wsegicv[Headers.
|
|
1197
|
+
wsegicv[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA] = wsegicv[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA].fillna(
|
|
1198
|
+
df_merge[Headers.FLOW_CROSS_SECTIONAL_AREA]
|
|
1199
|
+
)
|
|
1125
1200
|
wsegicv = wsegicv.reindex(
|
|
1126
|
-
columns=[
|
|
1201
|
+
columns=[
|
|
1202
|
+
Headers.WELL,
|
|
1203
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1204
|
+
Headers.FLOW_COEFFICIENT,
|
|
1205
|
+
Headers.FLOW_CROSS_SECTIONAL_AREA,
|
|
1206
|
+
Headers.DEFAULTS,
|
|
1207
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1208
|
+
]
|
|
1127
1209
|
)
|
|
1128
1210
|
wsegicv[Headers.EMPTY] = "/"
|
|
1129
1211
|
# create tubing icv table
|
|
@@ -1135,90 +1217,116 @@ def prepare_wsegicv(
|
|
|
1135
1217
|
left=df_merge_tubing,
|
|
1136
1218
|
right=df_tubing,
|
|
1137
1219
|
left_on=Headers.START_MEASURED_DEPTH,
|
|
1138
|
-
right_on=Headers.
|
|
1220
|
+
right_on=Headers.MEASURED_DEPTH,
|
|
1139
1221
|
direction="nearest",
|
|
1140
1222
|
)
|
|
1141
1223
|
df_temp = df_merge_tubing.copy()
|
|
1142
|
-
df_temp = df_temp[
|
|
1224
|
+
df_temp = df_temp[
|
|
1225
|
+
[
|
|
1226
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1227
|
+
Headers.FLOW_COEFFICIENT,
|
|
1228
|
+
Headers.FLOW_CROSS_SECTIONAL_AREA,
|
|
1229
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1230
|
+
]
|
|
1231
|
+
]
|
|
1143
1232
|
df_temp[Headers.WELL] = [well_name] * df_merge_tubing.shape[0]
|
|
1144
1233
|
df_temp[Headers.DEFAULTS] = "5*"
|
|
1145
|
-
df_temp[Headers.
|
|
1234
|
+
df_temp[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA] = df_temp[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA].fillna(
|
|
1235
|
+
math.pi * 0.5 * df_tubing[Headers.WELL_BORE_DIAMETER] ** 2
|
|
1236
|
+
)
|
|
1146
1237
|
df_temp = df_temp.reindex(
|
|
1147
|
-
columns=[
|
|
1238
|
+
columns=[
|
|
1239
|
+
Headers.WELL,
|
|
1240
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1241
|
+
Headers.FLOW_COEFFICIENT,
|
|
1242
|
+
Headers.FLOW_CROSS_SECTIONAL_AREA,
|
|
1243
|
+
Headers.DEFAULTS,
|
|
1244
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1245
|
+
]
|
|
1148
1246
|
)
|
|
1149
1247
|
df_temp[Headers.EMPTY] = "/"
|
|
1150
1248
|
wsegicv = pd.concat([wsegicv, df_temp], axis=0).reset_index(drop=True)
|
|
1151
1249
|
return wsegicv
|
|
1152
1250
|
|
|
1153
1251
|
|
|
1154
|
-
def
|
|
1252
|
+
def prepare_density_activated_recovery(well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
|
|
1155
1253
|
"""Prepare data frame for DAR.
|
|
1156
1254
|
|
|
1157
1255
|
Args:
|
|
1158
1256
|
well_name: Well name.
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
df_device: From function prepare_device_layer for this well and this lateral.
|
|
1257
|
+
df_well: Well data.
|
|
1258
|
+
df_device: Device data for this well and lateral.
|
|
1162
1259
|
|
|
1163
1260
|
Returns:
|
|
1164
1261
|
DataFrame for DAR.
|
|
1165
1262
|
"""
|
|
1166
|
-
df_well = df_well[df_well[Headers.
|
|
1167
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1263
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1168
1264
|
if df_well.shape[0] == 0:
|
|
1169
1265
|
return pd.DataFrame()
|
|
1170
1266
|
df_merge = pd.merge_asof(
|
|
1171
|
-
left=df_device,
|
|
1267
|
+
left=df_device,
|
|
1268
|
+
right=df_well,
|
|
1269
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1270
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1271
|
+
direction="nearest",
|
|
1172
1272
|
)
|
|
1173
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1273
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.DENSITY_ACTIVATED_RECOVERY]
|
|
1174
1274
|
wsegdar = pd.DataFrame()
|
|
1175
1275
|
if df_merge.shape[0] > 0:
|
|
1176
1276
|
wsegdar[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1177
|
-
wsegdar[Headers.
|
|
1277
|
+
wsegdar[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1178
1278
|
# the Cv is already corrected by the scaling factor
|
|
1179
|
-
wsegdar[Headers.
|
|
1180
|
-
wsegdar[Headers.
|
|
1181
|
-
wsegdar[Headers.
|
|
1182
|
-
wsegdar[Headers.
|
|
1183
|
-
wsegdar[Headers.
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
wsegdar[Headers.
|
|
1279
|
+
wsegdar[Headers.FLOW_COEFFICIENT] = df_merge[Headers.FLOW_COEFFICIENT].to_numpy()
|
|
1280
|
+
wsegdar[Headers.OIL_FLOW_CROSS_SECTIONAL_AREA] = df_merge[Headers.OIL_FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1281
|
+
wsegdar[Headers.GAS_FLOW_CROSS_SECTIONAL_AREA] = df_merge[Headers.GAS_FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1282
|
+
wsegdar[Headers.WATER_FLOW_CROSS_SECTIONAL_AREA] = df_merge[Headers.WATER_FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1283
|
+
wsegdar[Headers.WATER_HOLDUP_FRACTION_LOW_CUTOFF] = df_merge[
|
|
1284
|
+
Headers.WATER_HOLDUP_FRACTION_LOW_CUTOFF
|
|
1285
|
+
].to_numpy()
|
|
1286
|
+
wsegdar[Headers.WATER_HOLDUP_FRACTION_HIGH_CUTOFF] = df_merge[
|
|
1287
|
+
Headers.WATER_HOLDUP_FRACTION_HIGH_CUTOFF
|
|
1288
|
+
].to_numpy()
|
|
1289
|
+
wsegdar[Headers.GAS_HOLDUP_FRACTION_LOW_CUTOFF] = df_merge[Headers.GAS_HOLDUP_FRACTION_LOW_CUTOFF].to_numpy()
|
|
1290
|
+
wsegdar[Headers.GAS_HOLDUP_FRACTION_HIGH_CUTOFF] = df_merge[Headers.GAS_HOLDUP_FRACTION_HIGH_CUTOFF].to_numpy()
|
|
1187
1291
|
wsegdar[Headers.DEFAULTS] = "5*"
|
|
1188
|
-
wsegdar[Headers.
|
|
1292
|
+
wsegdar[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA] = wsegdar[Headers.OIL_FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1189
1293
|
wsegdar[Headers.EMPTY] = "/"
|
|
1190
1294
|
return wsegdar
|
|
1191
1295
|
|
|
1192
1296
|
|
|
1193
|
-
def
|
|
1297
|
+
def prepare_autonomous_inflow_control_valve(
|
|
1298
|
+
well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame
|
|
1299
|
+
) -> pd.DataFrame:
|
|
1194
1300
|
"""Prepare data frame for AICV.
|
|
1195
1301
|
|
|
1196
1302
|
Args:
|
|
1197
1303
|
well_name: Well name.
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
df_device: From function prepare_device_layer for this well and this lateral.
|
|
1304
|
+
df_well: Well data.
|
|
1305
|
+
df_device: Device data for this well and lateral.
|
|
1201
1306
|
|
|
1202
1307
|
Returns:
|
|
1203
1308
|
DataFrame for AICV.
|
|
1204
1309
|
"""
|
|
1205
|
-
df_well = df_well[df_well[Headers.
|
|
1206
|
-
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1310
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1207
1311
|
if df_well.shape[0] == 0:
|
|
1208
1312
|
return pd.DataFrame()
|
|
1209
1313
|
df_merge = pd.merge_asof(
|
|
1210
|
-
left=df_device,
|
|
1314
|
+
left=df_device,
|
|
1315
|
+
right=df_well,
|
|
1316
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1317
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1318
|
+
direction="nearest",
|
|
1211
1319
|
)
|
|
1212
|
-
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] ==
|
|
1320
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_VALVE]
|
|
1213
1321
|
wsegaicv = pd.DataFrame()
|
|
1214
1322
|
if df_merge.shape[0] > 0:
|
|
1215
1323
|
wsegaicv[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1216
|
-
wsegaicv[Headers.
|
|
1217
|
-
wsegaicv[Headers.
|
|
1324
|
+
wsegaicv[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1325
|
+
wsegaicv[Headers.END_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1218
1326
|
wsegaicv[Headers.ALPHA_MAIN] = df_merge[Headers.ALPHA_MAIN].to_numpy()
|
|
1219
|
-
wsegaicv[Headers.
|
|
1220
|
-
wsegaicv[Headers.
|
|
1221
|
-
wsegaicv[Headers.
|
|
1327
|
+
wsegaicv[Headers.SCALE_FACTOR] = df_merge[Headers.SCALE_FACTOR].to_numpy()
|
|
1328
|
+
wsegaicv[Headers.CALIBRATION_FLUID_DENSITY] = df_merge[Headers.AICV_CALIBRATION_FLUID_DENSITY].to_numpy()
|
|
1329
|
+
wsegaicv[Headers.CALIBRATION_FLUID_VISCOSITY] = df_merge[Headers.AICV_FLUID_VISCOSITY].to_numpy()
|
|
1222
1330
|
wsegaicv[Headers.DEF] = ["5*"] * df_merge.shape[0]
|
|
1223
1331
|
wsegaicv[Headers.X_MAIN] = df_merge[Headers.X_MAIN].to_numpy()
|
|
1224
1332
|
wsegaicv[Headers.Y_MAIN] = df_merge[Headers.Y_MAIN].to_numpy()
|
|
@@ -1238,8 +1346,8 @@ def prepare_wsegaicv(well_name: str, lateral: int, df_well: pd.DataFrame, df_dev
|
|
|
1238
1346
|
wsegaicv[Headers.D_PILOT] = df_merge[Headers.D_PILOT].to_numpy()
|
|
1239
1347
|
wsegaicv[Headers.E_PILOT] = df_merge[Headers.E_PILOT].to_numpy()
|
|
1240
1348
|
wsegaicv[Headers.F_PILOT] = df_merge[Headers.F_PILOT].to_numpy()
|
|
1241
|
-
wsegaicv[Headers.
|
|
1242
|
-
wsegaicv[Headers.
|
|
1349
|
+
wsegaicv[Headers.AICV_WATER_CUT] = df_merge[Headers.AICV_WATER_CUT].to_numpy()
|
|
1350
|
+
wsegaicv[Headers.AICV_GAS_HOLDUP_FRACTION] = df_merge[Headers.AICV_GAS_HOLDUP_FRACTION].to_numpy()
|
|
1243
1351
|
wsegaicv[Headers.EMPTY] = "/"
|
|
1244
1352
|
return wsegaicv
|
|
1245
1353
|
|
|
@@ -1258,40 +1366,68 @@ def print_wsegdar(df_wsegdar: pd.DataFrame, well_number: int) -> str:
|
|
|
1258
1366
|
CompletorError: If there are to many wells and/or segments with DAR.
|
|
1259
1367
|
"""
|
|
1260
1368
|
header = [
|
|
1261
|
-
[
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1369
|
+
[
|
|
1370
|
+
Headers.WELL,
|
|
1371
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1372
|
+
Headers.FLOW_COEFFICIENT,
|
|
1373
|
+
Headers.GAS_FLOW_CROSS_SECTIONAL_AREA,
|
|
1374
|
+
Headers.DEFAULTS,
|
|
1375
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1376
|
+
],
|
|
1377
|
+
[
|
|
1378
|
+
Headers.WELL,
|
|
1379
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1380
|
+
Headers.FLOW_COEFFICIENT,
|
|
1381
|
+
Headers.WATER_FLOW_CROSS_SECTIONAL_AREA,
|
|
1382
|
+
Headers.DEFAULTS,
|
|
1383
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1384
|
+
],
|
|
1385
|
+
[
|
|
1386
|
+
Headers.WELL,
|
|
1387
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1388
|
+
Headers.FLOW_COEFFICIENT,
|
|
1389
|
+
Headers.OIL_FLOW_CROSS_SECTIONAL_AREA,
|
|
1390
|
+
Headers.DEFAULTS,
|
|
1391
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1392
|
+
],
|
|
1393
|
+
[
|
|
1394
|
+
Headers.WELL,
|
|
1395
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1396
|
+
Headers.FLOW_COEFFICIENT,
|
|
1397
|
+
Headers.OIL_FLOW_CROSS_SECTIONAL_AREA,
|
|
1398
|
+
Headers.DEFAULTS,
|
|
1399
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1400
|
+
],
|
|
1265
1401
|
]
|
|
1266
1402
|
sign_water = ["<=", ">", "", "<"]
|
|
1267
1403
|
sign_gas = [">", "<=", "<", ""]
|
|
1268
1404
|
suvtrig = ["0", "0", "1", "2"]
|
|
1269
1405
|
action = "UDQ\n"
|
|
1270
1406
|
for idx in range(df_wsegdar.shape[0]):
|
|
1271
|
-
segment_number = df_wsegdar[Headers.
|
|
1407
|
+
segment_number = df_wsegdar[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1272
1408
|
well_name = df_wsegdar[Headers.WELL].iloc[idx]
|
|
1273
1409
|
action += f" ASSIGN SUVTRIG {well_name} {segment_number} 0 /\n"
|
|
1274
1410
|
action += "/\n\n"
|
|
1275
1411
|
iaction = 3
|
|
1276
|
-
action += Keywords.
|
|
1412
|
+
action += Keywords.WELL_SEGMENTS_VALVE + "\n"
|
|
1277
1413
|
header_string = "--"
|
|
1278
1414
|
for itm in header[iaction]:
|
|
1279
1415
|
header_string += " " + itm
|
|
1280
1416
|
action += header_string.rstrip() + "\n"
|
|
1281
1417
|
for idx in range(df_wsegdar.shape[0]):
|
|
1282
|
-
segment_number = df_wsegdar[Headers.
|
|
1283
|
-
print_df = df_wsegdar[df_wsegdar[Headers.
|
|
1418
|
+
segment_number = df_wsegdar[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1419
|
+
print_df = df_wsegdar[df_wsegdar[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1284
1420
|
print_df = print_df[header[iaction]]
|
|
1285
1421
|
print_df = dataframe_tostring(print_df, True, False, False) + "\n"
|
|
1286
1422
|
action += print_df
|
|
1287
1423
|
action += "/\n\n"
|
|
1288
1424
|
for idx in range(df_wsegdar.shape[0]):
|
|
1289
|
-
segment_number = df_wsegdar[Headers.
|
|
1425
|
+
segment_number = df_wsegdar[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1290
1426
|
well_name = df_wsegdar[Headers.WELL].iloc[idx]
|
|
1291
|
-
water_holdup_fraction_low_cutoff = df_wsegdar[Headers.
|
|
1292
|
-
water_holdup_fraction_high_cutoff = df_wsegdar[Headers.
|
|
1293
|
-
gas_holdup_fraction_low_cutoff = df_wsegdar[Headers.
|
|
1294
|
-
gas_holdup_fraction_high_cutoff = df_wsegdar[Headers.
|
|
1427
|
+
water_holdup_fraction_low_cutoff = df_wsegdar[Headers.WATER_HOLDUP_FRACTION_LOW_CUTOFF].iloc[idx]
|
|
1428
|
+
water_holdup_fraction_high_cutoff = df_wsegdar[Headers.WATER_HOLDUP_FRACTION_HIGH_CUTOFF].iloc[idx]
|
|
1429
|
+
gas_holdup_fraction_low_cutoff = df_wsegdar[Headers.GAS_HOLDUP_FRACTION_LOW_CUTOFF].iloc[idx]
|
|
1430
|
+
gas_holdup_fraction_high_cutoff = df_wsegdar[Headers.GAS_HOLDUP_FRACTION_HIGH_CUTOFF].iloc[idx]
|
|
1295
1431
|
for iaction in range(2):
|
|
1296
1432
|
act_number = iaction + 1
|
|
1297
1433
|
act_name = f"D{well_number:03d}{segment_number:03d}{act_number:1d}"
|
|
@@ -1306,9 +1442,9 @@ def print_wsegdar(df_wsegdar: pd.DataFrame, well_number: int) -> str:
|
|
|
1306
1442
|
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1307
1443
|
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1308
1444
|
)
|
|
1309
|
-
print_df = df_wsegdar[df_wsegdar[Headers.
|
|
1445
|
+
print_df = df_wsegdar[df_wsegdar[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1310
1446
|
print_df = print_df[header[iaction]] # type: ignore
|
|
1311
|
-
header_string = Keywords.
|
|
1447
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1312
1448
|
for item in header[iaction]:
|
|
1313
1449
|
header_string += " " + item
|
|
1314
1450
|
header_string = header_string.rstrip() + "\n"
|
|
@@ -1332,9 +1468,9 @@ def print_wsegdar(df_wsegdar: pd.DataFrame, well_number: int) -> str:
|
|
|
1332
1468
|
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1333
1469
|
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1334
1470
|
)
|
|
1335
|
-
print_df = df_wsegdar[df_wsegdar[Headers.
|
|
1471
|
+
print_df = df_wsegdar[df_wsegdar[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1336
1472
|
print_df = print_df[header[iaction]] # type: ignore
|
|
1337
|
-
header_string = Keywords.
|
|
1473
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1338
1474
|
for item in header[iaction]:
|
|
1339
1475
|
header_string += " " + item
|
|
1340
1476
|
header_string = header_string.rstrip() + "\n"
|
|
@@ -1355,9 +1491,9 @@ def print_wsegdar(df_wsegdar: pd.DataFrame, well_number: int) -> str:
|
|
|
1355
1491
|
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1356
1492
|
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1357
1493
|
)
|
|
1358
|
-
print_df = df_wsegdar[df_wsegdar[Headers.
|
|
1494
|
+
print_df = df_wsegdar[df_wsegdar[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1359
1495
|
print_df = print_df[header[iaction]] # type: ignore
|
|
1360
|
-
header_string = Keywords.
|
|
1496
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1361
1497
|
for item in header[iaction]:
|
|
1362
1498
|
header_string += " " + item
|
|
1363
1499
|
header_string = header_string.rstrip() + "\n"
|
|
@@ -1384,12 +1520,12 @@ def print_wsegaicv(df_wsegaicv: pd.DataFrame, well_number: int) -> str:
|
|
|
1384
1520
|
header = [
|
|
1385
1521
|
[
|
|
1386
1522
|
Headers.WELL,
|
|
1387
|
-
Headers.
|
|
1388
|
-
Headers.
|
|
1523
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1524
|
+
Headers.END_SEGMENT_NUMBER,
|
|
1389
1525
|
Headers.ALPHA_MAIN,
|
|
1390
|
-
Headers.
|
|
1391
|
-
Headers.
|
|
1392
|
-
Headers.
|
|
1526
|
+
Headers.SCALE_FACTOR,
|
|
1527
|
+
Headers.CALIBRATION_FLUID_DENSITY,
|
|
1528
|
+
Headers.CALIBRATION_FLUID_VISCOSITY,
|
|
1393
1529
|
Headers.DEF,
|
|
1394
1530
|
Headers.X_MAIN,
|
|
1395
1531
|
Headers.Y_MAIN,
|
|
@@ -1404,12 +1540,12 @@ def print_wsegaicv(df_wsegaicv: pd.DataFrame, well_number: int) -> str:
|
|
|
1404
1540
|
],
|
|
1405
1541
|
[
|
|
1406
1542
|
Headers.WELL,
|
|
1407
|
-
Headers.
|
|
1408
|
-
Headers.
|
|
1543
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1544
|
+
Headers.END_SEGMENT_NUMBER,
|
|
1409
1545
|
Headers.ALPHA_PILOT,
|
|
1410
|
-
Headers.
|
|
1411
|
-
Headers.
|
|
1412
|
-
Headers.
|
|
1546
|
+
Headers.SCALE_FACTOR,
|
|
1547
|
+
Headers.CALIBRATION_FLUID_DENSITY,
|
|
1548
|
+
Headers.CALIBRATION_FLUID_VISCOSITY,
|
|
1413
1549
|
Headers.DEF,
|
|
1414
1550
|
Headers.X_PILOT,
|
|
1415
1551
|
Headers.Y_PILOT,
|
|
@@ -1425,12 +1561,12 @@ def print_wsegaicv(df_wsegaicv: pd.DataFrame, well_number: int) -> str:
|
|
|
1425
1561
|
]
|
|
1426
1562
|
new_column = [
|
|
1427
1563
|
Headers.WELL,
|
|
1428
|
-
Headers.
|
|
1429
|
-
Headers.
|
|
1430
|
-
Headers.
|
|
1431
|
-
Headers.
|
|
1432
|
-
Headers.
|
|
1433
|
-
Headers.
|
|
1564
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1565
|
+
Headers.END_SEGMENT_NUMBER,
|
|
1566
|
+
Headers.STRENGTH,
|
|
1567
|
+
Headers.SCALE_FACTOR,
|
|
1568
|
+
Headers.CALIBRATION_FLUID_DENSITY,
|
|
1569
|
+
Headers.CALIBRATION_FLUID_VISCOSITY,
|
|
1434
1570
|
Headers.DEF,
|
|
1435
1571
|
Headers.X,
|
|
1436
1572
|
Headers.Y,
|
|
@@ -1448,10 +1584,10 @@ def print_wsegaicv(df_wsegaicv: pd.DataFrame, well_number: int) -> str:
|
|
|
1448
1584
|
operator = ["AND", "OR"]
|
|
1449
1585
|
action = ""
|
|
1450
1586
|
for idx in range(df_wsegaicv.shape[0]):
|
|
1451
|
-
segment_number = df_wsegaicv[Headers.
|
|
1587
|
+
segment_number = df_wsegaicv[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1452
1588
|
well_name = df_wsegaicv[Headers.WELL].iloc[idx]
|
|
1453
|
-
wct = df_wsegaicv[Headers.
|
|
1454
|
-
ghf = df_wsegaicv[Headers.
|
|
1589
|
+
wct = df_wsegaicv[Headers.AICV_WATER_CUT].iloc[idx]
|
|
1590
|
+
ghf = df_wsegaicv[Headers.AICV_GAS_HOLDUP_FRACTION].iloc[idx]
|
|
1455
1591
|
# LOWWCT_LOWGHF
|
|
1456
1592
|
for iaction in range(2):
|
|
1457
1593
|
act_number = iaction + 1
|
|
@@ -1465,9 +1601,9 @@ def print_wsegaicv(df_wsegaicv: pd.DataFrame, well_number: int) -> str:
|
|
|
1465
1601
|
f"SGHF '{well_name}' {segment_number} {sign_gas[iaction]} {ghf} /\n/\n"
|
|
1466
1602
|
)
|
|
1467
1603
|
|
|
1468
|
-
print_df = df_wsegaicv[df_wsegaicv[Headers.
|
|
1604
|
+
print_df = df_wsegaicv[df_wsegaicv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1469
1605
|
print_df = print_df[header[iaction]]
|
|
1470
1606
|
print_df.columns = new_column
|
|
1471
|
-
print_df = Keywords.
|
|
1607
|
+
print_df = Keywords.AUTONOMOUS_INFLOW_CONTROL_DEVICE + "\n" + dataframe_tostring(print_df, True)
|
|
1472
1608
|
action += f"{print_df}\n/\nENDACTIO\n\n"
|
|
1473
1609
|
return action
|