completor 1.1.3__py3-none-any.whl → 1.3.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 +5 -1
- completor/constants.py +15 -1
- completor/create_output.py +84 -15
- completor/input_validation.py +20 -1
- completor/main.py +8 -2
- completor/prepare_outputs.py +363 -10
- completor/read_casefile.py +59 -4
- completor/utils.py +1 -0
- completor/visualize_well.py +2 -0
- completor/wells.py +2 -0
- {completor-1.1.3.dist-info → completor-1.3.0.dist-info}/METADATA +7 -7
- completor-1.3.0.dist-info/RECORD +27 -0
- completor-1.1.3.dist-info/RECORD +0 -27
- {completor-1.1.3.dist-info → completor-1.3.0.dist-info}/LICENSE +0 -0
- {completor-1.1.3.dist-info → completor-1.3.0.dist-info}/WHEEL +0 -0
- {completor-1.1.3.dist-info → completor-1.3.0.dist-info}/entry_points.txt +0 -0
completor/completion.py
CHANGED
|
@@ -551,7 +551,7 @@ def get_device(df_well: pd.DataFrame, df_device: pd.DataFrame, device_type: str)
|
|
|
551
551
|
Args:
|
|
552
552
|
df_well: Must contain device type, device number, and the scaling factor.
|
|
553
553
|
df_device: Device table.
|
|
554
|
-
device_type: Device type. `AICD`, `ICD`, `DENSITY`, `VALVE`, `DUALRCP`, `ICV`.
|
|
554
|
+
device_type: Device type. `AICD`, `ICD`, `DENSITY`, `VALVE`, `DUALRCP`, `ICV`, `INJV`.
|
|
555
555
|
|
|
556
556
|
Returns:
|
|
557
557
|
Updated well information with device characteristics.
|
|
@@ -581,6 +581,10 @@ def get_device(df_well: pd.DataFrame, df_device: pd.DataFrame, device_type: str)
|
|
|
581
581
|
# rescale the Cv
|
|
582
582
|
# because no scaling factor in WELL_SEGMENTS_VALVE
|
|
583
583
|
df_well[Headers.FLOW_COEFFICIENT] = -df_well[Headers.FLOW_COEFFICIENT] / df_well[Headers.SCALE_FACTOR]
|
|
584
|
+
elif device_type == Content.INJECTION_VALVE:
|
|
585
|
+
# rescale the Cv
|
|
586
|
+
# because no scaling factor in WELL_SEGMENTS_VALVE
|
|
587
|
+
df_well[Headers.FLOW_COEFFICIENT] = -df_well[Headers.FLOW_COEFFICIENT] / df_well[Headers.SCALE_FACTOR]
|
|
584
588
|
return df_well
|
|
585
589
|
|
|
586
590
|
|
completor/constants.py
CHANGED
|
@@ -78,7 +78,7 @@ class _Headers:
|
|
|
78
78
|
DR = "DR"
|
|
79
79
|
FLAG = "FLAG" # This is actually a header, but OPEN, SHUT, and AUTO are its possible values, see manual on COMPLETION_DATA.
|
|
80
80
|
SHUT = "SHUT"
|
|
81
|
-
|
|
81
|
+
CROSS = "CROSS"
|
|
82
82
|
PRESSURE_TABLE = "PRESSURETABLE"
|
|
83
83
|
DENSITY_CALCULATION_TYPE = "DENSCAL" # Type of density calculation for the wellbore hydrostatic head.
|
|
84
84
|
REGION = "REGION"
|
|
@@ -126,6 +126,7 @@ class _Headers:
|
|
|
126
126
|
# This stops making sense from here on out?
|
|
127
127
|
X = "X"
|
|
128
128
|
Y = "Y"
|
|
129
|
+
Z = "Z"
|
|
129
130
|
# FLAG
|
|
130
131
|
A = "A"
|
|
131
132
|
B = "B"
|
|
@@ -165,6 +166,15 @@ class _Headers:
|
|
|
165
166
|
GAS_HOLDUP_FRACTION_LOW_CUTOFF = "GAS_HOLDUP_FRACTION_LOW_CUTOFF"
|
|
166
167
|
GAS_HOLDUP_FRACTION_HIGH_CUTOFF = "GAS_HOLDUP_FRACTION_HIGH_CUTOFF"
|
|
167
168
|
|
|
169
|
+
# Injection Valve Well Segments (WSEGINJV)
|
|
170
|
+
# DEVICE_NUMBER
|
|
171
|
+
TRIGGER_PARAMETER = "TRIGGER_PARAMETER"
|
|
172
|
+
TRIGGER_VALUE = "TRIGGER_VALUE"
|
|
173
|
+
# FLOW_COEFFICIENT / Cv
|
|
174
|
+
# FLOW_CROSS_SECTIONAL_AREA
|
|
175
|
+
PRIMARY_FLOW_CROSS_SECTIONAL_AREA = "PRIMARY_FLOW_CROSS_SECTIONAL_AREA"
|
|
176
|
+
SECONDARY_FLOW_CROSS_SECTIONAL_AREA = "SECONDARY_FLOW_CROSS_SECTIONAL_AREA"
|
|
177
|
+
|
|
168
178
|
# Miscellaneous
|
|
169
179
|
DEFAULTS = "DEFAULTS"
|
|
170
180
|
MEASURED_DEPTH = "MEASURED_DEPTH"
|
|
@@ -244,7 +254,9 @@ class _Keywords:
|
|
|
244
254
|
INFLOW_CONTROL_VALVE = "WSEGICV"
|
|
245
255
|
INFLOW_CONTROL_DEVICE = "WSEGSICD"
|
|
246
256
|
DENSITY = "WSEGDENSITY"
|
|
257
|
+
PYTHON_DEPENDENT = "PYTHON"
|
|
247
258
|
DENSITY_ACTIVATED_RECOVERY = "WSEGDAR"
|
|
259
|
+
INJECTION_VALVE = "WSEGINJV"
|
|
248
260
|
LATERAL_TO_DEVICE = "LATERAL_TO_DEVICE"
|
|
249
261
|
JOINT_LENGTH = "JOINTLENGTH"
|
|
250
262
|
SEGMENT_LENGTH = "SEGMENTLENGTH"
|
|
@@ -290,6 +302,7 @@ class _Content:
|
|
|
290
302
|
AUTONOMOUS_INFLOW_CONTROL_DEVICE = "AICD"
|
|
291
303
|
DENSITY = "DENSITY"
|
|
292
304
|
DENSITY_ACTIVATED_RECOVERY = "DAR"
|
|
305
|
+
INJECTION_VALVE = "INJV"
|
|
293
306
|
VALVE = "VALVE"
|
|
294
307
|
DEVICE_TYPES = [
|
|
295
308
|
AUTONOMOUS_INFLOW_CONTROL_DEVICE,
|
|
@@ -297,6 +310,7 @@ class _Content:
|
|
|
297
310
|
AUTONOMOUS_INFLOW_CONTROL_VALVE,
|
|
298
311
|
DENSITY,
|
|
299
312
|
DENSITY_ACTIVATED_RECOVERY,
|
|
313
|
+
INJECTION_VALVE,
|
|
300
314
|
INFLOW_CONTROL_DEVICE,
|
|
301
315
|
VALVE,
|
|
302
316
|
INFLOW_CONTROL_VALVE,
|
completor/create_output.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import getpass
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
|
|
8
|
+
import matplotlib.pyplot as plt # type: ignore
|
|
8
9
|
import numpy as np
|
|
9
10
|
import numpy.typing as npt
|
|
10
11
|
import pandas as pd
|
|
@@ -20,13 +21,13 @@ from completor.visualize_well import visualize_well
|
|
|
20
21
|
from completor.wells import Lateral, Well
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def format_output(well: Well, case: ReadCasefile,
|
|
24
|
+
def format_output(well: Well, case: ReadCasefile, pdf: PdfPages | None = None) -> tuple[str, str, str, str]:
|
|
24
25
|
"""Formats the finished output string to be written to a file.
|
|
25
26
|
|
|
26
27
|
Args:
|
|
27
28
|
well: Well data.
|
|
28
29
|
case: Case data.
|
|
29
|
-
|
|
30
|
+
pdf: The name of the figure, if None, no figure is printed. Defaults to None.
|
|
30
31
|
|
|
31
32
|
Returns:
|
|
32
33
|
Properly formatted output data for completion data, well segments, completion segments, and bonus.
|
|
@@ -41,7 +42,10 @@ def format_output(well: Well, case: ReadCasefile, figure_name: str | None = None
|
|
|
41
42
|
print_autonomous_inflow_control_device = ""
|
|
42
43
|
print_inflow_control_device = ""
|
|
43
44
|
print_density_driven = ""
|
|
45
|
+
print_density_driven_include = ""
|
|
46
|
+
print_injection_valve = ""
|
|
44
47
|
print_dual_rate_controlled_production = ""
|
|
48
|
+
print_density_driven_pyaction = ""
|
|
45
49
|
|
|
46
50
|
start_segment = 2
|
|
47
51
|
start_branch = 1
|
|
@@ -111,6 +115,7 @@ def format_output(well: Well, case: ReadCasefile, figure_name: str | None = None
|
|
|
111
115
|
well.well_name, lateral.df_well, lateral.df_device
|
|
112
116
|
)
|
|
113
117
|
df_density_driven = prepare_outputs.prepare_density_driven(well.well_name, lateral.df_well, lateral.df_device)
|
|
118
|
+
df_injection_valve = prepare_outputs.prepare_injection_valve(well.well_name, lateral.df_well, lateral.df_device)
|
|
114
119
|
df_dual_rate_controlled_production = prepare_outputs.prepare_dual_rate_controlled_production(
|
|
115
120
|
well.well_name, lateral.df_well, lateral.df_device
|
|
116
121
|
)
|
|
@@ -145,22 +150,35 @@ def format_output(well: Well, case: ReadCasefile, figure_name: str | None = None
|
|
|
145
150
|
print_inflow_control_valve += _format_inflow_control_valve(
|
|
146
151
|
well.well_name, lateral.lateral_number, df_inflow_control_valve, first
|
|
147
152
|
)
|
|
148
|
-
|
|
153
|
+
print_injection_valve += _format_injection_valve(well.well_number, df_injection_valve)
|
|
149
154
|
print_dual_rate_controlled_production += _format_dual_rate_controlled_production(
|
|
150
155
|
well.well_number, df_dual_rate_controlled_production
|
|
151
156
|
)
|
|
157
|
+
# output using ACTIONX (if-else) logic is dual RCP, density driven, and injection valve
|
|
158
|
+
if case.python_dependent:
|
|
159
|
+
# print the python file out
|
|
160
|
+
# append all laterals for density driven, dual RCP, and injection valve
|
|
161
|
+
# TODO(#274): Add functionality for dual RCP
|
|
162
|
+
print_density_driven_pyaction = _format_density_driven_pyaction(df_density_driven)
|
|
163
|
+
output_directory = prepare_outputs.print_python_file(
|
|
164
|
+
print_density_driven_pyaction, str(case.output_file), well.well_name, lateral.lateral_number
|
|
165
|
+
)
|
|
166
|
+
print_density_driven_include += prepare_outputs.print_wsegdensity_include(
|
|
167
|
+
output_directory, well.well_name, lateral.lateral_number
|
|
168
|
+
)
|
|
169
|
+
else:
|
|
170
|
+
print_density_driven += _format_density_driven(well.well_number, df_density_driven)
|
|
152
171
|
|
|
153
|
-
if
|
|
154
|
-
logger.info(f"Creating figure for lateral {lateral.lateral_number}.")
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
162
|
-
logger.info("Creating schematics: %s.pdf", figure_name)
|
|
172
|
+
if pdf is not None:
|
|
173
|
+
logger.info(f"Creating figure for well {well.well_name}, lateral {lateral.lateral_number}.")
|
|
174
|
+
fig = visualize_well(
|
|
175
|
+
well.well_name, well.df_well_all_laterals, well.df_reservoir_all_laterals, case.segment_length
|
|
176
|
+
)
|
|
177
|
+
pdf.savefig(fig, orientation="landscape")
|
|
178
|
+
plt.close(fig)
|
|
179
|
+
logger.info("Creating schematics: %s", pdf)
|
|
163
180
|
first = False
|
|
181
|
+
|
|
164
182
|
print_completion_data = "\n".join(completion_data_list)
|
|
165
183
|
if print_well_segments:
|
|
166
184
|
print_well_segments = f"{print_well_segments}\n/\n\n"
|
|
@@ -182,7 +200,7 @@ def format_output(well: Well, case: ReadCasefile, figure_name: str | None = None
|
|
|
182
200
|
if print_density_driven:
|
|
183
201
|
metadata = (
|
|
184
202
|
f"{'-' * 100}\n"
|
|
185
|
-
"-- This is how we model
|
|
203
|
+
"-- This is how we model density driven technology using sets of ACTIONX keywords.\n"
|
|
186
204
|
"-- The segment dP curves changes according to the segment water-\n"
|
|
187
205
|
"-- and gas volume fractions at downhole condition.\n"
|
|
188
206
|
"-- The value of Cv is adjusted according to the segment length and the number of\n"
|
|
@@ -191,15 +209,37 @@ def format_output(well: Well, case: ReadCasefile, figure_name: str | None = None
|
|
|
191
209
|
f"{'-' * 100}\n\n\n"
|
|
192
210
|
)
|
|
193
211
|
bonus.append(metadata + print_density_driven + "\n\n\n\n")
|
|
212
|
+
if print_injection_valve:
|
|
213
|
+
metadata = (
|
|
214
|
+
f"{'-' * 100}\n"
|
|
215
|
+
"-- This is how we model autonomous injection valve technology using sets of ACTIONX keywords.\n"
|
|
216
|
+
"-- The DP paramaters changes according to the trigger parameter.-\n"
|
|
217
|
+
"-- The value of Cv is adjusted according to the segment length and the number of\n"
|
|
218
|
+
"-- devices per joint. The constriction area will change if the parameter is triggered.\n"
|
|
219
|
+
f"{'-' * 100}\n\n\n"
|
|
220
|
+
)
|
|
221
|
+
bonus.append(metadata + print_injection_valve + "\n\n\n\n")
|
|
194
222
|
if print_dual_rate_controlled_production:
|
|
195
223
|
metadata = (
|
|
196
224
|
f"{'-' * 100}\n"
|
|
197
|
-
"-- This is how we model
|
|
225
|
+
"-- This is how we model dual RCP curves using sets of ACTIONX keyword\n"
|
|
198
226
|
"-- the DP parameters change according to the segment water cut (at downhole condition )\n"
|
|
199
227
|
"-- and gas volume fraction (at downhole condition)\n"
|
|
200
228
|
f"{'-' * 100}\n\n\n"
|
|
201
229
|
)
|
|
202
230
|
bonus.append(metadata + print_dual_rate_controlled_production + "\n\n\n\n")
|
|
231
|
+
if print_density_driven_pyaction:
|
|
232
|
+
metadata = (
|
|
233
|
+
f"{'-' * 100}\n"
|
|
234
|
+
"-- This is how we model density driven technology for python dependent keyword.\n"
|
|
235
|
+
"-- The segment dP curves changes according to the segment water-\n"
|
|
236
|
+
"-- and gas volume fractions at downhole condition.\n"
|
|
237
|
+
"-- The value of Cv is adjusted according to the segment length and the number of\n"
|
|
238
|
+
"-- devices per joint. The constriction area varies according to values of\n"
|
|
239
|
+
"-- volume fractions.\n"
|
|
240
|
+
f"{'-' * 100}\n\n\n"
|
|
241
|
+
)
|
|
242
|
+
bonus.append(metadata + print_density_driven_include + "\n\n\n\n")
|
|
203
243
|
|
|
204
244
|
return print_completion_data, print_well_segments, print_completion_segments, "".join(bonus)
|
|
205
245
|
|
|
@@ -450,6 +490,35 @@ def _format_density_driven(well_number: int, df_wsegdensity: pd.DataFrame) -> st
|
|
|
450
490
|
return prepare_outputs.print_wsegdensity(df_wsegdensity, well_number + 1)
|
|
451
491
|
|
|
452
492
|
|
|
493
|
+
def _format_density_driven_pyaction(df_wsegdensity: pd.DataFrame) -> str:
|
|
494
|
+
"""Formats well-segments for density driven valve.
|
|
495
|
+
|
|
496
|
+
Args:
|
|
497
|
+
df_wsegdensity: Data to print.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Formatted string.
|
|
501
|
+
"""
|
|
502
|
+
if df_wsegdensity.empty:
|
|
503
|
+
return ""
|
|
504
|
+
return prepare_outputs.print_wsegdensity_pyaction(df_wsegdensity)
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _format_injection_valve(well_number: int, df_wseginjv: pd.DataFrame) -> str:
|
|
508
|
+
"""Formats well-segments for injection valve.
|
|
509
|
+
|
|
510
|
+
Args:
|
|
511
|
+
well_number: The well's number
|
|
512
|
+
df_wsegdinjv: Data to print.
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
Formatted string.
|
|
516
|
+
"""
|
|
517
|
+
if df_wseginjv.empty:
|
|
518
|
+
return ""
|
|
519
|
+
return prepare_outputs.print_wseginjv(df_wseginjv, well_number + 1)
|
|
520
|
+
|
|
521
|
+
|
|
453
522
|
def _format_dual_rate_controlled_production(well_number: int, df_wsegdualrcp: pd.DataFrame) -> str:
|
|
454
523
|
"""Formats the DUALRCP section.
|
|
455
524
|
|
completor/input_validation.py
CHANGED
|
@@ -173,7 +173,7 @@ def _check_for_errors(df_comp: pd.DataFrame, well_name: str, idx: int) -> None:
|
|
|
173
173
|
if df_comp[Headers.DEVICE_TYPE].iloc[idx] not in Content.DEVICE_TYPES:
|
|
174
174
|
raise CompletorError(
|
|
175
175
|
f"{df_comp[Headers.DEVICE_TYPE].iloc[idx]} is not a valid device type. "
|
|
176
|
-
"Valid types are PERF, AICD, ICD, VALVE, DENSITY, DUALRCP, and ICV."
|
|
176
|
+
"Valid types are PERF, AICD, ICD, VALVE, DENSITY, INJV, DUALRCP, and ICV."
|
|
177
177
|
)
|
|
178
178
|
if df_comp[Headers.ANNULUS].iloc[idx] not in Content.ANNULUS_TYPES:
|
|
179
179
|
raise CompletorError(
|
|
@@ -290,6 +290,25 @@ def set_format_wsegdensity(df_temp: pd.DataFrame) -> pd.DataFrame:
|
|
|
290
290
|
return df_temp
|
|
291
291
|
|
|
292
292
|
|
|
293
|
+
def set_format_wseginjv(df_temp: pd.DataFrame) -> pd.DataFrame:
|
|
294
|
+
"""Format the well segments Injection Valve (INJV) data.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
df_temp: Well segments INJV device data.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
Updated data.
|
|
301
|
+
"""
|
|
302
|
+
df_temp[Headers.DEVICE_NUMBER] = df_temp[Headers.DEVICE_NUMBER].astype(np.int64)
|
|
303
|
+
# left out devicenumber and trigger parameter because devicenumber has been formatted as integer
|
|
304
|
+
# trigger parameter is a string
|
|
305
|
+
columns = df_temp.columns.to_numpy()[2:]
|
|
306
|
+
df_temp[columns] = df_temp[columns].astype(np.float64)
|
|
307
|
+
# Create ID device column
|
|
308
|
+
df_temp.insert(0, Headers.DEVICE_TYPE, np.full(df_temp.shape[0], Content.INJECTION_VALVE))
|
|
309
|
+
return df_temp
|
|
310
|
+
|
|
311
|
+
|
|
293
312
|
def set_format_wsegdualrcp(df_temp: pd.DataFrame) -> pd.DataFrame:
|
|
294
313
|
"""Format the well segments Dual RCP (DUALRCP) table.
|
|
295
314
|
|
completor/main.py
CHANGED
|
@@ -5,8 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
|
+
import sys
|
|
8
9
|
import time
|
|
9
10
|
|
|
11
|
+
from matplotlib.backends.backend_pdf import PdfPages # type: ignore
|
|
10
12
|
from tqdm import tqdm
|
|
11
13
|
|
|
12
14
|
from completor import create_output, parse, read_schedule, utils
|
|
@@ -89,6 +91,7 @@ def create(
|
|
|
89
91
|
"""
|
|
90
92
|
case = ReadCasefile(case_file=case_file, schedule_file=schedule, output_file=new_file)
|
|
91
93
|
active_wells = utils.get_active_wells(case.completion_table, case.gp_perf_devicelayer)
|
|
94
|
+
pdf = None
|
|
92
95
|
figure_name = None
|
|
93
96
|
if show_fig:
|
|
94
97
|
figure_no = 1
|
|
@@ -96,6 +99,7 @@ def create(
|
|
|
96
99
|
while os.path.isfile(figure_name):
|
|
97
100
|
figure_no += 1
|
|
98
101
|
figure_name = f"Well_schematic_{figure_no:03d}.pdf"
|
|
102
|
+
pdf = PdfPages(figure_name)
|
|
99
103
|
|
|
100
104
|
err: Exception | None = None
|
|
101
105
|
well = None
|
|
@@ -122,13 +126,13 @@ def create(
|
|
|
122
126
|
for chunk in find_keyword_data(Keywords.COMPLETION_SEGMENTS, schedule):
|
|
123
127
|
clean_data = clean_raw_data(chunk, Keywords.COMPLETION_SEGMENTS)
|
|
124
128
|
meaningful_data = read_schedule.set_compsegs(meaningful_data, clean_data)
|
|
125
|
-
for i, well_name in tqdm(enumerate(active_wells.tolist()), total=len(active_wells)):
|
|
129
|
+
for i, well_name in tqdm(enumerate(active_wells.tolist()), total=len(active_wells), file=sys.stdout):
|
|
126
130
|
try:
|
|
127
131
|
well = Well(well_name, i, case, meaningful_data[well_name])
|
|
128
132
|
except KeyError:
|
|
129
133
|
logger.warning(f"Well '{well_name}' is written in case file but does not exist in schedule file.")
|
|
130
134
|
continue
|
|
131
|
-
compdat, welsegs, compsegs, bonus = create_output.format_output(well, case,
|
|
135
|
+
compdat, welsegs, compsegs, bonus = create_output.format_output(well, case, pdf)
|
|
132
136
|
for keyword in [Keywords.COMPLETION_SEGMENTS, Keywords.WELL_SEGMENTS, Keywords.COMPLETION_DATA]:
|
|
133
137
|
old_data = find_well_keyword_data(well_name, keyword, schedule)
|
|
134
138
|
if not old_data:
|
|
@@ -156,6 +160,8 @@ def create(
|
|
|
156
160
|
schedule = replace_preprocessing_names(schedule, case.mapper)
|
|
157
161
|
with open(new_file, "w", encoding="utf-8") as file:
|
|
158
162
|
file.write(schedule)
|
|
163
|
+
if pdf is not None:
|
|
164
|
+
pdf.close()
|
|
159
165
|
|
|
160
166
|
if err is not None:
|
|
161
167
|
raise err
|
completor/prepare_outputs.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import math
|
|
4
4
|
from collections.abc import MutableMapping
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
@@ -120,6 +121,7 @@ def dataframe_tostring(
|
|
|
120
121
|
"END_MD": "{:.3f}".format,
|
|
121
122
|
Headers.FLOW_COEFFICIENT: "{:.10g}".format,
|
|
122
123
|
"CV": "{:.10g}".format,
|
|
124
|
+
Headers.CROSS: "{:.3e}".format,
|
|
123
125
|
Headers.FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
124
126
|
"FLOW_CROSS_SECTIONAL_AREA": "{:.3e}".format,
|
|
125
127
|
Headers.OIL_FLOW_CROSS_SECTIONAL_AREA: "{:.3e}".format,
|
|
@@ -135,6 +137,13 @@ def dataframe_tostring(
|
|
|
135
137
|
Headers.ALPHA_PILOT: "{:.10g}".format,
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
# Cast floats to str befor headers are messed up (pandas formatter does not work reliably with MultiIndex headers).
|
|
141
|
+
for column, formatter in formatters.items():
|
|
142
|
+
try:
|
|
143
|
+
df_temp[column] = df_temp[column].map(formatter)
|
|
144
|
+
except (KeyError, ValueError):
|
|
145
|
+
pass
|
|
146
|
+
|
|
138
147
|
if header:
|
|
139
148
|
# Modify headers to reduce width.
|
|
140
149
|
column_splits = [tuple(column.split("_")) for column in df_temp.columns]
|
|
@@ -173,9 +182,7 @@ def dataframe_tostring(
|
|
|
173
182
|
df_temp.columns = pd.MultiIndex.from_frame(new_cols)
|
|
174
183
|
|
|
175
184
|
try:
|
|
176
|
-
output_string = df_temp.to_string(
|
|
177
|
-
index=False, justify="justify", formatters=formatters, header=header, sparsify=False
|
|
178
|
-
)
|
|
185
|
+
output_string = df_temp.to_string(index=False, justify="justify", header=header, sparsify=False)
|
|
179
186
|
except ValueError:
|
|
180
187
|
if df_temp.isnull().values.any():
|
|
181
188
|
raise CompletorError("Got NaN values in table, please report if encountered!")
|
|
@@ -184,18 +191,14 @@ def dataframe_tostring(
|
|
|
184
191
|
df_temp = df_temp.replace("1*", np.nan, inplace=False)
|
|
185
192
|
# Probably find columns where this is the case and cast to numeric after replacing with nan?
|
|
186
193
|
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
|
-
)
|
|
194
|
+
output_string = df_temp.to_string(index=False, justify="justify", header=header, sparsify=False, na_rep="1*")
|
|
190
195
|
|
|
191
196
|
if output_string is None:
|
|
192
197
|
return ""
|
|
193
198
|
|
|
194
199
|
too_long_lines = check_width_lines(output_string, limit)
|
|
195
200
|
if too_long_lines:
|
|
196
|
-
output_string = df_temp.to_string(
|
|
197
|
-
index=False, justify="left", formatters=formatters, header=header, sparsify=False
|
|
198
|
-
)
|
|
201
|
+
output_string = df_temp.to_string(index=False, justify="left", header=header, sparsify=False)
|
|
199
202
|
if output_string is None:
|
|
200
203
|
return ""
|
|
201
204
|
too_long_lines2 = check_width_lines(output_string, limit)
|
|
@@ -454,7 +457,11 @@ def prepare_device_layer(df_well: pd.DataFrame, df_tubing: pd.DataFrame, device_
|
|
|
454
457
|
df_well[Headers.DEVICE_TYPE] == Content.DUAL_RATE_CONTROLLED_PRODUCTION,
|
|
455
458
|
"/ -- DUALRCP types",
|
|
456
459
|
np.where(
|
|
457
|
-
df_well[Headers.DEVICE_TYPE] == Content.
|
|
460
|
+
df_well[Headers.DEVICE_TYPE] == Content.INJECTION_VALVE,
|
|
461
|
+
"/ -- INJV types",
|
|
462
|
+
np.where(
|
|
463
|
+
df_well[Headers.DEVICE_TYPE] == Content.INFLOW_CONTROL_VALVE, "/ -- ICV types", ""
|
|
464
|
+
),
|
|
458
465
|
),
|
|
459
466
|
),
|
|
460
467
|
),
|
|
@@ -1068,6 +1075,8 @@ def prepare_autonomous_inflow_control_device(
|
|
|
1068
1075
|
wsegaicd[Headers.D] = df_merge[Headers.D].to_numpy()
|
|
1069
1076
|
wsegaicd[Headers.E] = df_merge[Headers.E].to_numpy()
|
|
1070
1077
|
wsegaicd[Headers.F] = df_merge[Headers.F].to_numpy()
|
|
1078
|
+
if Headers.Z in df_merge.columns:
|
|
1079
|
+
wsegaicd[Headers.Z] = df_merge[Headers.Z].to_numpy()
|
|
1071
1080
|
wsegaicd[Headers.EMPTY] = "/"
|
|
1072
1081
|
return wsegaicd
|
|
1073
1082
|
|
|
@@ -1303,6 +1312,48 @@ def prepare_density_driven(well_name: str, df_well: pd.DataFrame, df_device: pd.
|
|
|
1303
1312
|
return wsegdensity
|
|
1304
1313
|
|
|
1305
1314
|
|
|
1315
|
+
def prepare_injection_valve(well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame) -> pd.DataFrame:
|
|
1316
|
+
"""Prepare data frame for INJECTION VALVE.
|
|
1317
|
+
|
|
1318
|
+
Args:
|
|
1319
|
+
well_name: Well name.
|
|
1320
|
+
df_well: Well data.
|
|
1321
|
+
df_device: Device data for this well and lateral.
|
|
1322
|
+
|
|
1323
|
+
Returns:
|
|
1324
|
+
DataFrame for INJECTION VALVE.
|
|
1325
|
+
"""
|
|
1326
|
+
df_well = df_well[(df_well[Headers.DEVICE_TYPE] == Content.PERFORATED) | (df_well[Headers.NUMBER_OF_DEVICES] > 0)]
|
|
1327
|
+
if df_well.shape[0] == 0:
|
|
1328
|
+
return pd.DataFrame()
|
|
1329
|
+
df_merge = pd.merge_asof(
|
|
1330
|
+
left=df_device,
|
|
1331
|
+
right=df_well,
|
|
1332
|
+
left_on=[Headers.MEASURED_DEPTH],
|
|
1333
|
+
right_on=[Headers.TUBING_MEASURED_DEPTH],
|
|
1334
|
+
direction="nearest",
|
|
1335
|
+
)
|
|
1336
|
+
df_merge = df_merge[df_merge[Headers.DEVICE_TYPE] == Content.INJECTION_VALVE]
|
|
1337
|
+
wseginjv = pd.DataFrame()
|
|
1338
|
+
if df_merge.shape[0] > 0:
|
|
1339
|
+
wseginjv[Headers.WELL] = [well_name] * df_merge.shape[0]
|
|
1340
|
+
wseginjv[Headers.START_SEGMENT_NUMBER] = df_merge[Headers.START_SEGMENT_NUMBER].to_numpy()
|
|
1341
|
+
# the Cv is already corrected by the scaling factor
|
|
1342
|
+
wseginjv[Headers.FLOW_COEFFICIENT] = df_merge[Headers.FLOW_COEFFICIENT].to_numpy()
|
|
1343
|
+
wseginjv[Headers.PRIMARY_FLOW_CROSS_SECTIONAL_AREA] = df_merge[
|
|
1344
|
+
Headers.PRIMARY_FLOW_CROSS_SECTIONAL_AREA
|
|
1345
|
+
].to_numpy()
|
|
1346
|
+
wseginjv[Headers.SECONDARY_FLOW_CROSS_SECTIONAL_AREA] = df_merge[
|
|
1347
|
+
Headers.SECONDARY_FLOW_CROSS_SECTIONAL_AREA
|
|
1348
|
+
].to_numpy()
|
|
1349
|
+
wseginjv[Headers.TRIGGER_PARAMETER] = df_merge[Headers.TRIGGER_PARAMETER].to_numpy()
|
|
1350
|
+
wseginjv[Headers.TRIGGER_VALUE] = df_merge[Headers.TRIGGER_VALUE].to_numpy()
|
|
1351
|
+
wseginjv[Headers.DEFAULTS] = "5*"
|
|
1352
|
+
wseginjv[Headers.MAX_FLOW_CROSS_SECTIONAL_AREA] = wseginjv[Headers.PRIMARY_FLOW_CROSS_SECTIONAL_AREA].to_numpy()
|
|
1353
|
+
wseginjv[Headers.EMPTY] = "/"
|
|
1354
|
+
return wseginjv
|
|
1355
|
+
|
|
1356
|
+
|
|
1306
1357
|
def prepare_dual_rate_controlled_production(
|
|
1307
1358
|
well_name: str, df_well: pd.DataFrame, df_device: pd.DataFrame
|
|
1308
1359
|
) -> pd.DataFrame:
|
|
@@ -1513,6 +1564,168 @@ def print_wsegdensity(df_wsegdensity: pd.DataFrame, well_number: int) -> str:
|
|
|
1513
1564
|
return action
|
|
1514
1565
|
|
|
1515
1566
|
|
|
1567
|
+
def print_wseginjv(df_wseginjv: pd.DataFrame, well_number: int) -> str:
|
|
1568
|
+
"""Print INJECTION VALVE devices.
|
|
1569
|
+
|
|
1570
|
+
Args:
|
|
1571
|
+
df_wseginjv: Output from function prepare_wseginjv.
|
|
1572
|
+
well_number: Well number.
|
|
1573
|
+
|
|
1574
|
+
Returns:
|
|
1575
|
+
Formatted actions to be included in the output file.
|
|
1576
|
+
|
|
1577
|
+
Raises:
|
|
1578
|
+
CompletorError: If there are to many wells and/or segments with INJECTION VALVE.
|
|
1579
|
+
"""
|
|
1580
|
+
header = [
|
|
1581
|
+
[
|
|
1582
|
+
Headers.WELL,
|
|
1583
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1584
|
+
Headers.FLOW_COEFFICIENT,
|
|
1585
|
+
Headers.SECONDARY_FLOW_CROSS_SECTIONAL_AREA,
|
|
1586
|
+
Headers.DEFAULTS,
|
|
1587
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1588
|
+
],
|
|
1589
|
+
[
|
|
1590
|
+
Headers.WELL,
|
|
1591
|
+
Headers.START_SEGMENT_NUMBER,
|
|
1592
|
+
Headers.FLOW_COEFFICIENT,
|
|
1593
|
+
Headers.PRIMARY_FLOW_CROSS_SECTIONAL_AREA,
|
|
1594
|
+
Headers.DEFAULTS,
|
|
1595
|
+
Headers.MAX_FLOW_CROSS_SECTIONAL_AREA,
|
|
1596
|
+
],
|
|
1597
|
+
]
|
|
1598
|
+
|
|
1599
|
+
sign = ["<", ">="]
|
|
1600
|
+
suvtrig = ["0", "1"]
|
|
1601
|
+
action = "UDQ\n"
|
|
1602
|
+
for idx in range(df_wseginjv.shape[0]):
|
|
1603
|
+
segment_number = df_wseginjv[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1604
|
+
well_name = df_wseginjv[Headers.WELL].iloc[idx]
|
|
1605
|
+
action += f" ASSIGN SUVTRIG {well_name} {segment_number} 0 /\n"
|
|
1606
|
+
action += "/\n\n"
|
|
1607
|
+
iaction = 1
|
|
1608
|
+
action += Keywords.WELL_SEGMENTS_VALVE + "\n"
|
|
1609
|
+
header_string = "--"
|
|
1610
|
+
for itm in header[iaction]:
|
|
1611
|
+
header_string += " " + itm
|
|
1612
|
+
action += header_string.rstrip() + "\n"
|
|
1613
|
+
for idx in range(df_wseginjv.shape[0]):
|
|
1614
|
+
segment_number = df_wseginjv[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1615
|
+
print_df = df_wseginjv[df_wseginjv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1616
|
+
print_df = print_df[header[iaction]]
|
|
1617
|
+
print_df = dataframe_tostring(print_df, True, False, False) + "\n"
|
|
1618
|
+
action += print_df
|
|
1619
|
+
action += "/\n\n"
|
|
1620
|
+
for idx in range(df_wseginjv.shape[0]):
|
|
1621
|
+
segment_number = df_wseginjv[Headers.START_SEGMENT_NUMBER].iloc[idx]
|
|
1622
|
+
well_name = df_wseginjv[Headers.WELL].iloc[idx]
|
|
1623
|
+
# Trigger paramater is segment water rate
|
|
1624
|
+
if df_wseginjv[Headers.TRIGGER_PARAMETER].iloc[idx] == "SWFR":
|
|
1625
|
+
water_segment_rate_cutoff = -1 * df_wseginjv[Headers.TRIGGER_VALUE].iloc[idx]
|
|
1626
|
+
iaction = 0
|
|
1627
|
+
act_number = iaction + 1
|
|
1628
|
+
act_name = f"INJVOP{well_number:03d}{segment_number:03d}{act_number:1d}"
|
|
1629
|
+
if len(act_name) > 13:
|
|
1630
|
+
raise CompletorError("Too many wells and/or too many segments with Injection Valve")
|
|
1631
|
+
action += (
|
|
1632
|
+
f"ACTIONX\n{act_name} 1000000 /\n"
|
|
1633
|
+
f"SWFR '{well_name}' {segment_number} "
|
|
1634
|
+
f"{sign[iaction]} {water_segment_rate_cutoff} AND /\n"
|
|
1635
|
+
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1636
|
+
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1637
|
+
)
|
|
1638
|
+
print_df = df_wseginjv[df_wseginjv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1639
|
+
print_df = print_df[header[iaction]] # type: ignore
|
|
1640
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1641
|
+
|
|
1642
|
+
for item in header[iaction]:
|
|
1643
|
+
header_string += " " + item
|
|
1644
|
+
header_string = header_string.rstrip() + "\n"
|
|
1645
|
+
print_df = header_string + dataframe_tostring(print_df, True, False, False) # type: ignore
|
|
1646
|
+
print_df += "\n/\n"
|
|
1647
|
+
print_df += f"\nUDQ\n ASSIGN SUVTRIG {well_name} {segment_number} 1 /\n/\n"
|
|
1648
|
+
action += print_df + "\nENDACTIO\n\n"
|
|
1649
|
+
|
|
1650
|
+
iaction = 1
|
|
1651
|
+
act_number = iaction + 1
|
|
1652
|
+
act_name = f"INJVCL{well_number:03d}{segment_number:03d}{act_number:1d}"
|
|
1653
|
+
if len(act_name) > 13:
|
|
1654
|
+
raise CompletorError("Too many wells and/or too many segments with Injection Valve")
|
|
1655
|
+
action += (
|
|
1656
|
+
f"ACTIONX\n{act_name} 1000000 /\n"
|
|
1657
|
+
f"SWFR '{well_name}' {segment_number} "
|
|
1658
|
+
f"{sign[iaction]} {water_segment_rate_cutoff} AND /\n"
|
|
1659
|
+
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1660
|
+
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1661
|
+
)
|
|
1662
|
+
print_df = df_wseginjv[df_wseginjv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1663
|
+
print_df = print_df[header[iaction]] # type: ignore
|
|
1664
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1665
|
+
|
|
1666
|
+
for item in header[iaction]:
|
|
1667
|
+
header_string += " " + item
|
|
1668
|
+
header_string = header_string.rstrip() + "\n"
|
|
1669
|
+
print_df = header_string + dataframe_tostring(print_df, True, False, False) # type: ignore
|
|
1670
|
+
print_df += "\n/\n"
|
|
1671
|
+
print_df += f"\nUDQ\n ASSIGN SUVTRIG {well_name} {segment_number} 0 /\n/\n"
|
|
1672
|
+
action += print_df + "\nENDACTIO\n\n"
|
|
1673
|
+
|
|
1674
|
+
# Trigger parameter is segment pressure drop
|
|
1675
|
+
elif df_wseginjv[Headers.TRIGGER_PARAMETER].iloc[idx] == "SPRD":
|
|
1676
|
+
pressure_drop_cutoff = -1 * df_wseginjv[Headers.TRIGGER_VALUE].iloc[idx]
|
|
1677
|
+
iaction = 0
|
|
1678
|
+
act_number = iaction + 1
|
|
1679
|
+
act_name = f"INJVOP{well_number:03d}{segment_number:03d}{act_number:1d}"
|
|
1680
|
+
if len(act_name) > 13:
|
|
1681
|
+
raise CompletorError("Too many wells and/or too many segments with Injection Valve")
|
|
1682
|
+
action += (
|
|
1683
|
+
f"ACTIONX\n{act_name} 1000000 /\n"
|
|
1684
|
+
f"SPRD '{well_name}' {segment_number} "
|
|
1685
|
+
f"{sign[iaction]} {pressure_drop_cutoff} AND /\n"
|
|
1686
|
+
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1687
|
+
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1688
|
+
)
|
|
1689
|
+
print_df = df_wseginjv[df_wseginjv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1690
|
+
print_df = print_df[header[iaction]] # type: ignore
|
|
1691
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1692
|
+
|
|
1693
|
+
for item in header[iaction]:
|
|
1694
|
+
header_string += " " + item
|
|
1695
|
+
header_string = header_string.rstrip() + "\n"
|
|
1696
|
+
print_df = header_string + dataframe_tostring(print_df, True, False, False) # type: ignore
|
|
1697
|
+
print_df += "\n/\n"
|
|
1698
|
+
print_df += f"\nUDQ\n ASSIGN SUVTRIG {well_name} {segment_number} 1 /\n/\n"
|
|
1699
|
+
action += print_df + "\nENDACTIO\n\n"
|
|
1700
|
+
|
|
1701
|
+
iaction = 1
|
|
1702
|
+
act_number = iaction + 1
|
|
1703
|
+
act_name = f"INJVCL{well_number:03d}{segment_number:03d}{act_number:1d}"
|
|
1704
|
+
if len(act_name) > 13:
|
|
1705
|
+
raise CompletorError("Too many wells and/or too many segments with Injection Valve")
|
|
1706
|
+
action += (
|
|
1707
|
+
f"ACTIONX\n{act_name} 1000000 /\n"
|
|
1708
|
+
f"SPRD '{well_name}' {segment_number} "
|
|
1709
|
+
f"{sign[iaction]} {pressure_drop_cutoff} AND /\n"
|
|
1710
|
+
f"SUVTRIG '{well_name}' {segment_number} "
|
|
1711
|
+
f"= {suvtrig[iaction]} /\n/\n\n"
|
|
1712
|
+
)
|
|
1713
|
+
print_df = df_wseginjv[df_wseginjv[Headers.START_SEGMENT_NUMBER] == segment_number]
|
|
1714
|
+
print_df = print_df[header[iaction]] # type: ignore
|
|
1715
|
+
header_string = Keywords.WELL_SEGMENTS_VALVE + "\n--"
|
|
1716
|
+
|
|
1717
|
+
for item in header[iaction]:
|
|
1718
|
+
header_string += " " + item
|
|
1719
|
+
header_string = header_string.rstrip() + "\n"
|
|
1720
|
+
print_df = header_string + dataframe_tostring(print_df, True, False, False) # type: ignore
|
|
1721
|
+
print_df += "\n/\n"
|
|
1722
|
+
print_df += f"\nUDQ\n ASSIGN SUVTRIG {well_name} {segment_number} 0 /\n/\n"
|
|
1723
|
+
action += print_df + "\nENDACTIO\n\n"
|
|
1724
|
+
else:
|
|
1725
|
+
raise CompletorError("Trigger paramater given is not supported")
|
|
1726
|
+
return action
|
|
1727
|
+
|
|
1728
|
+
|
|
1516
1729
|
def print_wsegdualrcp(df_wsegdualrcp: pd.DataFrame, well_number: int) -> str:
|
|
1517
1730
|
"""Print for DUALRCP devices.
|
|
1518
1731
|
|
|
@@ -1616,3 +1829,143 @@ def print_wsegdualrcp(df_wsegdualrcp: pd.DataFrame, well_number: int) -> str:
|
|
|
1616
1829
|
print_df = Keywords.AUTONOMOUS_INFLOW_CONTROL_DEVICE + "\n" + dataframe_tostring(print_df, True)
|
|
1617
1830
|
action += f"{print_df}\n/\nENDACTIO\n\n"
|
|
1618
1831
|
return action
|
|
1832
|
+
|
|
1833
|
+
|
|
1834
|
+
def print_wsegdensity_pyaction(df_wsegdensity: pd.DataFrame) -> str:
|
|
1835
|
+
"""Create PYACTION code.
|
|
1836
|
+
|
|
1837
|
+
Args:
|
|
1838
|
+
df_wsegdensity: Output from function prepare_wsegdensity.
|
|
1839
|
+
|
|
1840
|
+
Returns:
|
|
1841
|
+
Final code output formatted in PYACTION.
|
|
1842
|
+
"""
|
|
1843
|
+
data_dict = df_wsegdensity.to_dict(orient="list")
|
|
1844
|
+
final_code = f"""
|
|
1845
|
+
import opm_embedded
|
|
1846
|
+
|
|
1847
|
+
ecl_state = opm_embedded.current_ecl_state
|
|
1848
|
+
schedule = opm_embedded.current_schedule
|
|
1849
|
+
report_step = opm_embedded.current_report_step
|
|
1850
|
+
summary_state = opm_embedded.current_summary_state
|
|
1851
|
+
|
|
1852
|
+
if 'setup_done' not in locals():
|
|
1853
|
+
execution_counter = dict()
|
|
1854
|
+
executed = False
|
|
1855
|
+
setup_done = True
|
|
1856
|
+
|
|
1857
|
+
data={data_dict}
|
|
1858
|
+
|
|
1859
|
+
for i in range(len(data["WELL"])):
|
|
1860
|
+
well_name = data["WELL"][i]
|
|
1861
|
+
segment_number = data["START_SEGMENT_NUMBER"][i]
|
|
1862
|
+
flow_coefficient = data["FLOW_COEFFICIENT"][i]
|
|
1863
|
+
oil_flow_area = data["OIL_FLOW_CROSS_SECTIONAL_AREA"][i]
|
|
1864
|
+
gas_flow_area = data["GAS_FLOW_CROSS_SECTIONAL_AREA"][i]
|
|
1865
|
+
water_flow_area = data["WATER_FLOW_CROSS_SECTIONAL_AREA"][i]
|
|
1866
|
+
max_flow_area = data["MAX_FLOW_CROSS_SECTIONAL_AREA"][i]
|
|
1867
|
+
water_low = data["WATER_HOLDUP_FRACTION_LOW_CUTOFF"][i]
|
|
1868
|
+
water_high = data["WATER_HOLDUP_FRACTION_HIGH_CUTOFF"][i]
|
|
1869
|
+
gas_low = data["GAS_HOLDUP_FRACTION_LOW_CUTOFF"][i]
|
|
1870
|
+
gas_high = data["GAS_HOLDUP_FRACTION_HIGH_CUTOFF"][i]
|
|
1871
|
+
defaults = data["DEFAULTS"][i]
|
|
1872
|
+
|
|
1873
|
+
swhf = summary_state[f"SWHF:{{well_name}}:{{segment_number}}"]
|
|
1874
|
+
sghf = summary_state[f"SGHF:{{well_name}}:{{segment_number}}"]
|
|
1875
|
+
suvtrig = summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"]
|
|
1876
|
+
|
|
1877
|
+
keyword_oil = (
|
|
1878
|
+
f"WSEGVALV\\n"
|
|
1879
|
+
f" '{{well_name}}' {{segment_number}} {{flow_coefficient}} {{oil_flow_area}} {{defaults}} {{max_flow_area}} /\\n/"
|
|
1880
|
+
)
|
|
1881
|
+
keyword_water = (
|
|
1882
|
+
f"WSEGVALV\\n"
|
|
1883
|
+
f" '{{well_name}}' {{segment_number}} {{flow_coefficient}} {{water_flow_area}} {{defaults}} {{max_flow_area}} /\\n/"
|
|
1884
|
+
)
|
|
1885
|
+
keyword_gas = (
|
|
1886
|
+
f"WSEGVALV\\n"
|
|
1887
|
+
f" '{{well_name}}' {{segment_number}} {{flow_coefficient}} {{gas_flow_area}} {{defaults}} {{max_flow_area}} /\\n/"
|
|
1888
|
+
)
|
|
1889
|
+
|
|
1890
|
+
key = (well_name, segment_number)
|
|
1891
|
+
execution_counter.setdefault(key, 0)
|
|
1892
|
+
|
|
1893
|
+
if execution_counter[key] == 0:
|
|
1894
|
+
schedule.insert_keywords(keyword_oil, report_step)
|
|
1895
|
+
summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"] = 0
|
|
1896
|
+
|
|
1897
|
+
if execution_counter[key] < 1000000:
|
|
1898
|
+
if swhf is not None and sghf is not None:
|
|
1899
|
+
if swhf <= water_high and sghf > gas_high and suvtrig == 0:
|
|
1900
|
+
schedule.insert_keywords(keyword_gas, report_step)
|
|
1901
|
+
summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"] = 1
|
|
1902
|
+
execution_counter[key] += 1
|
|
1903
|
+
|
|
1904
|
+
elif swhf > water_high and sghf <= gas_high and suvtrig == 0:
|
|
1905
|
+
schedule.insert_keywords(keyword_water, report_step)
|
|
1906
|
+
summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"] = 2
|
|
1907
|
+
execution_counter[key] += 1
|
|
1908
|
+
|
|
1909
|
+
elif sghf < gas_low and suvtrig == 1:
|
|
1910
|
+
schedule.insert_keywords(keyword_oil, report_step)
|
|
1911
|
+
summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"] = 0
|
|
1912
|
+
execution_counter[key] += 1
|
|
1913
|
+
|
|
1914
|
+
elif swhf < water_low and suvtrig == 2:
|
|
1915
|
+
schedule.insert_keywords(keyword_oil, report_step)
|
|
1916
|
+
summary_state[f"SUVTRIG:{{well_name}}:{{segment_number}}"] = 0
|
|
1917
|
+
execution_counter[key] += 1
|
|
1918
|
+
"""
|
|
1919
|
+
return final_code
|
|
1920
|
+
|
|
1921
|
+
|
|
1922
|
+
def print_python_file(code: str, dir: str, well_name: str, lateral_number: int) -> str:
|
|
1923
|
+
"""Print Python PYACTION file.
|
|
1924
|
+
|
|
1925
|
+
Args:
|
|
1926
|
+
code: Final code output formatted in PYACTION.
|
|
1927
|
+
dir: Output path.
|
|
1928
|
+
well_name: Well name.
|
|
1929
|
+
lateral_number: Lateral number.
|
|
1930
|
+
|
|
1931
|
+
Returns:
|
|
1932
|
+
Python file with PYACTION format, output directory with FMU format.
|
|
1933
|
+
"""
|
|
1934
|
+
base_dir = Path.cwd() if Path(dir).parent == Path(".") else Path(dir).parent
|
|
1935
|
+
fmu_path = Path("eclipse/include/")
|
|
1936
|
+
if str(fmu_path) in str(base_dir):
|
|
1937
|
+
base_include_path = Path("../include/schedule")
|
|
1938
|
+
else:
|
|
1939
|
+
base_include_path = Path("")
|
|
1940
|
+
output_directory = f"{base_include_path}/wsegdensity_{well_name}_{lateral_number}.py"
|
|
1941
|
+
python_file = base_dir / f"wsegdensity_{well_name}_{lateral_number}.py"
|
|
1942
|
+
with open(python_file, "w") as file:
|
|
1943
|
+
file.writelines(code)
|
|
1944
|
+
return output_directory
|
|
1945
|
+
|
|
1946
|
+
|
|
1947
|
+
def print_wsegdensity_include(output_directory: str, well_name: str, lateral_number: int) -> str:
|
|
1948
|
+
"""Formatted PYACTION include in the output file.
|
|
1949
|
+
|
|
1950
|
+
Args:
|
|
1951
|
+
output_directory: Include file path in FMU relative format.
|
|
1952
|
+
well_name: Well name.
|
|
1953
|
+
lateral_number: Lateral number.
|
|
1954
|
+
|
|
1955
|
+
Returns:
|
|
1956
|
+
Include file output for the output file.
|
|
1957
|
+
"""
|
|
1958
|
+
action = f"""
|
|
1959
|
+
-------------------------------------
|
|
1960
|
+
-- START OF PYACTION SECTION
|
|
1961
|
+
|
|
1962
|
+
PYACTION
|
|
1963
|
+
WSEGDENSITY_{well_name}_{lateral_number} UNLIMITED /
|
|
1964
|
+
|
|
1965
|
+
'{output_directory}' /
|
|
1966
|
+
|
|
1967
|
+
-- END OF PYACTION SECTION
|
|
1968
|
+
-------------------------------------
|
|
1969
|
+
"""
|
|
1970
|
+
|
|
1971
|
+
return action
|
completor/read_casefile.py
CHANGED
|
@@ -48,7 +48,7 @@ class ReadCasefile:
|
|
|
48
48
|
This class reads the case/input file of the Completor program.
|
|
49
49
|
It reads the following keywords:
|
|
50
50
|
COMPLETION, SEGMENTLENGTH, JOINTLENGTH, AUTONOMOUS_INFLOW_CONTROL_DEVICE, WELL_SEGMENTS_VALVE,
|
|
51
|
-
INFLOW_CONTROL_DEVICE, DENSITY_DRIVEN, DUAL_RATE_CONTROLLED_PRODUCTION, INFLOW_CONTROL_VALVE.
|
|
51
|
+
INFLOW_CONTROL_DEVICE, DENSITY_DRIVEN, INJECTION_VALVE, DUAL_RATE_CONTROLLED_PRODUCTION, INFLOW_CONTROL_VALVE.
|
|
52
52
|
In the absence of some keywords, the program uses the default values.
|
|
53
53
|
|
|
54
54
|
Attributes:
|
|
@@ -64,6 +64,7 @@ class ReadCasefile:
|
|
|
64
64
|
wsegvalv_table (pd.DataFrame): WELL_SEGMENTS_VALVE.
|
|
65
65
|
wsegicv_table (pd.DataFrame): INFLOW_CONTROL_VALVE.
|
|
66
66
|
wsegdensity_table (pd.DataFrame): DENSITY_DRIVEN.
|
|
67
|
+
wseginjv_table (pd.DataFrame): INJECTION_VALVE.
|
|
67
68
|
wsegdualrcp_table (pd.DataFrame): DUAL_RATE_CONTROLLED_PRODUCTION.
|
|
68
69
|
strict (bool): USE_STRICT. If TRUE it will exit if any lateral is not defined in the case-file. Default to TRUE.
|
|
69
70
|
lat2device (pd.DataFrame): LATERAL_TO_DEVICE.
|
|
@@ -90,6 +91,7 @@ class ReadCasefile:
|
|
|
90
91
|
self.minimum_segment_length: float = 0.0
|
|
91
92
|
self.strict = True
|
|
92
93
|
self.gp_perf_devicelayer = False
|
|
94
|
+
self.python_dependent = False
|
|
93
95
|
self.schedule_file = schedule_file
|
|
94
96
|
self.output_file = output_file
|
|
95
97
|
self.completion_table = pd.DataFrame()
|
|
@@ -99,6 +101,7 @@ class ReadCasefile:
|
|
|
99
101
|
self.wsegsicd_table = pd.DataFrame()
|
|
100
102
|
self.wsegvalv_table = pd.DataFrame()
|
|
101
103
|
self.wsegdensity_table = pd.DataFrame()
|
|
104
|
+
self.wseginjv_table = pd.DataFrame()
|
|
102
105
|
self.wsegdualrcp_table = pd.DataFrame()
|
|
103
106
|
self.wsegicv_table = pd.DataFrame()
|
|
104
107
|
self.lat2device = pd.DataFrame()
|
|
@@ -117,6 +120,8 @@ class ReadCasefile:
|
|
|
117
120
|
self.read_wsegvalv()
|
|
118
121
|
self.read_wsegsicd()
|
|
119
122
|
self.read_wsegdensity()
|
|
123
|
+
self.read_python_dependent()
|
|
124
|
+
self.read_wseginjv()
|
|
120
125
|
self.read_wsegdualrcp()
|
|
121
126
|
self.read_wsegicv()
|
|
122
127
|
self.read_lat2device()
|
|
@@ -449,10 +454,14 @@ class ReadCasefile:
|
|
|
449
454
|
Headers.F,
|
|
450
455
|
Headers.AICD_CALIBRATION_FLUID_DENSITY,
|
|
451
456
|
Headers.AICD_FLUID_VISCOSITY,
|
|
457
|
+
Headers.Z,
|
|
452
458
|
]
|
|
453
|
-
|
|
454
|
-
self._create_dataframe_with_columns(header, start_index, end_index)
|
|
455
|
-
|
|
459
|
+
try:
|
|
460
|
+
df_temp = self._create_dataframe_with_columns(header, start_index, end_index)
|
|
461
|
+
except CaseReaderFormatError:
|
|
462
|
+
header.remove(Headers.Z)
|
|
463
|
+
df_temp = self._create_dataframe_with_columns(header, start_index, end_index)
|
|
464
|
+
self.wsegaicd_table = input_validation.set_format_wsegaicd(df_temp)
|
|
456
465
|
device_checks = self.completion_table[
|
|
457
466
|
self.completion_table[Headers.DEVICE_TYPE] == Content.AUTONOMOUS_INFLOW_CONTROL_DEVICE
|
|
458
467
|
][Headers.DEVICE_NUMBER].to_numpy()
|
|
@@ -514,6 +523,52 @@ class ReadCasefile:
|
|
|
514
523
|
if not check_contents(device_checks, self.wsegdensity_table[Headers.DEVICE_NUMBER].to_numpy()):
|
|
515
524
|
raise CompletorError(f"Not all device in COMPLETION is specified in {key}")
|
|
516
525
|
|
|
526
|
+
def read_wseginjv(self) -> None:
|
|
527
|
+
"""Read the INJECTION_VALVE keyword in the case file.
|
|
528
|
+
|
|
529
|
+
Raises:
|
|
530
|
+
CompletorError: If INJECTION_VALVE is not defined and INJV is used in COMPLETION,
|
|
531
|
+
or if the device number is not found.
|
|
532
|
+
If not all devices in COMPLETION are specified in INJECTION_VALVE.
|
|
533
|
+
"""
|
|
534
|
+
start_index, end_index = parse.locate_keyword(self.content, Keywords.INJECTION_VALVE)
|
|
535
|
+
if start_index == end_index:
|
|
536
|
+
if Content.INJECTION_VALVE in self.completion_table[Headers.DEVICE_TYPE]:
|
|
537
|
+
raise CompletorError(
|
|
538
|
+
f"{Keywords.INJECTION_VALVE} keyword must be defined, if INJV is used in the completion."
|
|
539
|
+
)
|
|
540
|
+
else:
|
|
541
|
+
# Table headers
|
|
542
|
+
header = [
|
|
543
|
+
Headers.DEVICE_NUMBER,
|
|
544
|
+
Headers.TRIGGER_PARAMETER,
|
|
545
|
+
Headers.TRIGGER_VALUE,
|
|
546
|
+
Headers.FLOW_COEFFICIENT,
|
|
547
|
+
Headers.PRIMARY_FLOW_CROSS_SECTIONAL_AREA,
|
|
548
|
+
Headers.SECONDARY_FLOW_CROSS_SECTIONAL_AREA,
|
|
549
|
+
]
|
|
550
|
+
self.wseginjv_table = input_validation.set_format_wseginjv(
|
|
551
|
+
self._create_dataframe_with_columns(header, start_index, end_index)
|
|
552
|
+
)
|
|
553
|
+
# Check if the device in COMPLETION is exist in INJECTION_VALVE
|
|
554
|
+
device_checks = self.completion_table[
|
|
555
|
+
self.completion_table[Headers.DEVICE_TYPE] == Content.INJECTION_VALVE
|
|
556
|
+
][Headers.DEVICE_NUMBER].to_numpy()
|
|
557
|
+
if not check_contents(device_checks, self.wseginjv_table[Headers.DEVICE_NUMBER].to_numpy()):
|
|
558
|
+
raise CompletorError(f"Not all device in COMPLETION is specified in {Keywords.INJECTION_VALVE}")
|
|
559
|
+
|
|
560
|
+
def read_python_dependent(self) -> None:
|
|
561
|
+
"""Read PYTHON keyword. Accepts TRUE or just '/' as True."""
|
|
562
|
+
start_index, end_index = parse.locate_keyword(self.content, Keywords.PYTHON_DEPENDENT)
|
|
563
|
+
|
|
564
|
+
if end_index == start_index + 1:
|
|
565
|
+
# Keyword followed directly by '/', no value = True
|
|
566
|
+
self.python_dependent = True
|
|
567
|
+
elif end_index == start_index + 2:
|
|
568
|
+
val = self.content[start_index + 1]
|
|
569
|
+
if val.upper() == "TRUE":
|
|
570
|
+
self.python_dependent = True
|
|
571
|
+
|
|
517
572
|
def read_wsegdualrcp(self) -> None:
|
|
518
573
|
"""Read the DUALRCP keyword in the case file.
|
|
519
574
|
|
completor/utils.py
CHANGED
|
@@ -193,6 +193,7 @@ def get_active_wells(completion_table: pd.DataFrame, gp_perf_devicelayer: bool)
|
|
|
193
193
|
Content.AUTONOMOUS_INFLOW_CONTROL_DEVICE,
|
|
194
194
|
Content.DUAL_RATE_CONTROLLED_PRODUCTION,
|
|
195
195
|
Content.DENSITY,
|
|
196
|
+
Content.INJECTION_VALVE,
|
|
196
197
|
Content.INFLOW_CONTROL_DEVICE,
|
|
197
198
|
Content.VALVE,
|
|
198
199
|
Content.INFLOW_CONTROL_VALVE,
|
completor/visualize_well.py
CHANGED
|
@@ -48,6 +48,8 @@ def visualize_device(axs: Axes, df_well: pd.DataFrame) -> Axes:
|
|
|
48
48
|
axs.plot(xpar, ypar, "rv-", markevery=[1])
|
|
49
49
|
elif df_device[Headers.DEVICE_TYPE].iloc[idx] == Content.DENSITY:
|
|
50
50
|
axs.plot(xpar, ypar, "rP-", markevery=[1])
|
|
51
|
+
elif df_device[Headers.DEVICE_TYPE].iloc[idx] == Content.INJECTION_VALVE:
|
|
52
|
+
axs.plot(xpar, ypar, "rP-", markevery=[1])
|
|
51
53
|
elif df_device[Headers.DEVICE_TYPE].iloc[idx] == Content.DUAL_RATE_CONTROLLED_PRODUCTION:
|
|
52
54
|
axs.plot(xpar, ypar, "r*-", markevery=[1])
|
|
53
55
|
return axs
|
completor/wells.py
CHANGED
|
@@ -220,6 +220,8 @@ class Lateral:
|
|
|
220
220
|
df_well = completion.get_device(df_well, case.wsegaicd_table, Content.AUTONOMOUS_INFLOW_CONTROL_DEVICE)
|
|
221
221
|
if Content.DENSITY in active_devices:
|
|
222
222
|
df_well = completion.get_device(df_well, case.wsegdensity_table, Content.DENSITY)
|
|
223
|
+
if Content.INJECTION_VALVE in active_devices:
|
|
224
|
+
df_well = completion.get_device(df_well, case.wseginjv_table, Content.INJECTION_VALVE)
|
|
223
225
|
if Content.DUAL_RATE_CONTROLLED_PRODUCTION in active_devices:
|
|
224
226
|
df_well = completion.get_device(df_well, case.wsegdualrcp_table, Content.DUAL_RATE_CONTROLLED_PRODUCTION)
|
|
225
227
|
if Content.INFLOW_CONTROL_VALVE in active_devices:
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: completor
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Advanced multi-segmented well completion tool.
|
|
5
5
|
Home-page: https://github.com/equinor/completor
|
|
6
6
|
License: LGPL-3.0-only
|
|
7
7
|
Author: Equinor ASA
|
|
8
8
|
Author-email: opensource@equinor.com
|
|
9
|
-
Requires-Python: >=3.11,<
|
|
9
|
+
Requires-Python: >=3.11,<3.14
|
|
10
10
|
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
11
11
|
Classifier: Natural Language :: English
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
17
|
Provides-Extra: ert
|
|
17
18
|
Provides-Extra: test
|
|
18
|
-
Requires-Dist: ert (>=
|
|
19
|
+
Requires-Dist: ert (>=14,<15) ; extra == "ert"
|
|
19
20
|
Requires-Dist: matplotlib (>=3.9,<4.0)
|
|
20
|
-
Requires-Dist: numpy (>=
|
|
21
|
+
Requires-Dist: numpy (>=2.0,<3.0)
|
|
21
22
|
Requires-Dist: pandas (>=2.2,<3.0)
|
|
22
23
|
Requires-Dist: pytest (>=8.3,<9.0) ; extra == "test"
|
|
23
24
|
Requires-Dist: pytest-env (>=1,<2) ; extra == "test"
|
|
24
25
|
Requires-Dist: pytest-xdist (>=3.6,<4.0) ; extra == "test"
|
|
25
26
|
Requires-Dist: rstcheck-core (>=1.2,<2.0) ; extra == "test"
|
|
26
|
-
Requires-Dist: scipy (>=1.14,<2.0)
|
|
27
27
|
Requires-Dist: tqdm (>=4.66,<5.0)
|
|
28
28
|
Project-URL: Bug Tracker, https://github.com/equinor/completor/issues
|
|
29
29
|
Project-URL: Documentation, https://equinor.github.io/completor
|
|
@@ -44,7 +44,7 @@ Detailed documentation for usage of completor can be found at https://equinor.gi
|
|
|
44
44
|
## Getting started as a user
|
|
45
45
|
|
|
46
46
|
### Prerequisites
|
|
47
|
-
* [Python](https://www.python.org/), version 3.11
|
|
47
|
+
* [Python](https://www.python.org/), version 3.11 or 3.13.
|
|
48
48
|
* [ERT](https://github.com/equinor/ert) (optional, and only available on Linux.)
|
|
49
49
|
|
|
50
50
|
### Installation
|
|
@@ -85,7 +85,7 @@ and making a pull request.
|
|
|
85
85
|
See [Contribution Document](documentation/docs/contribution_guide.mdx) on how to contribute.
|
|
86
86
|
|
|
87
87
|
### Install completor as dev
|
|
88
|
-
In order to run Completor® you need to have versions of [Python 3.11](https://www.python.org/downloads/) installed.
|
|
88
|
+
In order to run Completor® you need to have versions of [Python 3.11, 3.12 or 3.13](https://www.python.org/downloads/) installed.
|
|
89
89
|
#### Source code
|
|
90
90
|
Clone the [Completor® repository](https://github.com/equinor/completor) to get the source code.
|
|
91
91
|
```bash
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
completor/__init__.py,sha256=k6amf7jhp7KkBIlaw93-NZITxyZjPSzA5McFAZh8yv8,76
|
|
2
|
+
completor/completion.py,sha256=quhQOdQREv8MsHW5amT0sG-84Y12KVdT0eylbKCul3g,31177
|
|
3
|
+
completor/config_jobs/run_completor,sha256=XePKj2xocfGF0XFRqr7sqfpZGrjgWcfaZLHIhVvGFCQ,600
|
|
4
|
+
completor/constants.py,sha256=2e1o5Env5lHyhopkrs_C__9DksS5xml1-Ea_X3cLl0E,13521
|
|
5
|
+
completor/create_output.py,sha256=6ygglcCUYYII5sWr_ey4cvUCCsXb0UGqXY5GQAzX8fQ,25969
|
|
6
|
+
completor/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
completor/exceptions/clean_exceptions.py,sha256=uQ2jgGfvUDAoS56JBWh-8ZCPIMB4hvYxLF-snA-_-pg,373
|
|
8
|
+
completor/exceptions/exceptions.py,sha256=eS00mVzmC4gQ7MUyGSknvKotmo2XzNGyp007mhjLMy0,5081
|
|
9
|
+
completor/get_version.py,sha256=LMzybu7m-O203lUSZvyu86J4bMobbjE9A23fWLDlxaM,168
|
|
10
|
+
completor/hook_implementations/jobs.py,sha256=8Ao8UadfJzEY7jWzj6C_OXm18fHmfXrbCB2_jS7KHiU,2180
|
|
11
|
+
completor/input_validation.py,sha256=F17AWi-qR6cX5_1lEFgtYOMOO0Xo3gTtL2ETM5P_uGE,15022
|
|
12
|
+
completor/launch_args_parser.py,sha256=gb3FcyufZlRnKS3BZkFmgVH1VoSxMD0MbCLsHZKmz4c,1413
|
|
13
|
+
completor/logger.py,sha256=gYDbPL8ca5qT_MqYlDKEMKcSfIXW_59QklX8Gss5b2U,4784
|
|
14
|
+
completor/main.py,sha256=HlQzv5gpBYdDbYTBLSkAnK7o6d2QfTQnjrNizq3Ym6s,9343
|
|
15
|
+
completor/parse.py,sha256=EGlt9CgkrXPqa7woyWQ5t_nh6OWsFrc2SJr8aFr_KsQ,20133
|
|
16
|
+
completor/prepare_outputs.py,sha256=o-7SLD0F5jiw5_lnq5kewB1tYOiLa0u2TxGz6kRIO-8,87613
|
|
17
|
+
completor/read_casefile.py,sha256=NebZRrO35aqrZIJ7eHcS6buBbAaDWw8wUtc4kBHsV2U,38184
|
|
18
|
+
completor/read_schedule.py,sha256=IYyCubOggFGg664h1flTl7MUJhJWyibr6JsptnURjUA,18101
|
|
19
|
+
completor/utils.py,sha256=9Qayt7xMsimpoVDo5sL86gVaQBbIOezMBRyMXd3haXw,13598
|
|
20
|
+
completor/visualization.py,sha256=ObxThqIyW3fsvVIupxVsgySFI_54n_Di-HTzFtDMSgo,4580
|
|
21
|
+
completor/visualize_well.py,sha256=HLglSN2ce-u9nklJelqwhSxwwaj7n-aU6o8lUScbiI0,8790
|
|
22
|
+
completor/wells.py,sha256=Q2detK0FxIBgusYkCRmomRIfcScBNvNTYX43GFyAHGw,12246
|
|
23
|
+
completor-1.3.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
24
|
+
completor-1.3.0.dist-info/METADATA,sha256=IL5-ncKANt09P_kbEZeJu0DV3YpjAS4RiFtCThhHBKM,8018
|
|
25
|
+
completor-1.3.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
26
|
+
completor-1.3.0.dist-info/entry_points.txt,sha256=co5L2_CC2QQWVdEALeMp-NIC4mx4nRpcLcvpVXMYdeI,106
|
|
27
|
+
completor-1.3.0.dist-info/RECORD,,
|
completor-1.1.3.dist-info/RECORD
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
completor/__init__.py,sha256=k6amf7jhp7KkBIlaw93-NZITxyZjPSzA5McFAZh8yv8,76
|
|
2
|
-
completor/completion.py,sha256=--c2tN1ItE8r7YjxxOrTeZ71tz0KCVStxzWkjU-ERy4,30925
|
|
3
|
-
completor/config_jobs/run_completor,sha256=XePKj2xocfGF0XFRqr7sqfpZGrjgWcfaZLHIhVvGFCQ,600
|
|
4
|
-
completor/constants.py,sha256=N1u1SrsZap8hSvd4Cs9LCsNZBBIJy_3P2wd9djdTrgg,13028
|
|
5
|
-
completor/create_output.py,sha256=T9W_uNdPzPkW1IyTAXWV38hF8ZvZs5ZrmrxvNHuS-mM,22909
|
|
6
|
-
completor/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
completor/exceptions/clean_exceptions.py,sha256=uQ2jgGfvUDAoS56JBWh-8ZCPIMB4hvYxLF-snA-_-pg,373
|
|
8
|
-
completor/exceptions/exceptions.py,sha256=eS00mVzmC4gQ7MUyGSknvKotmo2XzNGyp007mhjLMy0,5081
|
|
9
|
-
completor/get_version.py,sha256=LMzybu7m-O203lUSZvyu86J4bMobbjE9A23fWLDlxaM,168
|
|
10
|
-
completor/hook_implementations/jobs.py,sha256=8Ao8UadfJzEY7jWzj6C_OXm18fHmfXrbCB2_jS7KHiU,2180
|
|
11
|
-
completor/input_validation.py,sha256=jNqYeAZFxrGJy5-xwK-n1Y0t9EKvJ12aA_z6yzN3N5E,14315
|
|
12
|
-
completor/launch_args_parser.py,sha256=gb3FcyufZlRnKS3BZkFmgVH1VoSxMD0MbCLsHZKmz4c,1413
|
|
13
|
-
completor/logger.py,sha256=gYDbPL8ca5qT_MqYlDKEMKcSfIXW_59QklX8Gss5b2U,4784
|
|
14
|
-
completor/main.py,sha256=ipARMDXXqPYRtBxYQnlj5MohepwkgrQkX3s2IJEaEcI,9151
|
|
15
|
-
completor/parse.py,sha256=EGlt9CgkrXPqa7woyWQ5t_nh6OWsFrc2SJr8aFr_KsQ,20133
|
|
16
|
-
completor/prepare_outputs.py,sha256=GAQsRFrz7SwilExCq0w6f1tZE-4TmpHIeMS6_CwdbCM,72547
|
|
17
|
-
completor/read_casefile.py,sha256=ToE7wGh0bKlS8hNFlRN21sPAufPuhRAvadkZGwB2ky4,35452
|
|
18
|
-
completor/read_schedule.py,sha256=IYyCubOggFGg664h1flTl7MUJhJWyibr6JsptnURjUA,18101
|
|
19
|
-
completor/utils.py,sha256=ieqgLXfjbjDXHHSW283bliznj04Qep5KRUYGi_BXQRI,13557
|
|
20
|
-
completor/visualization.py,sha256=ObxThqIyW3fsvVIupxVsgySFI_54n_Di-HTzFtDMSgo,4580
|
|
21
|
-
completor/visualize_well.py,sha256=fkrjlEtSLsRrmSHoPYtCKIrCeEvXg4LsYyEEPryAB0I,8653
|
|
22
|
-
completor/wells.py,sha256=GgZyfRa5wpSMIJUl5CPi5F1zdmU0XK6QjSduTzuh2NI,12093
|
|
23
|
-
completor-1.1.3.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
24
|
-
completor-1.1.3.dist-info/METADATA,sha256=TAE2gJSk-z2H0sRan100EzToaDlrisCAdlo_jVOVFzA,7979
|
|
25
|
-
completor-1.1.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
26
|
-
completor-1.1.3.dist-info/entry_points.txt,sha256=co5L2_CC2QQWVdEALeMp-NIC4mx4nRpcLcvpVXMYdeI,106
|
|
27
|
-
completor-1.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|