completor 1.4.0__py3-none-any.whl → 1.5.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/constants.py +19 -0
- completor/create_output.py +12 -3
- completor/icv_file_handling.py +362 -0
- completor/icv_functions.py +845 -0
- completor/initialization.py +563 -0
- completor/input_validation.py +63 -0
- completor/logger.py +1 -1
- completor/main.py +88 -19
- completor/parse.py +5 -5
- completor/read_casefile.py +429 -48
- completor/utils.py +133 -2
- {completor-1.4.0.dist-info → completor-1.5.0.dist-info}/METADATA +11 -3
- {completor-1.4.0.dist-info → completor-1.5.0.dist-info}/RECORD +16 -13
- {completor-1.4.0.dist-info → completor-1.5.0.dist-info}/LICENSE +0 -0
- {completor-1.4.0.dist-info → completor-1.5.0.dist-info}/WHEEL +0 -0
- {completor-1.4.0.dist-info → completor-1.5.0.dist-info}/entry_points.txt +0 -0
completor/main.py
CHANGED
|
@@ -7,6 +7,7 @@ import os
|
|
|
7
7
|
import re
|
|
8
8
|
import sys
|
|
9
9
|
import time
|
|
10
|
+
from pathlib import Path
|
|
10
11
|
|
|
11
12
|
from matplotlib.backends.backend_pdf import PdfPages # type: ignore
|
|
12
13
|
from tqdm import tqdm
|
|
@@ -15,15 +16,18 @@ from completor import create_output, parse, read_schedule, utils
|
|
|
15
16
|
from completor.constants import Keywords, ScheduleData
|
|
16
17
|
from completor.exceptions.clean_exceptions import CompletorError
|
|
17
18
|
from completor.get_version import get_version
|
|
19
|
+
from completor.icv_file_handling import IcvFileHandling
|
|
20
|
+
from completor.initialization import Initialization
|
|
18
21
|
from completor.launch_args_parser import get_parser
|
|
19
22
|
from completor.logger import handle_error_messages, logger
|
|
20
|
-
from completor.read_casefile import ReadCasefile
|
|
23
|
+
from completor.read_casefile import ICVReadCasefile, ReadCasefile
|
|
21
24
|
from completor.utils import (
|
|
22
|
-
abort,
|
|
23
25
|
clean_file_lines,
|
|
24
26
|
clean_raw_data,
|
|
27
|
+
completion_keyword_in_file,
|
|
25
28
|
find_keyword_data,
|
|
26
29
|
find_well_keyword_data,
|
|
30
|
+
icvc_keyword_in_file,
|
|
27
31
|
replace_preprocessing_names,
|
|
28
32
|
)
|
|
29
33
|
from completor.wells import Well
|
|
@@ -76,7 +80,7 @@ def get_content_and_path(case_content: str, file_path: str | None, keyword: str)
|
|
|
76
80
|
|
|
77
81
|
def create(
|
|
78
82
|
case_file: str, schedule: str, new_file: str, show_fig: bool = False, paths: tuple[str, str] | None = None
|
|
79
|
-
) -> tuple[ReadCasefile, Well | None]:
|
|
83
|
+
) -> tuple[ReadCasefile, Well | None, list[tuple[str, int]]]:
|
|
80
84
|
"""Create and write the advanced schedule file from input case- and schedule files.
|
|
81
85
|
|
|
82
86
|
Args:
|
|
@@ -87,10 +91,13 @@ def create(
|
|
|
87
91
|
paths: Optional additional paths.
|
|
88
92
|
|
|
89
93
|
Returns:
|
|
90
|
-
|
|
94
|
+
- ReadCasefile object.
|
|
95
|
+
- Well object or None if no well was found.
|
|
96
|
+
- Well segment list or None if no update of segment list.
|
|
91
97
|
"""
|
|
92
98
|
case = ReadCasefile(case_file=case_file, schedule_file=schedule, output_file=new_file)
|
|
93
99
|
active_wells = utils.get_active_wells(case.completion_table, case.gp_perf_devicelayer)
|
|
100
|
+
well_segment_list: list[tuple[str, int]] = []
|
|
94
101
|
pdf = None
|
|
95
102
|
figure_name = None
|
|
96
103
|
if show_fig:
|
|
@@ -109,6 +116,7 @@ def create(
|
|
|
109
116
|
schedule = re.sub(r"[^\S\r\n]+$", "", schedule, flags=re.MULTILINE)
|
|
110
117
|
meaningful_data: ScheduleData = {}
|
|
111
118
|
|
|
119
|
+
well_segment_list = []
|
|
112
120
|
try:
|
|
113
121
|
# Find the old data for each of the four main keywords.
|
|
114
122
|
for chunk in find_keyword_data(Keywords.WELL_SPECIFICATION, schedule):
|
|
@@ -132,7 +140,9 @@ def create(
|
|
|
132
140
|
except KeyError:
|
|
133
141
|
logger.warning(f"Well '{well_name}' is written in case file but does not exist in schedule file.")
|
|
134
142
|
continue
|
|
135
|
-
compdat, welsegs, compsegs, bonus = create_output.format_output(well, case, pdf)
|
|
143
|
+
compdat, welsegs, compsegs, bonus, df_icv = create_output.format_output(well, case, pdf)
|
|
144
|
+
if len(df_icv) > 0:
|
|
145
|
+
get_icv_segment(well_segment_list, df_icv)
|
|
136
146
|
for keyword in [Keywords.COMPLETION_SEGMENTS, Keywords.WELL_SEGMENTS, Keywords.COMPLETION_DATA]:
|
|
137
147
|
old_data = find_well_keyword_data(well_name, keyword, schedule)
|
|
138
148
|
if not old_data:
|
|
@@ -166,7 +176,14 @@ def create(
|
|
|
166
176
|
if err is not None:
|
|
167
177
|
raise err
|
|
168
178
|
|
|
169
|
-
return case, well
|
|
179
|
+
return case, well, well_segment_list
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def get_icv_segment(well_segment_list, icv_dataframe):
|
|
183
|
+
for row in range(len(icv_dataframe)):
|
|
184
|
+
well_name = icv_dataframe.iloc[row]["WELL"]
|
|
185
|
+
segment_number = int(icv_dataframe.iloc[row]["START_SEGMENT_NUMBER"])
|
|
186
|
+
well_segment_list.append((well_name, segment_number))
|
|
170
187
|
|
|
171
188
|
|
|
172
189
|
def main() -> None:
|
|
@@ -197,18 +214,17 @@ def main() -> None:
|
|
|
197
214
|
schedule_file_content, inputs.schedulefile = get_content_and_path(
|
|
198
215
|
case_file_content, inputs.schedulefile, Keywords.SCHEDULE_FILE
|
|
199
216
|
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
217
|
+
# If ICVC exists, it should not be mandatory to have whole schedule files
|
|
218
|
+
# Check on both schedule and case files first
|
|
219
|
+
if completion_keyword_in_file(inputs.inputfile) and not icvc_keyword_in_file(inputs.inputfile):
|
|
220
|
+
if isinstance(schedule_file_content, str):
|
|
221
|
+
parse.read_schedule_keywords(clean_file_lines(schedule_file_content.splitlines()), Keywords.main_keywords)
|
|
203
222
|
|
|
204
223
|
_, inputs.outputfile = get_content_and_path(case_file_content, inputs.outputfile, Keywords.OUT_FILE)
|
|
205
224
|
|
|
206
225
|
if inputs.outputfile is None:
|
|
207
226
|
if inputs.schedulefile is None:
|
|
208
|
-
raise ValueError(
|
|
209
|
-
"Could not find a path to schedule file. "
|
|
210
|
-
f"It must be provided as a input argument or within the case files keyword '{Keywords.SCHEDULE_FILE}'."
|
|
211
|
-
)
|
|
227
|
+
raise ValueError("Could not find a path to schedule file. It must be provided as a input argument.")
|
|
212
228
|
inputs.outputfile = inputs.schedulefile.split(".")[0] + "_advanced.wells"
|
|
213
229
|
|
|
214
230
|
paths_input_schedule = (inputs.inputfile, inputs.schedulefile)
|
|
@@ -217,16 +233,69 @@ def main() -> None:
|
|
|
217
233
|
logger.debug("-" * 60)
|
|
218
234
|
start_a = time.time()
|
|
219
235
|
|
|
220
|
-
handle_error_messages(create)(
|
|
236
|
+
case, well, well_start_segments = handle_error_messages(create)(
|
|
221
237
|
case_file_content, schedule_file_content, inputs.outputfile, inputs.figure, paths=paths_input_schedule
|
|
222
238
|
)
|
|
239
|
+
if icvc_keyword_in_file(inputs.inputfile):
|
|
240
|
+
# start running ICV Control
|
|
241
|
+
# the input schedule file to second run of ICV Control is the output file from Completor
|
|
242
|
+
# therefore
|
|
243
|
+
|
|
244
|
+
inputs.schedulefile = inputs.outputfile
|
|
245
|
+
inputs.schedulefile = os.path.abspath(inputs.schedulefile)
|
|
246
|
+
|
|
247
|
+
if inputs.outputfile is not None:
|
|
248
|
+
|
|
249
|
+
schedule_content, inputs.schedulefile = get_content_and_path(
|
|
250
|
+
case_file_content, inputs.schedulefile, Keywords.SCHEDULE_FILE
|
|
251
|
+
)
|
|
252
|
+
inputs.outputfile, inputs.outputdirectory = get_output_filename_and_directory(inputs)
|
|
253
|
+
|
|
254
|
+
if inputs.inputfile is not None:
|
|
255
|
+
create_icvc(case_file_content, schedule_content, inputs, well_start_segments)
|
|
223
256
|
|
|
224
257
|
logger.debug("Total runtime: %d", (time.time() - start_a))
|
|
225
258
|
logger.debug("-" * 60)
|
|
226
259
|
|
|
227
260
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
261
|
+
def get_output_filename_and_directory(inputs) -> tuple[str, str]:
|
|
262
|
+
"""Get the output filename and directory from the user input.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
arguments: Arguments from the command line.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
output_filename: The output filename.
|
|
269
|
+
output_directory: The output directory.
|
|
270
|
+
"""
|
|
271
|
+
if inputs.outputfile:
|
|
272
|
+
output_path = Path(inputs.outputfile)
|
|
273
|
+
output_filename = f"{output_path.name}"
|
|
274
|
+
else:
|
|
275
|
+
output_path = Path(inputs.schedulefile)
|
|
276
|
+
output_filename = f"{output_path.stem}.sch"
|
|
277
|
+
|
|
278
|
+
# use cwd as output directory if the output_path is just a filename. e.g. output.sch
|
|
279
|
+
output_directory = str(Path.cwd() if output_path.parent == Path(".") else output_path.parent)
|
|
280
|
+
return output_filename, output_directory
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def create_icvc(case_content: str, schedule_content: str | None, inputs, new_segments: str):
|
|
284
|
+
"""
|
|
285
|
+
Create ICV-control schedule- and include files from input case- and schedule files.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
input_case_content: Input case file.
|
|
289
|
+
schedule_content: Input schedule file.
|
|
290
|
+
arguments: Arguments from the command line.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
case = ICVReadCasefile(case_content, schedule_content, new_segments)
|
|
294
|
+
initials = Initialization(case, schedule_content)
|
|
295
|
+
file_data = {
|
|
296
|
+
"output_file_name": inputs.outputfile,
|
|
297
|
+
"output_directory": inputs.outputdirectory,
|
|
298
|
+
"schedule_file_path": inputs.schedulefile,
|
|
299
|
+
"input_case_file": inputs.inputfile,
|
|
300
|
+
}
|
|
301
|
+
IcvFileHandling(file_data, initials)
|
completor/parse.py
CHANGED
|
@@ -338,8 +338,8 @@ def get_welsegs_table(collections: list[ContentCollection]) -> tuple[pd.DataFram
|
|
|
338
338
|
try:
|
|
339
339
|
header_table: npt.NDArray[np.unicode_] | pd.DataFrame
|
|
340
340
|
record_table: npt.NDArray[np.unicode_] | pd.DataFrame
|
|
341
|
-
header_table = np.
|
|
342
|
-
record_table = np.
|
|
341
|
+
header_table = np.vstack((header_table, header_collection))
|
|
342
|
+
record_table = np.vstack((record_table, record_collection))
|
|
343
343
|
except NameError:
|
|
344
344
|
# First iteration
|
|
345
345
|
header_table = np.asarray(header_collection)
|
|
@@ -394,7 +394,7 @@ def get_welspecs_table(collections: list[ContentCollection]) -> pd.DataFrame:
|
|
|
394
394
|
if welspecs_table is None:
|
|
395
395
|
welspecs_table = np.copy(the_collection)
|
|
396
396
|
else:
|
|
397
|
-
welspecs_table = np.
|
|
397
|
+
welspecs_table = np.vstack((welspecs_table, the_collection))
|
|
398
398
|
|
|
399
399
|
if welspecs_table is None:
|
|
400
400
|
raise ValueError(f"Collection does not contain the '{Keywords.WELL_SPECIFICATION}' keyword")
|
|
@@ -424,7 +424,7 @@ def get_compdat_table(collections: list[ContentCollection]) -> pd.DataFrame:
|
|
|
424
424
|
if compdat_table is None:
|
|
425
425
|
compdat_table = np.copy(the_collection)
|
|
426
426
|
else:
|
|
427
|
-
compdat_table = np.
|
|
427
|
+
compdat_table = np.vstack((compdat_table, the_collection))
|
|
428
428
|
if compdat_table is None:
|
|
429
429
|
raise ValueError(f"Collection does not contain the '{Keywords.COMPLETION_DATA}' keyword")
|
|
430
430
|
compdat_table = pd.DataFrame(
|
|
@@ -472,7 +472,7 @@ def get_compsegs_table(collections: list[ContentCollection]) -> pd.DataFrame:
|
|
|
472
472
|
if compsegs_table is None:
|
|
473
473
|
compsegs_table = np.copy(the_collection)
|
|
474
474
|
else:
|
|
475
|
-
compsegs_table = np.
|
|
475
|
+
compsegs_table = np.vstack((compsegs_table, the_collection))
|
|
476
476
|
|
|
477
477
|
if compsegs_table is None:
|
|
478
478
|
raise ValueError(f"Collection does not contain the '{Keywords.COMPLETION_SEGMENTS}' keyword")
|