completor 0.1.3__py3-none-any.whl → 1.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.
@@ -1,19 +1,18 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import math
4
- from collections.abc import Callable, Mapping
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.completion import WellSchedule
12
- from completor.constants import Headers, Keywords
13
- from completor.exceptions import CompletorError
11
+ from completor.constants import Content, Headers, Keywords
12
+ from completor.exceptions.clean_exceptions import CompletorError
14
13
  from completor.logger import logger
15
- from completor.read_casefile import ReadCasefile
16
- from completor.utils import as_data_frame
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. WELSPECS, COMPSEGS, COMPDAT, WELSEGS, etc.
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
- formatters: Mapping[str | int, Callable[..., Any]] | None = None,
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: COMPDAT, COMPSEGS, etc.
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
- # Add single quotes around well names in output file
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
- output_string = df_temp.to_string(index=False, justify="justify", header=header)
102
+
103
+ formatters: MutableMapping[Any, Any] = {}
101
104
  if format_column:
102
- if formatters is None:
103
- formatters = {
104
- Headers.ALPHA: "{:.10g}".format,
105
- Headers.SF: "{:.10g}".format,
106
- Headers.ROUGHNESS: "{:.10g}".format,
107
- Headers.CONNECTION_FACTOR: "{:.10g}".format,
108
- Headers.FORAMTION_PERMEABILITY_THICKNESS: "{:.10g}".format,
109
- Headers.MD: "{:.3f}".format,
110
- Headers.TVD: "{:.3f}".format,
111
- Headers.START_MEASURED_DEPTH: "{:.3f}".format,
112
- Headers.END_MEASURED_DEPTH: "{:.3f}".format,
113
- Headers.CV_DAR: "{:.10g}".format,
114
- Headers.CV: "{:.10g}".format,
115
- Headers.AC: "{:.3e}".format,
116
- Headers.AC_OIL: "{:.3e}".format,
117
- Headers.AC_GAS: "{:.3e}".format,
118
- Headers.AC_WATER: "{:.3e}".format,
119
- Headers.AC_MAX: "{:.3e}".format,
120
- Headers.DEFAULTS: "{:.10s}".format,
121
- Headers.WHF_LCF_DAR: "{:.10g}".format,
122
- Headers.WHF_HCF_DAR: "{:.10g}".format,
123
- Headers.GHF_LCF_DAR: "{:.10g}".format,
124
- Headers.GHF_HCF_DAR: "{:.10g}".format,
125
- Headers.ALPHA_MAIN: "{:.10g}".format,
126
- Headers.ALPHA_PILOT: "{:.10g}".format,
127
- }
128
- try:
129
- output_string = df_temp.to_string(index=False, justify="justify", formatters=formatters, header=header)
130
- except ValueError:
131
- pass
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
- return output_string
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.MD])
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)), columns=[Headers.MD, Headers.SEG]
237
+ np.column_stack((reference_md, reference_segment_number)),
238
+ columns=[Headers.MEASURED_DEPTH, Headers.START_SEGMENT_NUMBER],
158
239
  )
159
- df_reference[Headers.SEG] = df_reference[Headers.SEG].astype(np.int64)
160
- df_reference.sort_values(by=[Headers.MD], inplace=True)
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.MD], direction="nearest")[Headers.SEG]
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. WELSEGS, COMPSEGS, COMPDAT, etc.
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.WELSEGS:
197
- header = f"{'-' * nchar}\n-- Well : {well_name} : Lateral : {lat} : {layer} layer\n"
279
+ if keyword == Keywords.WELL_SEGMENTS:
280
+ header = f"Well: {well_name}, Lateral: {lat}, {layer} layer"
198
281
  else:
199
- header = f"{'-' * nchar}\n-- Well : {well_name} : Lateral : {lat}\n"
200
- return header + "-" * nchar + "\n"
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
- schedule: WellSchedule,
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
- schedule: Schedule object.
216
- well_name: Well name.
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
- rnm = {
227
- Headers.TUBINGMD: Headers.MD,
228
- Headers.TUBINGTVD: Headers.TVD,
229
- Headers.TUBING_INNER_DIAMETER: Headers.DIAMETER,
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(rnm.values())
233
- df_well = df_well[df_well[Headers.WELL] == well_name]
234
- df_well = df_well[df_well[Headers.LATERAL] == lateral]
235
- df_tubing_in_reservoir = as_data_frame(
236
- MD=df_well[Headers.TUB_MD],
237
- TVD=df_well[Headers.TUB_TVD],
238
- DIAM=df_well[Headers.INNER_DIAMETER],
239
- ROUGHNESS=df_well[Headers.ROUGHNESS],
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
- # handle overburden
242
- well_segments = schedule.get_well_segments(well_name, lateral)[1]
243
- md_input_welsegs = well_segments[Headers.TUBINGMD]
244
- md_welsegs_in_reservoir = df_tubing_in_reservoir[Headers.MD]
245
- overburden = well_segments[(md_welsegs_in_reservoir[0] - md_input_welsegs) > 1.0]
246
- if not overburden.empty:
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
- df_tubing_with_overburden[Headers.SEG] = start_segment + np.arange(df_tubing_with_overburden.shape[0])
253
- df_tubing_with_overburden[Headers.SEG2] = df_tubing_with_overburden[Headers.SEG]
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
- # set out-segment to be successive.
257
- # The first item will be updated in connect_lateral
258
- df_tubing_with_overburden[Headers.OUT] = df_tubing_with_overburden[Headers.SEG] - 1
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.SEG, Headers.SEG2, Headers.BRANCH, Headers.OUT] + cols
340
+ columns=[Headers.START_SEGMENT_NUMBER, Headers.END_SEGMENT_NUMBER, Headers.BRANCH, Headers.OUT] + cols
262
341
  )
263
- df_tubing_with_overburden[Headers.EMPTY] = "/" # for printing
264
- # locate where it attached to (the top segment)
265
- wsa = schedule.get_well_segments(well_name)[1] # all laterals
266
- top = wsa[wsa.TUBINGSEGMENT == well_segments.iloc[0][Headers.TUBING_OUTLET]] # could be empty
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 WELSEGS segments located above the top COMPSEGS segment.
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 WELSEGS segments in the overburden.
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 in not found in overburden at overburden_md.
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.TUBINGBRANCH].iloc[0]
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.MD].iloc[idx_overburden]
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.DIAMETER)] = (
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 connect_lateral(
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
- well_name: Well name.
394
- lateral: Lateral number.
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.SEG].to_numpy()) + 1
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
- df_well = df_well[df_well[Headers.WELL] == well_name]
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] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
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.SEG] = start_segment + np.arange(df_well.shape[0])
416
- df_device[Headers.SEG2] = df_device[Headers.SEG].to_numpy()
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.TUB_MD].to_numpy(), df_tubing[Headers.MD].to_numpy(), df_tubing[Headers.SEG].to_numpy()
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.MD] = df_well[Headers.TUB_MD].to_numpy() + device_length
422
- df_device[Headers.TVD] = df_well[Headers.TUB_TVD].to_numpy()
423
- df_device[Headers.DIAMETER] = df_well[Headers.INNER_DIAMETER].to_numpy()
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] == "PERF",
439
+ df_well[Headers.DEVICE_TYPE] == Content.PERFORATED,
427
440
  "/ -- Open Perforation",
428
441
  np.where(
429
- df_well[Headers.DEVICE_TYPE] == "AICD",
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] == "ICD",
445
+ df_well[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_DEVICE,
433
446
  "/ -- ICD types",
434
447
  np.where(
435
- df_well[Headers.DEVICE_TYPE] == "VALVE",
448
+ df_well[Headers.DEVICE_TYPE] == Content.VALVE,
436
449
  "/ -- Valve types",
437
450
  np.where(
438
- df_well[Headers.DEVICE_TYPE] == "DAR",
451
+ df_well[Headers.DEVICE_TYPE] == Content.DENSITY_ACTIVATED_RECOVERY,
439
452
  "/ -- DAR types",
440
453
  np.where(
441
- df_well[Headers.DEVICE_TYPE] == "AICV",
454
+ df_well[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_VALVE,
442
455
  "/ -- AICV types",
443
- np.where(df_well[Headers.DEVICE_TYPE] == "ICV", "/ -- ICV types", ""),
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, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame, annulus_length: float = 0.1
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
- lateral: Lateral number.
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
- df_wseglink = pd.DataFrame()
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() == "PERF")
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.SEG]) + 1
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.SEG]) + 1
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() == "PERF")
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, df_wseglink_upstream = calculate_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.SEG] = start_segment + np.arange(df_branch_downstream.shape[0])
523
- df_annulus_downstream[Headers.SEG2] = df_annulus_downstream[Headers.SEG]
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.SEG] + 1
526
- df_annulus_downstream[Headers.MD] = df_branch_downstream[Headers.TUB_MD].to_numpy() + annulus_length
527
- df_annulus_downstream[Headers.TVD] = df_branch_downstream[Headers.TUB_TVD].to_numpy()
528
- df_annulus_downstream[Headers.DIAMETER] = df_branch_downstream[Headers.OUTER_DIAMETER].to_numpy()
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 WSEGLINK in the downstream part because
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.SEG]) + 1
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, df_wseglink_upstream = calculate_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
- df_wseglink = df_wseglink_upstream.copy(deep=True)
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
- df_wseglink = pd.concat([df_wseglink, df_wseglink_upstream])
570
+ df_well_segments_link = pd.concat([df_well_segments_link, df_well_segments_link_upstream])
553
571
 
554
- if df_wseglink.shape[0] > 0:
555
- df_wseglink = df_wseglink[[Headers.WELL, Headers.ANNULUS, Headers.DEVICE]]
556
- df_wseglink[Headers.ANNULUS] = df_wseglink[Headers.ANNULUS].astype(np.int64)
557
- df_wseglink[Headers.DEVICE] = df_wseglink[Headers.DEVICE].astype(np.int64)
558
- df_wseglink[Headers.EMPTY] = "/"
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, df_wseglink
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.SEG] = start_segment + np.arange(df_branch.shape[0])
590
- df_annulus_upstream[Headers.SEG2] = df_annulus_upstream[Headers.SEG]
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.SEG].to_numpy() - 1
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.TUB_MD].to_numpy(), df_device[Headers.MD].to_numpy(), df_device[Headers.SEG].to_numpy()
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.TUB_MD].to_numpy() + annulus_length
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.MD] = md_
607
- df_annulus_upstream[Headers.TVD] = df_branch[Headers.TUB_TVD].to_numpy()
608
- df_annulus_upstream[Headers.DIAMETER] = df_branch[Headers.OUTER_DIAMETER].to_numpy()
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.TUB_MD].to_numpy(), df_device[Headers.MD].to_numpy(), df_device[Headers.SEG].to_numpy()
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.TUB_MD].to_numpy(),
615
- df_annulus_upstream[Headers.MD].to_numpy(),
616
- df_annulus_upstream[Headers.SEG].to_numpy(),
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.TUB_MD].to_numpy(),
620
- df_annulus_upstream[Headers.MD].to_numpy(),
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
- df_wseglink_upstream = as_data_frame(
624
- WELL=[well_name] * device_segment.shape[0],
625
- ANNULUS=annulus_segment,
626
- DEVICE=device_segment,
627
- OUTLET=outlet_segment,
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
- # basically WSEGLINK is only for those segments
630
- # whose its outlet segment is not a device segment
631
- df_wseglink_upstream = df_wseglink_upstream[df_wseglink_upstream[Headers.DEVICE] != df_wseglink_upstream["OUTLET"]]
632
- return df_annulus_upstream, df_wseglink_upstream
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, df_completion_table: 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 COMPSEGS with the correct depth due to ICV segmenting combination.
663
+ """Connect COMPLETION_SEGMENTS with the correct depth due to ICV segmenting combination.
639
664
 
640
665
  Args:
641
- df_reservoir: The df_reservoir from class object CreateWells.
642
- df_device: DataFrame from function prepare_device_layer for this well and lateral.
643
- df_annulus: DataFrame from function prepare_annulus_layer for this well and lateral.
644
- df_completion_table: DataFrame.
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
- df_compseg_device, df_compseg_annulus.
672
+ Completion segments for devices and completion segments for annulus.
648
673
  """
649
674
  _MARKER_MEASURED_DEPTH = "TEMPORARY_MARKER_MEASURED_DEPTH"
650
- df_temp = df_completion_table[
651
- (df_completion_table[Headers.VALVES_PER_JOINT] > 0.0) | (df_completion_table[Headers.DEVICE_TYPE] == "PERF")
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.MD]
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 = f"@df_res.MD >= {start} and @df_res.MD <= {end} and @df_res.DEVICETYPE == 'ICV'"
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, right=df_device, left_on=_MARKER_MEASURED_DEPTH, right_on=Headers.MD, direction="nearest"
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 (df_completion_table[Headers.ANNULUS] == "OA").any():
707
+ if (df_completion[Headers.ANNULUS] == Content.OPEN_ANNULUS).any():
674
708
  df_compseg_annulus = pd.merge_asof(
675
- left=df_res, right=df_annulus, left_on=_MARKER_MEASURED_DEPTH, right_on=Headers.MD, direction="nearest"
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 prepare_compsegs(
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 COMPSEGS.
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 df_reservoir from class object CreateWells.
695
- df_device: DataFrame from function prepare_device_layer for this well and this lateral.
696
- df_annulus: DataFrame from function prepare_annulus_layer for this well and this lateral.
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
- COMPSEGS DataFrame.
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] == "PERF")
750
+ | (df_reservoir[Headers.DEVICE_TYPE] == Content.PERFORATED)
713
751
  ]
714
- # sort device dataframe by MD to be used for pd.merge_asof
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.MD])
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] == "ICV").any()
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.MD], direction="nearest"
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(left=df_reservoir, right=df_device, on=[Headers.MD], direction="nearest")
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.DIRECTION] = df_compseg_device[Headers.COMPSEGS_DIRECTION].to_numpy()
793
+ compseg[Headers.COMPSEGS_DIRECTION] = df_compseg_device[Headers.COMPSEGS_DIRECTION].to_numpy()
754
794
  compseg[Headers.DEF] = "3*"
755
- compseg[Headers.SEG] = df_compseg_device[Headers.SEG].to_numpy()
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.MD])
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.MD], direction="nearest"
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.MD], direction="nearest"
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.MD], direction="nearest"
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
- def _choose(parameter: str) -> np.ndarray:
792
- return choose_layer(df_reservoir, df_compseg_annulus, df_compseg_device, parameter)
793
-
794
- compseg = as_data_frame(
795
- I=_choose(Headers.I),
796
- J=_choose(Headers.J),
797
- K=_choose(Headers.K),
798
- BRANCH=_choose(Headers.BRANCH),
799
- STARTMD=_choose(Headers.START_MEASURED_DEPTH),
800
- ENDMD=_choose(Headers.END_MEASURED_DEPTH),
801
- DIR=_choose(Headers.COMPSEGS_DIRECTION),
802
- DEF="3*",
803
- SEG=_choose(Headers.SEG),
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 COMPSEGS with user segmentation.
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 df_completion_table due to user segmentation method.
864
+ depth in the df_completion due to user segmentation method.
816
865
 
817
866
  Args:
818
- df_reservoir: The df_reservoir from class object CreateWells.
819
- df_device: DataFrame from function prepare_device_layer for this well and lateral.
820
- df_annulus: DataFrame from function prepare_annulus_layer for this well and lateral.
821
- df_completion_table: DataFrame.
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
- df_compseg_device, df_compseg_annulus.
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) | (df_completion_table[Headers.DEVICE_TYPE] == "PERF")
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] != "PA")]
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] == "OA"]
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.MD >= {start} and @df_res.MD <= {end}"
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.ndarray:
881
- """Choose relevant parameters from either df_compseg_annulus or df_compseg_device.
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 == "PERF"), df_compseg_device[parameter].to_numpy(), -1),
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 COMPDAT section is in agreement with
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 dataframe.
908
- df_completion_table: ReadCasefile object for current well/lateral.
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 ReadCasefile object.
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.MD]:
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.DIAMETER] = completion_diameters
974
+ df_reservoir[Headers.WELL_BORE_DIAMETER] = completion_diameters
925
975
  return df_reservoir
926
976
 
927
977
 
928
- def prepare_compdat(
929
- well_name: str, lateral: int, df_reservoir: pd.DataFrame, df_completion_table: 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 COMPDAT data frame.
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: df_reservoir from class CreateWells.
937
- df_completion_table: From class ReadCasefile.
986
+ df_reservoir: Reservoir data.
987
+ df_completion: Completion data.
938
988
 
939
989
  Returns:
940
- COMPDAT.
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] == "PERF"))
996
+ | ((df_reservoir[Headers.NUMBER_OF_DEVICES] > 0) | (df_reservoir[Headers.DEVICE_TYPE] == Content.PERFORATED))
947
997
  ]
948
- if df_reservoir.shape[0] == 0:
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.SAT] = df_reservoir[Headers.SATURATION_FUNCTION_REGION_NUMBERS].to_numpy()
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.DIAMETER] = fix_well_id(df_reservoir, df_completion_table)[Headers.DIAMETER].to_numpy()
960
- compdat[Headers.FORAMTION_PERMEABILITY_THICKNESS] = df_reservoir[
961
- Headers.FORAMTION_PERMEABILITY_THICKNESS
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.DFACT] = df_reservoir[Headers.DFACT].to_numpy()
965
- compdat[Headers.DIRECTION] = df_reservoir[Headers.COMPDAT_DIRECTION].to_numpy()
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 prepare_wsegaicd(well_name: str, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
974
- """Prepare WSEGAICD data frame.
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
- lateral: Lateral number.
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
- WSEGAICD.
1038
+ AUTONOMOUS_INFLOW_CONTROL_DEVICE.
984
1039
  """
985
- df_well = df_well[df_well[Headers.WELL] == well_name]
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, right=df_well, left_on=[Headers.MD], right_on=[Headers.TUB_MD], direction="nearest"
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] == "AICD"]
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.SEG] = df_merge[Headers.SEG].to_numpy()
998
- wsegaicd[Headers.SEG2] = df_merge[Headers.SEG].to_numpy()
999
- wsegaicd[Headers.ALPHA] = df_merge[Headers.ALPHA].to_numpy()
1000
- wsegaicd[Headers.SF] = df_merge[Headers.SCALING_FACTOR].to_numpy()
1001
- wsegaicd[Headers.RHO] = df_merge[Headers.RHOCAL_AICD].to_numpy()
1002
- wsegaicd[Headers.VISCOSITY] = df_merge[Headers.VISCAL_AICD].to_numpy()
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 prepare_wsegsicd(well_name: str, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
1018
- """Prepare WSEGSICD data frame.
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
- lateral: Lateral number.
1023
- df_well: df_well from class CreateWells.
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
- WSEGSICD.
1083
+ INFLOW_CONTROL_DEVICE.
1028
1084
  """
1029
- df_well = df_well[df_well[Headers.LATERAL] == lateral]
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, right=df_well, left_on=[Headers.MD], right_on=[Headers.TUB_MD], direction="nearest"
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] == "ICD"]
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.SEG] = df_merge[Headers.SEG].to_numpy()
1041
- wsegsicd[Headers.SEG2] = df_merge[Headers.SEG].to_numpy()
1042
- wsegsicd[Headers.ALPHA] = df_merge[Headers.STRENGTH].to_numpy()
1043
- wsegsicd[Headers.SF] = df_merge[Headers.SCALING_FACTOR].to_numpy()
1044
- wsegsicd[Headers.RHO] = df_merge[Headers.RHOCAL_ICD].to_numpy()
1045
- wsegsicd[Headers.VISCOSITY] = df_merge[Headers.VISCAL_ICD].to_numpy()
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 prepare_wsegvalv(well_name: str, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
1052
- """Prepare WSEGVALV data frame.
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
- lateral: Lateral number.
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
- WSEGVALV.
1119
+ WELL_SEGMENTS_VALVE.
1062
1120
  """
1063
- df_well = df_well[df_well[Headers.LATERAL] == lateral]
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, right=df_well, left_on=[Headers.MD], right_on=[Headers.TUB_MD], direction="nearest"
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] == "VALVE"].reset_index(drop=True)
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.SEG] = df_merge[Headers.SEG].to_numpy()
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.CV] = df_merge[Headers.CV].to_numpy()
1077
- wsegvalv[Headers.AC] = df_merge[Headers.AC].to_numpy()
1078
- wsegvalv[Headers.L] = "5*"
1079
- wsegvalv[Headers.AC_MAX] = df_merge[Headers.AC_MAX].to_numpy()
1080
- wsegvalv[Headers.AC_MAX] = wsegvalv[Headers.AC_MAX].fillna(df_merge[Headers.AC])
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 prepare_wsegicv(
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 WSEGICV DataFrame with WSEGVALV format. Include ICVs in device and tubing layer.
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: df_well from class CreateWells.
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 WSEGICV keyword from class ReadCaseFile.
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] == "PERF") | (df_well[Headers.NUMBER_OF_DEVICES] > 0))
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, right=df_well, left_on=Headers.MD, right_on=Headers.TUB_MD, direction="nearest"
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] == "ICV"]
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[[Headers.SEG, Headers.CV, Headers.AC, Headers.AC_MAX]]
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.AC_MAX] = wsegicv[Headers.AC_MAX].fillna(df_merge[Headers.AC])
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=[Headers.WELL, Headers.SEG, Headers.CV, Headers.AC, Headers.DEFAULTS, Headers.AC_MAX]
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.MD,
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[[Headers.SEG, Headers.CV, Headers.AC, Headers.AC_MAX]]
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.AC_MAX] = df_temp[Headers.AC_MAX].fillna(math.pi * 0.5 * df_tubing[Headers.DIAMETER] ** 2)
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=[Headers.WELL, Headers.SEG, Headers.CV, Headers.AC, Headers.DEFAULTS, Headers.AC_MAX]
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 prepare_wsegdar(well_name: str, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
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
- lateral: Lateral number.
1160
- df_well: df_well from class CreateWells.
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.LATERAL] == lateral]
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, right=df_well, left_on=[Headers.MD], right_on=[Headers.TUB_MD], direction="nearest"
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] == "DAR"]
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.SEG] = df_merge[Headers.SEG].to_numpy()
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.CV_DAR] = df_merge[Headers.CV_DAR].to_numpy()
1180
- wsegdar[Headers.AC_OIL] = df_merge[Headers.AC_OIL].to_numpy()
1181
- wsegdar[Headers.AC_GAS] = df_merge[Headers.AC_GAS].to_numpy()
1182
- wsegdar[Headers.AC_WATER] = df_merge[Headers.AC_WATER].to_numpy()
1183
- wsegdar[Headers.WHF_LCF_DAR] = df_merge[Headers.WHF_LCF_DAR].to_numpy()
1184
- wsegdar[Headers.WHF_HCF_DAR] = df_merge[Headers.WHF_HCF_DAR].to_numpy()
1185
- wsegdar[Headers.GHF_LCF_DAR] = df_merge[Headers.GHF_LCF_DAR].to_numpy()
1186
- wsegdar[Headers.GHF_HCF_DAR] = df_merge[Headers.GHF_HCF_DAR].to_numpy()
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.AC_MAX] = wsegdar[Headers.AC_OIL].to_numpy()
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 prepare_wsegaicv(well_name: str, lateral: int, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
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
- lateral: Lateral number.
1199
- df_well: df_well from class CreateWells.
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.LATERAL] == lateral]
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, right=df_well, left_on=[Headers.MD], right_on=[Headers.TUB_MD], direction="nearest"
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] == "AICV"]
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.SEG] = df_merge[Headers.SEG].to_numpy()
1217
- wsegaicv[Headers.SEG2] = df_merge[Headers.SEG].to_numpy()
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.SF] = df_merge[Headers.SCALING_FACTOR].to_numpy()
1220
- wsegaicv[Headers.RHO] = df_merge[Headers.RHOCAL_AICV].to_numpy()
1221
- wsegaicv[Headers.VISCOSITY] = df_merge[Headers.VISCAL_AICV].to_numpy()
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.WCT_AICV] = df_merge[Headers.WCT_AICV].to_numpy()
1242
- wsegaicv[Headers.GHF_AICV] = df_merge[Headers.GHF_AICV].to_numpy()
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
- [Headers.WELL, Headers.SEG, Headers.CV_DAR, Headers.AC_GAS, Headers.DEFAULTS, Headers.AC_MAX],
1262
- [Headers.WELL, Headers.SEG, Headers.CV_DAR, Headers.AC_WATER, Headers.DEFAULTS, Headers.AC_MAX],
1263
- [Headers.WELL, Headers.SEG, Headers.CV_DAR, Headers.AC_OIL, Headers.DEFAULTS, Headers.AC_MAX],
1264
- [Headers.WELL, Headers.SEG, Headers.CV_DAR, Headers.AC_OIL, Headers.DEFAULTS, Headers.AC_MAX],
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.SEG].iloc[idx]
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.WSEGVALV + "\n"
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.SEG].iloc[idx]
1283
- print_df = df_wsegdar[df_wsegdar[Headers.SEG] == segment_number]
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.SEG].iloc[idx]
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.WHF_LCF_DAR].iloc[idx]
1292
- water_holdup_fraction_high_cutoff = df_wsegdar[Headers.WHF_HCF_DAR].iloc[idx]
1293
- gas_holdup_fraction_low_cutoff = df_wsegdar[Headers.GHF_LCF_DAR].iloc[idx]
1294
- gas_holdup_fraction_high_cutoff = df_wsegdar[Headers.GHF_HCF_DAR].iloc[idx]
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.SEG] == segment_number]
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.WSEGVALV + "\n--"
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.SEG] == segment_number]
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.WSEGVALV + "\n--"
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.SEG] == segment_number]
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.WSEGVALV + "\n--"
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.SEG,
1388
- Headers.SEG2,
1523
+ Headers.START_SEGMENT_NUMBER,
1524
+ Headers.END_SEGMENT_NUMBER,
1389
1525
  Headers.ALPHA_MAIN,
1390
- Headers.SF,
1391
- Headers.RHO,
1392
- Headers.VISCOSITY,
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.SEG,
1408
- Headers.SEG2,
1543
+ Headers.START_SEGMENT_NUMBER,
1544
+ Headers.END_SEGMENT_NUMBER,
1409
1545
  Headers.ALPHA_PILOT,
1410
- Headers.SF,
1411
- Headers.RHO,
1412
- Headers.VISCOSITY,
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.SEG,
1429
- Headers.SEG2,
1430
- Headers.ALPHA,
1431
- Headers.SF,
1432
- Headers.RHO,
1433
- Headers.VISCOSITY,
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.SEG].iloc[idx]
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.WCT_AICV].iloc[idx]
1454
- ghf = df_wsegaicv[Headers.GHF_AICV].iloc[idx]
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.SEG] == segment_number]
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.WSEGAICD + "\n" + dataframe_tostring(print_df, True)
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