completor 0.1.2__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/__init__.py +3 -0
- completor/completion.py +1042 -0
- completor/config_jobs/run_completor +18 -0
- completor/constants.py +256 -0
- completor/create_output.py +462 -0
- completor/create_wells.py +314 -0
- completor/exceptions/__init__.py +4 -0
- completor/exceptions/clean_exceptions.py +10 -0
- completor/exceptions/exceptions.py +134 -0
- completor/hook_implementations/jobs.py +63 -0
- completor/input_validation.py +340 -0
- completor/launch_args_parser.py +41 -0
- completor/logger.py +138 -0
- completor/main.py +486 -0
- completor/parse.py +581 -0
- completor/prepare_outputs.py +1473 -0
- completor/pvt_model.py +14 -0
- completor/read_casefile.py +677 -0
- completor/read_schedule.py +160 -0
- completor/utils.py +185 -0
- completor/visualization.py +164 -0
- completor/visualize_well.py +217 -0
- completor-0.1.2.dist-info/LICENSE +165 -0
- completor-0.1.2.dist-info/METADATA +205 -0
- completor-0.1.2.dist-info/RECORD +27 -0
- completor-0.1.2.dist-info/WHEEL +4 -0
- completor-0.1.2.dist-info/entry_points.txt +6 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
"""Defines a class for generating output files."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import getpass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
import matplotlib # type: ignore
|
|
9
|
+
|
|
10
|
+
from completor import prepare_outputs as po
|
|
11
|
+
from completor.completion import WellSchedule
|
|
12
|
+
from completor.constants import Headers, Keywords
|
|
13
|
+
from completor.create_wells import CreateWells
|
|
14
|
+
from completor.logger import logger
|
|
15
|
+
from completor.pvt_model import CORRELATION_UDQ
|
|
16
|
+
from completor.read_casefile import ReadCasefile
|
|
17
|
+
from completor.visualize_well import visualize_well
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CreateOutput:
|
|
21
|
+
"""Create output files from completor.
|
|
22
|
+
|
|
23
|
+
There are two output files from completor:
|
|
24
|
+
1. Well schedule file (text file) for input to reservoir simulator.
|
|
25
|
+
2. Well diagram (pdf file), i.e. a well completion schematic.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
case: ReadCasefile object.
|
|
29
|
+
schedule: ReadSchedule object.
|
|
30
|
+
wells: CreateWells object.
|
|
31
|
+
well_name: Well name.
|
|
32
|
+
iwell: Well number used in creating WSEGAICV and WSEGDAR output.
|
|
33
|
+
version: Completor version information.
|
|
34
|
+
show_figure: Flag for pdf export of well completion schematic.
|
|
35
|
+
figure_no: Figure number.
|
|
36
|
+
write_welsegs: Flag to write WELSEGS.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
case: ReadCasefile,
|
|
42
|
+
schedule: WellSchedule,
|
|
43
|
+
wells: CreateWells,
|
|
44
|
+
well_name: str,
|
|
45
|
+
iwell: int,
|
|
46
|
+
completor_version: str,
|
|
47
|
+
show_figure: bool = False,
|
|
48
|
+
figure_name: matplotlib.backends.backend_pdf.PdfPages | None = None, # type: ignore
|
|
49
|
+
write_welsegs: bool = True,
|
|
50
|
+
paths: tuple[str, str] | None = None,
|
|
51
|
+
):
|
|
52
|
+
"""Initialize CreateOutput class.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
case: ReadCasefile object.
|
|
56
|
+
schedule: ReadSchedule object.
|
|
57
|
+
wells: CreateWells object.
|
|
58
|
+
completor_version: Completor version information.
|
|
59
|
+
figure_no: Must be set if show_figure.
|
|
60
|
+
show_figure: True if the user wants to create well diagram file.
|
|
61
|
+
"""
|
|
62
|
+
self.case = case
|
|
63
|
+
self.schedule = schedule
|
|
64
|
+
self.case_path: str | None
|
|
65
|
+
self.schedule_path: str | None
|
|
66
|
+
if paths:
|
|
67
|
+
self.case_path, self.schedule_path = paths
|
|
68
|
+
else:
|
|
69
|
+
self.case_path = None
|
|
70
|
+
self.schedule_path = None
|
|
71
|
+
self.wells = wells
|
|
72
|
+
self.well_name = well_name
|
|
73
|
+
self.iwell = iwell
|
|
74
|
+
self.version = completor_version
|
|
75
|
+
self.write_welsegs = write_welsegs
|
|
76
|
+
self.show_figure = show_figure
|
|
77
|
+
|
|
78
|
+
# different line connection
|
|
79
|
+
self.newline1 = "\n\n\n"
|
|
80
|
+
self.newline2 = "\n/" + self.newline1
|
|
81
|
+
self.newline3 = "/" + self.newline1
|
|
82
|
+
|
|
83
|
+
# create final print
|
|
84
|
+
self.header = self.make_completor_header()
|
|
85
|
+
|
|
86
|
+
# Prints the UDQ statement if a PVT file and
|
|
87
|
+
# PVT table are specified in the case file.
|
|
88
|
+
self.print_udq = False
|
|
89
|
+
self.udq_correlation = ""
|
|
90
|
+
self.udq_parameter: dict[str, str] = {}
|
|
91
|
+
if self.case.completion_table[Headers.DEVICE_TYPE].isin(["AICV"]).any():
|
|
92
|
+
self.print_udq = True
|
|
93
|
+
self.udq_correlation = CORRELATION_UDQ
|
|
94
|
+
|
|
95
|
+
# Start printing all wells
|
|
96
|
+
self.finalprint = self.header
|
|
97
|
+
# print udq equation if relevant
|
|
98
|
+
if self.print_udq:
|
|
99
|
+
self.finalprint += self.udq_correlation
|
|
100
|
+
|
|
101
|
+
self.df_reservoir = wells.df_reservoir_all[wells.df_reservoir_all[Headers.WELL] == self.well_name]
|
|
102
|
+
self.df_well = wells.df_well_all[wells.df_well_all[Headers.WELL] == self.well_name]
|
|
103
|
+
self.laterals = self.df_well[self.df_well[Headers.WELL] == self.well_name][Headers.LATERAL].unique()
|
|
104
|
+
|
|
105
|
+
# Start printing per well.
|
|
106
|
+
self.welsegs_header, _ = self.schedule.get_well_segments(self.well_name, branch=1)
|
|
107
|
+
self.check_welsegs1()
|
|
108
|
+
self.print_welsegs = f"{Keywords.WELSEGS}\n{po.dataframe_tostring(self.welsegs_header, True)}\n"
|
|
109
|
+
self.print_welsegsinit = self.print_welsegs
|
|
110
|
+
self.print_wseglink = f"{Keywords.WSEGLINK}\n"
|
|
111
|
+
self.print_wseglinkinit = self.print_wseglink
|
|
112
|
+
self.print_compsegs = f"{Keywords.COMPSEGS}\n'{self.well_name}' /\n"
|
|
113
|
+
self.print_compsegsinit = self.print_compsegs
|
|
114
|
+
self.print_compdat = f"{Keywords.COMPDAT}\n"
|
|
115
|
+
self.print_compdatinit = self.print_compdat
|
|
116
|
+
self.print_wsegvalv = f"{Keywords.WSEGVALV}\n"
|
|
117
|
+
self.print_wsegvalvinit = self.print_wsegvalv
|
|
118
|
+
self.print_wsegicv = f"{Keywords.WSEGVALV}\n"
|
|
119
|
+
self.print_wsegicvinit = self.print_wsegicv
|
|
120
|
+
self.print_wsegaicd = f"{Keywords.WSEGAICD}\n"
|
|
121
|
+
self.print_wsegaicdinit = self.print_wsegaicd
|
|
122
|
+
self.print_wsegsicd = f"{Keywords.WSEGSICD}\n"
|
|
123
|
+
self.print_wsegsicdinit = self.print_wsegsicd
|
|
124
|
+
self.print_wsegdar = f"""\
|
|
125
|
+
{'-' * 100}
|
|
126
|
+
-- This is how we model DAR technology using sets of ACTIONX keywords.
|
|
127
|
+
-- The segment dP curves changes according to the segment water-
|
|
128
|
+
-- and gas volume fractions at downhole condition.
|
|
129
|
+
-- The value of Cv is adjusted according to the segment length and the number of
|
|
130
|
+
-- devices per joint. The constriction area varies according to values of
|
|
131
|
+
-- volume fractions.
|
|
132
|
+
{"-" * 100}{self.newline1}"""
|
|
133
|
+
|
|
134
|
+
self.print_wsegdarinit = self.print_wsegdar
|
|
135
|
+
self.print_wsegaicv = f"""\
|
|
136
|
+
{"-" * 100}
|
|
137
|
+
-- This is how we model AICV technology using sets of ACTIONX keyword
|
|
138
|
+
-- the DP parameters change according to the segment water cut (at downhole condition )
|
|
139
|
+
-- and gas volume fraction (at downhole condition)
|
|
140
|
+
{"-" * 100}{self.newline1}"""
|
|
141
|
+
|
|
142
|
+
self.print_wsegaicvinit = self.print_wsegaicv
|
|
143
|
+
self.start_segment = 2
|
|
144
|
+
self.start_branch = 1
|
|
145
|
+
# pre-preparations
|
|
146
|
+
data = {} # just a container. need to to loop twice to make connect_lateral work
|
|
147
|
+
for lateral in self.laterals:
|
|
148
|
+
self.df_tubing, top = po.prepare_tubing_layer(
|
|
149
|
+
self.schedule,
|
|
150
|
+
self.well_name,
|
|
151
|
+
lateral,
|
|
152
|
+
self.df_well,
|
|
153
|
+
self.start_segment,
|
|
154
|
+
self.start_branch,
|
|
155
|
+
self.case.completion_table,
|
|
156
|
+
)
|
|
157
|
+
self.df_device = po.prepare_device_layer(self.well_name, lateral, self.df_well, self.df_tubing)
|
|
158
|
+
self.df_annulus, self.df_wseglink = po.prepare_annulus_layer(
|
|
159
|
+
self.well_name, lateral, self.df_well, self.df_device
|
|
160
|
+
)
|
|
161
|
+
self.update_segmentbranch()
|
|
162
|
+
self.check_segments(lateral)
|
|
163
|
+
data[lateral] = (self.df_tubing, self.df_device, self.df_annulus, self.df_wseglink, top)
|
|
164
|
+
# attach lateral to their proper segments (in overburden, potentially)
|
|
165
|
+
for lateral in data:
|
|
166
|
+
po.connect_lateral(self.well_name, lateral, data, self.case)
|
|
167
|
+
# main preparations
|
|
168
|
+
for lateral in self.laterals:
|
|
169
|
+
self.df_tubing, self.df_device, self.df_annulus, self.df_wseglink = data[lateral][:4]
|
|
170
|
+
|
|
171
|
+
self.branch_revision(lateral)
|
|
172
|
+
|
|
173
|
+
completion_table_well = case.completion_table[case.completion_table[Headers.WELL] == self.well_name]
|
|
174
|
+
completion_table_lateral = completion_table_well[completion_table_well[Headers.BRANCH] == lateral]
|
|
175
|
+
self.df_compsegs = po.prepare_compsegs(
|
|
176
|
+
self.well_name,
|
|
177
|
+
lateral,
|
|
178
|
+
self.df_reservoir,
|
|
179
|
+
self.df_device,
|
|
180
|
+
self.df_annulus,
|
|
181
|
+
completion_table_lateral,
|
|
182
|
+
self.case.segment_length,
|
|
183
|
+
)
|
|
184
|
+
self.df_compdat = po.prepare_compdat(self.well_name, lateral, self.df_reservoir, completion_table_lateral)
|
|
185
|
+
self.df_wsegvalv = po.prepare_wsegvalv(self.well_name, lateral, self.df_well, self.df_device)
|
|
186
|
+
self.df_wsegsicd = po.prepare_wsegsicd(self.well_name, lateral, self.df_well, self.df_device)
|
|
187
|
+
self.df_wsegaicd = po.prepare_wsegaicd(self.well_name, lateral, self.df_well, self.df_device)
|
|
188
|
+
self.df_wsegdar = po.prepare_wsegdar(self.well_name, lateral, self.df_well, self.df_device)
|
|
189
|
+
self.df_wsegaicv = po.prepare_wsegaicv(self.well_name, lateral, self.df_well, self.df_device)
|
|
190
|
+
self.df_wsegicv = po.prepare_wsegicv(
|
|
191
|
+
self.well_name,
|
|
192
|
+
lateral,
|
|
193
|
+
self.df_well,
|
|
194
|
+
self.df_device,
|
|
195
|
+
self.df_tubing,
|
|
196
|
+
self.case.completion_icv_tubing,
|
|
197
|
+
self.case.wsegicv_table,
|
|
198
|
+
)
|
|
199
|
+
self.make_compdat(lateral)
|
|
200
|
+
self.make_welsegs(lateral)
|
|
201
|
+
self.make_wseglink(lateral)
|
|
202
|
+
self.make_compsegs(lateral)
|
|
203
|
+
self.make_wsegvalv(lateral)
|
|
204
|
+
self.make_wsegsicd(lateral)
|
|
205
|
+
self.make_wsegaicd(lateral)
|
|
206
|
+
self.make_wsegicv(lateral)
|
|
207
|
+
self.make_wsegdar()
|
|
208
|
+
self.make_wsegaicv()
|
|
209
|
+
|
|
210
|
+
if show_figure and figure_name is not None:
|
|
211
|
+
logger.info(f"Creating figure for lateral {lateral}.")
|
|
212
|
+
figure_name.savefig(
|
|
213
|
+
visualize_well(self.well_name, self.df_well, self.df_reservoir, self.case.segment_length),
|
|
214
|
+
orientation="landscape",
|
|
215
|
+
)
|
|
216
|
+
logger.info("creating schematics: %s.pdf", figure_name)
|
|
217
|
+
elif show_figure and figure_name is None:
|
|
218
|
+
raise ValueError("Cannot show figure without filename supplied.")
|
|
219
|
+
self.fix_printing()
|
|
220
|
+
self.print_per_well()
|
|
221
|
+
|
|
222
|
+
def make_completor_header(self) -> str:
|
|
223
|
+
"""Print header note."""
|
|
224
|
+
header = f"{'-' * 100}\n"
|
|
225
|
+
header += f"-- Output from completor {self.version}\n"
|
|
226
|
+
try:
|
|
227
|
+
header += f"-- Case file : {self.case_path}\n"
|
|
228
|
+
except AttributeError:
|
|
229
|
+
header += "-- Case file : No path found \n"
|
|
230
|
+
logger.warning("Could not resolve case-file path to output file")
|
|
231
|
+
header += f"-- Schedule file : {self.schedule_path}\n"
|
|
232
|
+
|
|
233
|
+
header += f"""\
|
|
234
|
+
-- Created by : {(getpass.getuser()).upper()}
|
|
235
|
+
-- Created at : {datetime.now().strftime('%Y %B %d %H:%M')}
|
|
236
|
+
{'-' * 100}{self.newline1}
|
|
237
|
+
"""
|
|
238
|
+
return header
|
|
239
|
+
|
|
240
|
+
def check_welsegs1(self) -> None:
|
|
241
|
+
"""Check whether the measured depth of the first segment is deeper than the first cells start measured depth.
|
|
242
|
+
|
|
243
|
+
In this case, adjust segments measured depth to be 1 meter shallower.
|
|
244
|
+
"""
|
|
245
|
+
start_md = self.df_reservoir[Headers.START_MEASURED_DEPTH].iloc[0]
|
|
246
|
+
if self.welsegs_header[Headers.SEGMENTMD].iloc[0] > start_md:
|
|
247
|
+
self.welsegs_header[Headers.SEGMENTMD] = start_md - 1.0
|
|
248
|
+
|
|
249
|
+
def check_segments(self, lateral: int) -> None:
|
|
250
|
+
"""Check whether there is annular flow in the well.
|
|
251
|
+
|
|
252
|
+
Also check if there are any connections from the reservoir to the tubing in a well.
|
|
253
|
+
"""
|
|
254
|
+
if self.df_annulus.shape[0] == 0:
|
|
255
|
+
logger.info("No annular flow in Well : %s Lateral : %d", self.well_name, lateral)
|
|
256
|
+
if self.df_device.shape[0] == 0:
|
|
257
|
+
logger.warning("No connection from reservoir to tubing in Well : %s Lateral : %d", self.well_name, lateral)
|
|
258
|
+
|
|
259
|
+
def update_segmentbranch(self) -> None:
|
|
260
|
+
"""Update the numbering of the tubing segment and branch."""
|
|
261
|
+
|
|
262
|
+
if self.df_annulus.shape[0] == 0 and self.df_device.shape[0] > 0:
|
|
263
|
+
self.start_segment = max(self.df_device[Headers.SEG].to_numpy()) + 1
|
|
264
|
+
self.start_branch = max(self.df_device[Headers.BRANCH].to_numpy()) + 1
|
|
265
|
+
elif self.df_annulus.shape[0] > 0:
|
|
266
|
+
self.start_segment = max(self.df_annulus[Headers.SEG].to_numpy()) + 1
|
|
267
|
+
self.start_branch = max(self.df_annulus[Headers.BRANCH].to_numpy()) + 1
|
|
268
|
+
|
|
269
|
+
def make_compdat(self, lateral: int) -> None:
|
|
270
|
+
"""Print completion data to file."""
|
|
271
|
+
nchar = po.get_number_of_characters(self.df_compdat)
|
|
272
|
+
if self.df_compdat.shape[0] > 0:
|
|
273
|
+
self.print_compdat += (
|
|
274
|
+
po.get_header(self.well_name, Keywords.COMPDAT, lateral, "", nchar)
|
|
275
|
+
+ po.dataframe_tostring(self.df_compdat, True)
|
|
276
|
+
+ "\n"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
def make_welsegs(self, lateral: int) -> None:
|
|
280
|
+
"""Print well segments to file."""
|
|
281
|
+
nchar = po.get_number_of_characters(self.df_tubing)
|
|
282
|
+
if self.df_device.shape[0] > 0:
|
|
283
|
+
self.print_welsegs += (
|
|
284
|
+
po.get_header(self.well_name, Keywords.WELSEGS, lateral, "Tubing", nchar)
|
|
285
|
+
+ po.dataframe_tostring(self.df_tubing, True)
|
|
286
|
+
+ "\n"
|
|
287
|
+
)
|
|
288
|
+
if self.df_device.shape[0] > 0:
|
|
289
|
+
nchar = po.get_number_of_characters(self.df_tubing)
|
|
290
|
+
self.print_welsegs += (
|
|
291
|
+
po.get_header(self.well_name, Keywords.WELSEGS, lateral, "Device", nchar)
|
|
292
|
+
+ po.dataframe_tostring(self.df_device, True)
|
|
293
|
+
+ "\n"
|
|
294
|
+
)
|
|
295
|
+
if self.df_annulus.shape[0] > 0:
|
|
296
|
+
nchar = po.get_number_of_characters(self.df_tubing)
|
|
297
|
+
self.print_welsegs += (
|
|
298
|
+
po.get_header(self.well_name, Keywords.WELSEGS, lateral, "Annulus", nchar)
|
|
299
|
+
+ po.dataframe_tostring(self.df_annulus, True)
|
|
300
|
+
+ "\n"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def make_wseglink(self, lateral: int) -> None:
|
|
304
|
+
"""Print WSEGLINK to file."""
|
|
305
|
+
if self.df_wseglink.shape[0] > 0:
|
|
306
|
+
nchar = po.get_number_of_characters(self.df_wseglink)
|
|
307
|
+
self.print_wseglink += (
|
|
308
|
+
po.get_header(self.well_name, Keywords.WSEGLINK, lateral, "", nchar)
|
|
309
|
+
+ po.dataframe_tostring(self.df_wseglink, True)
|
|
310
|
+
+ "\n"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def make_compsegs(self, lateral: int) -> None:
|
|
314
|
+
"""Print completion segments to file."""
|
|
315
|
+
nchar = po.get_number_of_characters(self.df_compsegs)
|
|
316
|
+
if self.df_compsegs.shape[0] > 0:
|
|
317
|
+
self.print_compsegs += (
|
|
318
|
+
po.get_header(self.well_name, Keywords.COMPSEGS, lateral, "", nchar)
|
|
319
|
+
+ po.dataframe_tostring(self.df_compsegs, True)
|
|
320
|
+
+ "\n"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
def make_wsegaicd(self, lateral: int) -> None:
|
|
324
|
+
"""Print WSEGAICD to file."""
|
|
325
|
+
if self.df_wsegaicd.shape[0] > 0:
|
|
326
|
+
nchar = po.get_number_of_characters(self.df_wsegaicd)
|
|
327
|
+
self.print_wsegaicd += (
|
|
328
|
+
po.get_header(self.well_name, Keywords.WSEGAICD, lateral, "", nchar)
|
|
329
|
+
+ po.dataframe_tostring(self.df_wsegaicd, True)
|
|
330
|
+
+ "\n"
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def make_wsegsicd(self, lateral: int) -> None:
|
|
334
|
+
"""Print WSEGSICD to file."""
|
|
335
|
+
if self.df_wsegsicd.shape[0] > 0:
|
|
336
|
+
nchar = po.get_number_of_characters(self.df_wsegsicd)
|
|
337
|
+
self.print_wsegsicd += (
|
|
338
|
+
po.get_header(self.well_name, Keywords.WSEGSICD, lateral, "", nchar)
|
|
339
|
+
+ po.dataframe_tostring(self.df_wsegsicd, True)
|
|
340
|
+
+ "\n"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def make_wsegvalv(self, lateral: int) -> None:
|
|
344
|
+
"""Print WSEGVALV to file."""
|
|
345
|
+
if self.df_wsegvalv.shape[0] > 0:
|
|
346
|
+
nchar = po.get_number_of_characters(self.df_wsegvalv)
|
|
347
|
+
self.print_wsegvalv += (
|
|
348
|
+
po.get_header(self.well_name, Keywords.WSEGVALV, lateral, "", nchar)
|
|
349
|
+
+ po.dataframe_tostring(self.df_wsegvalv, True)
|
|
350
|
+
+ "\n"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def make_wsegicv(self, lateral: int) -> None:
|
|
354
|
+
"""Print WSEGICV to file."""
|
|
355
|
+
if self.df_wsegicv.shape[0] > 0:
|
|
356
|
+
nchar = po.get_number_of_characters(self.df_wsegicv)
|
|
357
|
+
self.print_wsegicv += (
|
|
358
|
+
po.get_header(self.well_name, Keywords.WSEGVALV, lateral, "", nchar)
|
|
359
|
+
+ po.dataframe_tostring(self.df_wsegicv, True)
|
|
360
|
+
+ "\n"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
def make_wsegdar(self) -> None:
|
|
364
|
+
"""Print WSEGDAR to file."""
|
|
365
|
+
if self.df_wsegdar.shape[0] > 0:
|
|
366
|
+
self.print_wsegdar += po.print_wsegdar(self.df_wsegdar, self.iwell + 1) + "\n"
|
|
367
|
+
|
|
368
|
+
def make_wsegaicv(self) -> None:
|
|
369
|
+
"""Print WSEGAICV to file."""
|
|
370
|
+
if self.df_wsegaicv.shape[0] > 0:
|
|
371
|
+
self.print_wsegaicv += po.print_wsegaicv(self.df_wsegaicv, self.iwell + 1) + "\n"
|
|
372
|
+
|
|
373
|
+
def fix_printing(self) -> None:
|
|
374
|
+
"""Avoid printing non-existing keywords."""
|
|
375
|
+
# if no compdat then dont print it
|
|
376
|
+
if self.print_compdat == self.print_compdatinit:
|
|
377
|
+
self.print_compdat = ""
|
|
378
|
+
else:
|
|
379
|
+
self.print_compdat += self.newline3
|
|
380
|
+
# if no welsegs then dont print it
|
|
381
|
+
if self.print_welsegs == self.print_welsegsinit:
|
|
382
|
+
self.print_welsegs = ""
|
|
383
|
+
else:
|
|
384
|
+
self.print_welsegs += self.newline3
|
|
385
|
+
# if no compsegs then dont print it
|
|
386
|
+
if self.print_compsegs == self.print_compsegsinit:
|
|
387
|
+
self.print_compsegs = ""
|
|
388
|
+
else:
|
|
389
|
+
self.print_compsegs += self.newline3
|
|
390
|
+
# if no weseglink then dont print it
|
|
391
|
+
if self.print_wseglink == Keywords.WSEGLINK + "\n":
|
|
392
|
+
self.print_wseglink = ""
|
|
393
|
+
else:
|
|
394
|
+
self.print_wseglink += self.newline3
|
|
395
|
+
# if no VALVE then dont print
|
|
396
|
+
if self.print_wsegvalv == Keywords.WSEGVALV + "\n":
|
|
397
|
+
self.print_wsegvalv = ""
|
|
398
|
+
else:
|
|
399
|
+
self.print_wsegvalv += self.newline3
|
|
400
|
+
# if no ICD then dont print
|
|
401
|
+
if self.print_wsegsicd == Keywords.WSEGSICD + "\n":
|
|
402
|
+
self.print_wsegsicd = ""
|
|
403
|
+
else:
|
|
404
|
+
self.print_wsegsicd += self.newline3
|
|
405
|
+
# if no AICD then dont print
|
|
406
|
+
if self.print_wsegaicd == Keywords.WSEGAICD + "\n":
|
|
407
|
+
self.print_wsegaicd = ""
|
|
408
|
+
else:
|
|
409
|
+
self.print_wsegaicd += self.newline3
|
|
410
|
+
# if no DAR then dont print
|
|
411
|
+
if self.print_wsegdar == self.print_wsegdarinit:
|
|
412
|
+
self.print_wsegdar = ""
|
|
413
|
+
else:
|
|
414
|
+
self.print_wsegdar += self.newline1
|
|
415
|
+
# if no DAR then dont print
|
|
416
|
+
if self.print_wsegaicv == self.print_wsegaicvinit:
|
|
417
|
+
self.print_wsegaicv = ""
|
|
418
|
+
else:
|
|
419
|
+
self.print_wsegaicv += self.newline1
|
|
420
|
+
# if no ICV then dont print
|
|
421
|
+
if self.print_wsegicv == Keywords.WSEGVALV + "\n":
|
|
422
|
+
self.print_wsegicv = ""
|
|
423
|
+
else:
|
|
424
|
+
self.print_wsegicv += self.newline3
|
|
425
|
+
|
|
426
|
+
def print_per_well(self) -> None:
|
|
427
|
+
"""Collect final printing for all wells."""
|
|
428
|
+
# here starts active wells
|
|
429
|
+
finalprint = self.finalprint + self.print_compdat
|
|
430
|
+
if self.write_welsegs:
|
|
431
|
+
finalprint += self.print_welsegs
|
|
432
|
+
finalprint += self.print_wseglink
|
|
433
|
+
finalprint += self.print_compsegs
|
|
434
|
+
# print udq parameter if relevant
|
|
435
|
+
if self.well_name in self.udq_parameter and self.print_udq:
|
|
436
|
+
finalprint += self.udq_parameter[self.well_name]
|
|
437
|
+
|
|
438
|
+
finalprint += (
|
|
439
|
+
self.print_wsegvalv
|
|
440
|
+
+ self.print_wsegsicd
|
|
441
|
+
+ self.print_wsegaicd
|
|
442
|
+
+ self.print_wsegdar
|
|
443
|
+
+ self.print_wsegaicv
|
|
444
|
+
+ self.print_wsegicv
|
|
445
|
+
)
|
|
446
|
+
self.finalprint = finalprint
|
|
447
|
+
|
|
448
|
+
def branch_revision(self, lateral: int) -> None:
|
|
449
|
+
"""Revises the order of branch numbers to be in agreement with common practice.
|
|
450
|
+
|
|
451
|
+
This means that tubing layers will get branch numbers from 1 to the number of laterals.
|
|
452
|
+
Device and lateral branch numbers are changed accordingly if they exist.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
lateral: The lateral number being worked on.
|
|
456
|
+
"""
|
|
457
|
+
correction = max(self.laterals) - lateral
|
|
458
|
+
self.df_tubing[Headers.BRANCH] = lateral
|
|
459
|
+
if self.df_device.shape[0] > 0:
|
|
460
|
+
self.df_device[Headers.BRANCH] += correction
|
|
461
|
+
if self.df_annulus.shape[0] > 0:
|
|
462
|
+
self.df_annulus[Headers.BRANCH] += correction
|