schedule-reader 0.7.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.
- schedule_reader/__init__.py +81 -0
- schedule_reader/compdat.py +153 -0
- schedule_reader/counter.py +66 -0
- schedule_reader/data_reader.py +796 -0
- schedule_reader/dates.py +37 -0
- schedule_reader/extract_keyword.py +39 -0
- schedule_reader/helpers.py +44 -0
- schedule_reader/property_keywords.py +81 -0
- schedule_reader/renamer.py +17 -0
- schedule_reader/schedule_keywords.py +75 -0
- schedule_reader/wcon.py +132 -0
- schedule_reader/welspec.py +119 -0
- schedule_reader/wlist.py +37 -0
- schedule_reader-0.7.0.dist-info/METADATA +59 -0
- schedule_reader-0.7.0.dist-info/RECORD +18 -0
- schedule_reader-0.7.0.dist-info/WHEEL +5 -0
- schedule_reader-0.7.0.dist-info/licenses/LICENSE +21 -0
- schedule_reader-0.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A function to read the .DATA file, look for schedule section and return a dictionary of keywords and its records on order of appearance.
|
|
3
|
+
|
|
4
|
+
developed by: Martin Araya
|
|
5
|
+
email: martinaraya@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .counter import Counter
|
|
9
|
+
from .helpers import remove_inline_comment
|
|
10
|
+
from os.path import exists
|
|
11
|
+
|
|
12
|
+
__version__ = '0.7.0'
|
|
13
|
+
__release__ = 20260228
|
|
14
|
+
|
|
15
|
+
def read_data(filepath: str, *, encoding: str='cp1252', verbose: bool=False,
|
|
16
|
+
start_date: str=None, paths: dict={}, folder: str=None, counter: Counter=None, main=True,
|
|
17
|
+
concatenate_lines=True) -> dict:
|
|
18
|
+
"""
|
|
19
|
+
reads the .DATA file, look for schedule section and returns a dictionary of keywords and its records on order of appearance.
|
|
20
|
+
|
|
21
|
+
Params:
|
|
22
|
+
filepath: str
|
|
23
|
+
the path to the .DATA or schedule include file
|
|
24
|
+
paths: dict {str: str}, optional
|
|
25
|
+
dictionary of the paths described by PATHS keyword. If the .DATA is provided this data is automatically extracted.
|
|
26
|
+
start_date: str, optional
|
|
27
|
+
the start date of the simulation
|
|
28
|
+
if None, it will be read from keyword START or set by default to 01 JAN 1900
|
|
29
|
+
folder: str, optional
|
|
30
|
+
tha absolute path to the folder where the .DATA file is located. If the .DATA is provided this data is automatically extracted.
|
|
31
|
+
encoding: str
|
|
32
|
+
The encoding format of input text files. For files with especial characters, it might be convenient to use 'cp1252' or 'latin1'.
|
|
33
|
+
verbose: bool
|
|
34
|
+
set it False to skip printing messages.
|
|
35
|
+
counter: an instance of the Counter class, should not be provided by the user!
|
|
36
|
+
internal counter provided by the same function recursive calls when reading include files.
|
|
37
|
+
|
|
38
|
+
Return:
|
|
39
|
+
dict of dicts of keywords and their records
|
|
40
|
+
{i: {keyword: [records]}}
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def _keyword():
|
|
44
|
+
return datafile[line].split()[0].upper()
|
|
45
|
+
|
|
46
|
+
def _keyword_end():
|
|
47
|
+
if line >= len(datafile):
|
|
48
|
+
return True
|
|
49
|
+
return datafile[line].strip().startswith('/')
|
|
50
|
+
|
|
51
|
+
def _comment_line():
|
|
52
|
+
return datafile[line].strip().startswith('--')
|
|
53
|
+
|
|
54
|
+
def _empty_line():
|
|
55
|
+
return len(datafile[line].strip()) == 0
|
|
56
|
+
|
|
57
|
+
def _line_data():
|
|
58
|
+
return _this_line().rstrip('/ ')
|
|
59
|
+
|
|
60
|
+
def _this_line():
|
|
61
|
+
return remove_inline_comment(datafile[line])
|
|
62
|
+
|
|
63
|
+
def _last_date():
|
|
64
|
+
extracted_dates = [k_ for k_ in extracted
|
|
65
|
+
if list(extracted[k_].keys())[0] == 'DATES' and extracted[k_]['DATES'] is not False]
|
|
66
|
+
if len(extracted_dates) == 0:
|
|
67
|
+
return start_date
|
|
68
|
+
else:
|
|
69
|
+
return extracted[max(extracted_dates)]['DATES']
|
|
70
|
+
|
|
71
|
+
skip0_keywords = ('ECHO', 'NOECHO', 'SKIPREST', 'SKIP', 'SKIP100', 'SKIP300', 'ENDSKIP', 'RPTONLY', 'RPTONLYO', 'SAVENOW')
|
|
72
|
+
skip1_keywords = ('NEXT', 'NEXTSTEP', 'LIFTOPT', 'GCONTOL', 'GUIDERAT', 'WLIMTOL', 'RPTSCHED', 'FILEUNIT', 'CVCRIT',
|
|
73
|
+
'TITLE')
|
|
74
|
+
skip3_keywords = ('TUNING')
|
|
75
|
+
|
|
76
|
+
# check file exists
|
|
77
|
+
if not exists(filepath):
|
|
78
|
+
newfilepath = f"{folder}{'' if folder.endswith('/') else '/'}{filepath.strip('"').strip("'").strip('"')}"
|
|
79
|
+
if exists(newfilepath):
|
|
80
|
+
filepath = newfilepath
|
|
81
|
+
else:
|
|
82
|
+
print(f"{folder}{'' if folder.endswith('/') else '/'}{filepath}")
|
|
83
|
+
raise ValueError(f"The file doesn't exists: {filepath}")
|
|
84
|
+
filepath = filepath.replace('\\', '/')
|
|
85
|
+
if folder is None:
|
|
86
|
+
folder = '/'.join(filepath.split('/')[:-1]) + '/'
|
|
87
|
+
if verbose:
|
|
88
|
+
print(f"parent folder: {folder}")
|
|
89
|
+
|
|
90
|
+
# clean verbose parameter
|
|
91
|
+
if verbose is None:
|
|
92
|
+
verbose = True
|
|
93
|
+
else:
|
|
94
|
+
verbose = bool(verbose)
|
|
95
|
+
|
|
96
|
+
# read and clean the main file
|
|
97
|
+
if verbose:
|
|
98
|
+
print('Reading the file:', filepath)
|
|
99
|
+
with open(filepath, 'r', encoding=encoding) as f:
|
|
100
|
+
datafile = f.readlines()
|
|
101
|
+
datafile = [remove_inline_comment(line) for line in datafile]
|
|
102
|
+
|
|
103
|
+
# initialize the counter
|
|
104
|
+
if counter is None:
|
|
105
|
+
counter = Counter()
|
|
106
|
+
if verbose:
|
|
107
|
+
keywords_before = counter.curr()
|
|
108
|
+
print(f"{counter.curr()} keywords found until now")
|
|
109
|
+
|
|
110
|
+
# if the file is the .DATA, look for START and PATHS keywords
|
|
111
|
+
if filepath.upper().endswith('.DATA'):
|
|
112
|
+
|
|
113
|
+
# looks for START
|
|
114
|
+
if main and start_date is None and 'START' in ''.join(datafile):
|
|
115
|
+
start_date = datafile[[remove_inline_comment(line) for line in datafile].index('START') + 1].replace('/', '').strip()
|
|
116
|
+
if verbose:
|
|
117
|
+
print(f"Found START date: {start_date}")
|
|
118
|
+
|
|
119
|
+
# looks for PATHS and update dictionary if PATHS found
|
|
120
|
+
if main and len(paths) == 0 and 'PATHS' in datafile:
|
|
121
|
+
line = datafile.index('PATHS') + 1
|
|
122
|
+
while not _keyword_end():
|
|
123
|
+
paths.update({datafile[line].strip().strip('/').split()[0].strip("'"):
|
|
124
|
+
datafile[line].strip().strip('/').split()[1].strip("'")})
|
|
125
|
+
line += 1
|
|
126
|
+
if verbose:
|
|
127
|
+
print('Found PATHS keyword:\n', "\n ".join([k + ":" + v for k, v in paths.items()]))
|
|
128
|
+
|
|
129
|
+
# jump to SCHEDULE keyword line
|
|
130
|
+
schedule_line = None
|
|
131
|
+
if main and 'SCHEDULE' in datafile:
|
|
132
|
+
schedule_line = datafile.index('SCHEDULE')
|
|
133
|
+
else:
|
|
134
|
+
schedule_line = [line.split()[0].upper().startswith('SCHEDULE') if len(line) > 0 else False for line in
|
|
135
|
+
datafile]
|
|
136
|
+
schedule_line = schedule_line.index(True) if True in schedule_line else None
|
|
137
|
+
if schedule_line is None:
|
|
138
|
+
schedule_line = 0 # read the entire file
|
|
139
|
+
# raise ValueError("'SCHEDULE' keyword not found in this DATA file.")
|
|
140
|
+
if verbose:
|
|
141
|
+
if main and schedule_line == 0:
|
|
142
|
+
print(
|
|
143
|
+
f"SCHEDULE keyword not found in this DATA, will proceed to read everything line by line... it could take some time...")
|
|
144
|
+
else:
|
|
145
|
+
print(f"found SCHEDULE keyword in line {schedule_line}")
|
|
146
|
+
else:
|
|
147
|
+
schedule_line = 0
|
|
148
|
+
|
|
149
|
+
# initialize the extracted dictionary, where every read keyword will be stored
|
|
150
|
+
if not main:
|
|
151
|
+
extracted = {}
|
|
152
|
+
elif start_date is None: # is main file
|
|
153
|
+
# empty dictionary, START date by default and can be updated at the end of the loop
|
|
154
|
+
extracted = {counter(): {'DATES': '01 JAN 1900'}}
|
|
155
|
+
start_date = '01 JAN 1900'
|
|
156
|
+
if verbose:
|
|
157
|
+
print(f"START keyword not found, will start dates from default value '01 JAN 1900'")
|
|
158
|
+
else: # is main file and start_date is not None
|
|
159
|
+
# START date is the first keyword in the dictionary
|
|
160
|
+
extracted = {counter(): {'DATES': start_date}}
|
|
161
|
+
|
|
162
|
+
# start reading the file, from the schedule_line if found
|
|
163
|
+
line = schedule_line
|
|
164
|
+
skip_ = False
|
|
165
|
+
while line < len(datafile): # read every line until the end
|
|
166
|
+
|
|
167
|
+
# skip lines as indicated by SKIP keywords
|
|
168
|
+
if skip_ and not datafile[line].upper().startswith('ENDSKIP'):
|
|
169
|
+
line += 1
|
|
170
|
+
elif skip_ and datafile[line].upper().startswith('ENDSKIP'):
|
|
171
|
+
line += 1
|
|
172
|
+
skip_ = False
|
|
173
|
+
|
|
174
|
+
# skip empty and comment lines
|
|
175
|
+
if _empty_line() or _comment_line():
|
|
176
|
+
line += 1
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# if a DATES is found
|
|
180
|
+
elif datafile[line].upper().startswith('DATES'):
|
|
181
|
+
line += 1
|
|
182
|
+
if verbose:
|
|
183
|
+
print("found DATES keyword")
|
|
184
|
+
_counter0 = counter.curr() + 1
|
|
185
|
+
|
|
186
|
+
# read all the dates within DATES until the closing /
|
|
187
|
+
while not _keyword_end():
|
|
188
|
+
# skip empty and commented lines
|
|
189
|
+
if _empty_line() or _comment_line():
|
|
190
|
+
line += 1
|
|
191
|
+
continue
|
|
192
|
+
|
|
193
|
+
extracted[counter()] = {'DATES': str(_line_data())}
|
|
194
|
+
line += 1
|
|
195
|
+
line += 1 # keyword end line
|
|
196
|
+
if verbose:
|
|
197
|
+
print(f" {' until '.join(set([extracted[_counter0]['DATES'], extracted[counter.curr()]['DATES']]))}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# if COMPDAT is found
|
|
201
|
+
elif datafile[line].upper().startswith('COMPDAT'):
|
|
202
|
+
line += 1
|
|
203
|
+
key_columns = 14
|
|
204
|
+
if verbose:
|
|
205
|
+
print("found COMPDAT keyword")
|
|
206
|
+
_counter0 = counter.curr() + 1
|
|
207
|
+
|
|
208
|
+
# read all the COMPDAT lines until the closing /
|
|
209
|
+
while not _keyword_end():
|
|
210
|
+
# skip empty or commented lines
|
|
211
|
+
if _empty_line() or _comment_line():
|
|
212
|
+
line += 1
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
216
|
+
raise ValueError(
|
|
217
|
+
f"Error format in keyword COMPDAT in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
218
|
+
|
|
219
|
+
# append lines until line slash
|
|
220
|
+
compdat_line = _line_data().split()
|
|
221
|
+
while '/' not in _this_line():
|
|
222
|
+
line += 1
|
|
223
|
+
compdat_line += _line_data().split()
|
|
224
|
+
line += 1
|
|
225
|
+
|
|
226
|
+
# complete default values at the end if requered
|
|
227
|
+
if len(compdat_line) < key_columns:
|
|
228
|
+
compdat_line_expanded = []
|
|
229
|
+
for each in compdat_line:
|
|
230
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
231
|
+
compdat_line_expanded = compdat_line_expanded + (['1*'] * int(each[:-1]))
|
|
232
|
+
else:
|
|
233
|
+
compdat_line_expanded.append(each)
|
|
234
|
+
compdat_line_expanded = compdat_line_expanded + (
|
|
235
|
+
['1*'] * (key_columns - len(compdat_line_expanded)))
|
|
236
|
+
compdat_line = compdat_line_expanded
|
|
237
|
+
extracted[counter()] = {'COMPDAT': compdat_line}
|
|
238
|
+
|
|
239
|
+
line += 1 # keyword end line
|
|
240
|
+
if verbose:
|
|
241
|
+
print(
|
|
242
|
+
f" for wells: {', '.join(set([extracted[i_]['COMPDAT'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# if COMPDATL or COMPDATM is found
|
|
246
|
+
elif datafile[line].upper().startswith('COMPDATL') or datafile[line].upper().startswith('COMPDATM'):
|
|
247
|
+
line += 1
|
|
248
|
+
key_columns = 15
|
|
249
|
+
if verbose:
|
|
250
|
+
print("found COMPDATL keyword")
|
|
251
|
+
_counter0 = counter.curr() + 1
|
|
252
|
+
|
|
253
|
+
# read all the COMPDATL lines until the closing /
|
|
254
|
+
while not _keyword_end():
|
|
255
|
+
# skip empty or commented lines
|
|
256
|
+
if _empty_line() or _comment_line():
|
|
257
|
+
line += 1
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
261
|
+
raise ValueError(
|
|
262
|
+
f"Error format in keyword COMPDATL in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
263
|
+
|
|
264
|
+
# append lines until line slash
|
|
265
|
+
compdatl_line = _line_data().split()
|
|
266
|
+
while '/' not in _this_line():
|
|
267
|
+
line += 1
|
|
268
|
+
compdatl_line += _line_data().split()
|
|
269
|
+
line += 1
|
|
270
|
+
|
|
271
|
+
# complete default values at the end if requered
|
|
272
|
+
if len(compdatl_line) < key_columns:
|
|
273
|
+
compdatl_line_expanded = []
|
|
274
|
+
for each in compdatl_line:
|
|
275
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
276
|
+
compdatl_line_expanded = compdatl_line_expanded + (['1*'] * int(each[:-1]))
|
|
277
|
+
else:
|
|
278
|
+
compdatl_line_expanded.append(each)
|
|
279
|
+
compdatl_line_expanded = compdatl_line_expanded + (
|
|
280
|
+
['1*'] * (key_columns - len(compdatl_line_expanded)))
|
|
281
|
+
compdatl_line = compdatl_line_expanded
|
|
282
|
+
extracted[counter()] = {'COMPDATL': compdatl_line}
|
|
283
|
+
|
|
284
|
+
line += 1 # keyword end line
|
|
285
|
+
if verbose:
|
|
286
|
+
print(
|
|
287
|
+
f" for wells: {', '.join(set([extracted[i_]['COMPDATL'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
# if WELSPECS is found
|
|
291
|
+
elif datafile[line].upper().startswith('WELSPECS'):
|
|
292
|
+
line += 1
|
|
293
|
+
key_columns = 17
|
|
294
|
+
if verbose:
|
|
295
|
+
print("found WELSPECS keyword")
|
|
296
|
+
_counter0 = counter.curr() + 1
|
|
297
|
+
|
|
298
|
+
while not _keyword_end():
|
|
299
|
+
|
|
300
|
+
# skip empty or commented lines
|
|
301
|
+
if _empty_line() or _comment_line():
|
|
302
|
+
line += 1
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
306
|
+
raise ValueError(
|
|
307
|
+
f"Error format in keyword WELSPECS in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
308
|
+
|
|
309
|
+
# append lines until line slash
|
|
310
|
+
welspecs_line = _line_data().split()
|
|
311
|
+
while '/' not in _this_line():
|
|
312
|
+
line += 1
|
|
313
|
+
welspecs_line += _line_data().split()
|
|
314
|
+
line += 1
|
|
315
|
+
|
|
316
|
+
# complete default values at the end if requered
|
|
317
|
+
if len(welspecs_line) < key_columns:
|
|
318
|
+
welspecs_line_expanded = []
|
|
319
|
+
for each in welspecs_line:
|
|
320
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
321
|
+
welspecs_line_expanded = welspecs_line_expanded + (['1*'] * int(each[:-1]))
|
|
322
|
+
else:
|
|
323
|
+
welspecs_line_expanded.append(each)
|
|
324
|
+
welspecs_line_expanded = welspecs_line_expanded + (
|
|
325
|
+
['1*'] * (key_columns - len(welspecs_line_expanded)))
|
|
326
|
+
welspecs_line = welspecs_line_expanded
|
|
327
|
+
extracted[counter()] = {'WELSPECS': welspecs_line}
|
|
328
|
+
|
|
329
|
+
line += 1 # keyword end line
|
|
330
|
+
if verbose:
|
|
331
|
+
print(
|
|
332
|
+
f" for wells: {', '.join(set([extracted[i_]['WELSPECS'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
# if WELSPECL is found
|
|
336
|
+
elif datafile[line].upper().startswith('WELSPECL'):
|
|
337
|
+
line += 1
|
|
338
|
+
key_columns = 18
|
|
339
|
+
if verbose:
|
|
340
|
+
print("found WELSPECL keyword")
|
|
341
|
+
_counter0 = counter.curr() + 1
|
|
342
|
+
|
|
343
|
+
while not _keyword_end():
|
|
344
|
+
|
|
345
|
+
# skip empty or commented lines
|
|
346
|
+
if _empty_line() or _comment_line():
|
|
347
|
+
line += 1
|
|
348
|
+
continue
|
|
349
|
+
|
|
350
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
351
|
+
raise ValueError(
|
|
352
|
+
f"Error format in keyword WELSPECL in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
353
|
+
|
|
354
|
+
# append lines until line slash
|
|
355
|
+
welspecl_line = _line_data().split()
|
|
356
|
+
while '/' not in _this_line():
|
|
357
|
+
line += 1
|
|
358
|
+
welspecl_line += _line_data().split()
|
|
359
|
+
line += 1
|
|
360
|
+
|
|
361
|
+
# complete default values at the end if requered
|
|
362
|
+
if len(welspecl_line) < key_columns:
|
|
363
|
+
welspecl_line_expanded = []
|
|
364
|
+
for each in welspecs_line:
|
|
365
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
366
|
+
welspecl_line_expanded = welspecl_line_expanded + (['1*'] * int(each[:-1]))
|
|
367
|
+
else:
|
|
368
|
+
welspecl_line_expanded.append(each)
|
|
369
|
+
welspecl_line_expanded = welspecl_line_expanded + (
|
|
370
|
+
['1*'] * (key_columns - len(welspecl_line_expanded)))
|
|
371
|
+
welspecl_line = welspecl_line_expanded
|
|
372
|
+
extracted[counter()] = {'WELSPECL': welspecl_line}
|
|
373
|
+
|
|
374
|
+
line += 1 # keyword end line
|
|
375
|
+
if verbose:
|
|
376
|
+
print(
|
|
377
|
+
f" for wells: {', '.join(set([extracted[i_]['WELSPECL'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# if WELLSPEC is found
|
|
381
|
+
elif datafile[line].upper().startswith('WELLSPEC'):
|
|
382
|
+
line += 1
|
|
383
|
+
key_columns = 7
|
|
384
|
+
if verbose:
|
|
385
|
+
print("found WELLSPEC keyword")
|
|
386
|
+
_counter0 = counter.curr() + 1
|
|
387
|
+
|
|
388
|
+
while not _keyword_end():
|
|
389
|
+
|
|
390
|
+
# skip empty or commented lines
|
|
391
|
+
if _empty_line() or _comment_line():
|
|
392
|
+
line += 1
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
396
|
+
raise ValueError(
|
|
397
|
+
f"Error format in keyword WELLSPEC in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
398
|
+
|
|
399
|
+
# append lines until line slash
|
|
400
|
+
wellspec_line = _line_data().split()
|
|
401
|
+
while '/' not in _this_line():
|
|
402
|
+
line += 1
|
|
403
|
+
wellspec_line += _line_data().split()
|
|
404
|
+
line += 1
|
|
405
|
+
|
|
406
|
+
# complete default values at the end if requered
|
|
407
|
+
if len(wellspec_line) < key_columns:
|
|
408
|
+
wellspec_line_expanded = []
|
|
409
|
+
for each in welspecs_line:
|
|
410
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
411
|
+
wellspec_line_expanded = wellspec_line_expanded + (['1*'] * int(each[:-1]))
|
|
412
|
+
else:
|
|
413
|
+
wellspec_line_expanded.append(each)
|
|
414
|
+
wellspec_line_expanded = wellspec_line_expanded + (
|
|
415
|
+
['1*'] * (key_columns - len(wellspec_line_expanded)))
|
|
416
|
+
wellspec_line = wellspec_line_expanded
|
|
417
|
+
extracted[counter()] = {'WELLSPEC': wellspec_line}
|
|
418
|
+
|
|
419
|
+
line += 1 # keyword end line
|
|
420
|
+
if verbose:
|
|
421
|
+
print(
|
|
422
|
+
f" for wells: {', '.join(set([extracted[i_]['WELLSPEC'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
# if WCONPROD is found
|
|
426
|
+
elif datafile[line].upper().startswith('WCONPROD'):
|
|
427
|
+
line += 1
|
|
428
|
+
key_columns = 20
|
|
429
|
+
if verbose:
|
|
430
|
+
print("found WCONPROD keyword")
|
|
431
|
+
_counter0 = counter.curr() + 1
|
|
432
|
+
|
|
433
|
+
while not _keyword_end():
|
|
434
|
+
|
|
435
|
+
# skip empty or commented lines
|
|
436
|
+
if _empty_line() or _comment_line():
|
|
437
|
+
line += 1
|
|
438
|
+
continue
|
|
439
|
+
|
|
440
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
441
|
+
raise ValueError(
|
|
442
|
+
f"Error format in keyword WCONPROD in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
443
|
+
|
|
444
|
+
# append lines until line slash
|
|
445
|
+
wconprod_line = _line_data().split()
|
|
446
|
+
while '/' not in _this_line():
|
|
447
|
+
line += 1
|
|
448
|
+
wconprod_line += _line_data().split()
|
|
449
|
+
line += 1
|
|
450
|
+
|
|
451
|
+
# complete default values at the end if requered
|
|
452
|
+
if len(wconprod_line) < key_columns:
|
|
453
|
+
wconprod_line_expanded = []
|
|
454
|
+
for each in wconprod_line:
|
|
455
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
456
|
+
wconprod_line_expanded = wconprod_line_expanded + (['1*'] * int(each[:-1]))
|
|
457
|
+
else:
|
|
458
|
+
wconprod_line_expanded.append(each)
|
|
459
|
+
wconprod_line_expanded = wconprod_line_expanded + (
|
|
460
|
+
['1*'] * (key_columns - len(wconprod_line_expanded)))
|
|
461
|
+
wconprod_line = wconprod_line_expanded
|
|
462
|
+
extracted[counter()] = {'WCONPROD': wconprod_line}
|
|
463
|
+
|
|
464
|
+
line += 1 # keyword end line
|
|
465
|
+
if verbose:
|
|
466
|
+
print(
|
|
467
|
+
f" for wells: {', '.join(set([extracted[i_]['WCONPROD'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
# if WCONHIST is found
|
|
471
|
+
elif datafile[line].upper().startswith('WCONHIST'):
|
|
472
|
+
line += 1
|
|
473
|
+
key_columns = 12
|
|
474
|
+
if verbose:
|
|
475
|
+
print("found WCONHIST keyword")
|
|
476
|
+
_counter0 = counter.curr() + 1
|
|
477
|
+
|
|
478
|
+
while not _keyword_end():
|
|
479
|
+
|
|
480
|
+
# skip empty or commented lines
|
|
481
|
+
if _empty_line() or _comment_line():
|
|
482
|
+
line += 1
|
|
483
|
+
continue
|
|
484
|
+
|
|
485
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
486
|
+
raise ValueError(
|
|
487
|
+
f"Error format in keyword WCONHIST in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
488
|
+
|
|
489
|
+
# append lines until line slash
|
|
490
|
+
wconhist_line = _line_data().split()
|
|
491
|
+
while '/' not in _this_line():
|
|
492
|
+
line += 1
|
|
493
|
+
wconhist_line += _line_data().split()
|
|
494
|
+
line += 1
|
|
495
|
+
|
|
496
|
+
# complete default values at the end if requered
|
|
497
|
+
if len(wconhist_line) < key_columns:
|
|
498
|
+
wconhist_line_expanded = []
|
|
499
|
+
for each in wconhist_line:
|
|
500
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
501
|
+
wconhist_line_expanded = wconhist_line_expanded + (['1*'] * int(each[:-1]))
|
|
502
|
+
else:
|
|
503
|
+
wconhist_line_expanded.append(each)
|
|
504
|
+
wconhist_line_expanded = wconhist_line_expanded + (
|
|
505
|
+
['1*'] * (key_columns - len(wconhist_line_expanded)))
|
|
506
|
+
wconhist_line = wconhist_line_expanded
|
|
507
|
+
extracted[counter()] = {'WCONHIST': wconhist_line}
|
|
508
|
+
|
|
509
|
+
line += 1 # keyword end line
|
|
510
|
+
if verbose:
|
|
511
|
+
print(
|
|
512
|
+
f" for wells: {', '.join(set([extracted[i_]['WCONHIST'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
# if WCONINJE is found
|
|
516
|
+
elif datafile[line].upper().startswith('WCONINJE'):
|
|
517
|
+
line += 1
|
|
518
|
+
key_columns = 15
|
|
519
|
+
if verbose:
|
|
520
|
+
print("found WCONINJE keyword")
|
|
521
|
+
_counter0 = counter.curr() + 1
|
|
522
|
+
|
|
523
|
+
while not _keyword_end():
|
|
524
|
+
|
|
525
|
+
# skip empty or commented lines
|
|
526
|
+
if _empty_line() or _comment_line():
|
|
527
|
+
line += 1
|
|
528
|
+
continue
|
|
529
|
+
|
|
530
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
531
|
+
raise ValueError(
|
|
532
|
+
f"Error format in keyword WCONINJE in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
533
|
+
|
|
534
|
+
# append lines until line slash
|
|
535
|
+
wconinje_line = _line_data().split()
|
|
536
|
+
while '/' not in _this_line():
|
|
537
|
+
line += 1
|
|
538
|
+
wconinje_line += _line_data().split()
|
|
539
|
+
line += 1
|
|
540
|
+
|
|
541
|
+
# complete default values at the end if requered
|
|
542
|
+
if len(wconinje_line) < key_columns:
|
|
543
|
+
wconinje_line_expanded = []
|
|
544
|
+
for each in wconinje_line:
|
|
545
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
546
|
+
wconinje_line_expanded = wconinje_line_expanded + (['1*'] * int(each[:-1]))
|
|
547
|
+
else:
|
|
548
|
+
wconinje_line_expanded.append(each)
|
|
549
|
+
wconinje_line_expanded = wconinje_line_expanded + (
|
|
550
|
+
['1*'] * (key_columns - len(wconinje_line_expanded)))
|
|
551
|
+
wconinje_line = wconinje_line_expanded
|
|
552
|
+
extracted[counter()] = {'WCONINJE': wconinje_line}
|
|
553
|
+
|
|
554
|
+
line += 1 # keyword end line
|
|
555
|
+
if verbose:
|
|
556
|
+
print(
|
|
557
|
+
f" for wells: {', '.join(set([extracted[i_]['WCONINJE'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
# if WCONINJH is found
|
|
561
|
+
elif datafile[line].upper().startswith('WCONINJH'):
|
|
562
|
+
line += 1
|
|
563
|
+
key_columns = 12
|
|
564
|
+
if verbose:
|
|
565
|
+
print("found WCONINJH keyword")
|
|
566
|
+
_counter0 = counter.curr() + 1
|
|
567
|
+
|
|
568
|
+
while not _keyword_end():
|
|
569
|
+
|
|
570
|
+
# skip empty or commented lines
|
|
571
|
+
if _empty_line() or _comment_line():
|
|
572
|
+
line += 1
|
|
573
|
+
continue
|
|
574
|
+
|
|
575
|
+
if not concatenate_lines and '/' not in datafile[line]:
|
|
576
|
+
raise ValueError(
|
|
577
|
+
f"Error format in keyword WCONINJH in line {line + 1} in file {filepath}. Missing / at the end of the line.")
|
|
578
|
+
|
|
579
|
+
# append lines until line slash
|
|
580
|
+
wconinjh_line = _line_data().split()
|
|
581
|
+
while '/' not in _this_line():
|
|
582
|
+
line += 1
|
|
583
|
+
wconinjh_line += _line_data().split()
|
|
584
|
+
line += 1
|
|
585
|
+
|
|
586
|
+
# complete default values at the end if requered
|
|
587
|
+
if len(wconinjh_line) < key_columns:
|
|
588
|
+
wconinjh_line_expanded = []
|
|
589
|
+
for each in wconinjh_line:
|
|
590
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
591
|
+
wconinjh_line_expanded = wconinjh_line_expanded + (['1*'] * int(each[:-1]))
|
|
592
|
+
else:
|
|
593
|
+
wconinjh_line_expanded.append(each)
|
|
594
|
+
wconinjh_line_expanded = wconinjh_line_expanded + (
|
|
595
|
+
['1*'] * (key_columns - len(wconinjh_line_expanded)))
|
|
596
|
+
wconinjh_line = wconinjh_line_expanded
|
|
597
|
+
extracted[counter()] = {'WCONINJH': wconinjh_line}
|
|
598
|
+
|
|
599
|
+
line += 1 # keyword end line
|
|
600
|
+
if verbose:
|
|
601
|
+
print(
|
|
602
|
+
f" for wells: {', '.join(set([extracted[i_]['WCONINJH'][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
# if INCLUDE is found, will read the include file
|
|
606
|
+
elif datafile[line].upper().startswith('INCLUDE'):
|
|
607
|
+
line += 1
|
|
608
|
+
if verbose:
|
|
609
|
+
print(f"found INCLUDE file inside {filepath}:")
|
|
610
|
+
|
|
611
|
+
# skip empty or commented lines
|
|
612
|
+
while _empty_line() or _comment_line():
|
|
613
|
+
line += 1
|
|
614
|
+
|
|
615
|
+
include = datafile[line][::-1][datafile[line][::-1].index('/') + 1:][::-1].strip().strip("'")
|
|
616
|
+
if verbose:
|
|
617
|
+
print(include)
|
|
618
|
+
|
|
619
|
+
if '$' in include: # identify path from PATHS dictionary
|
|
620
|
+
path_i = include.index('$')
|
|
621
|
+
path_f = include.index('/', path_i)
|
|
622
|
+
path_var = include[path_i: path_f]
|
|
623
|
+
if path_var[1:] not in paths:
|
|
624
|
+
raise ValueError(f"Path variable '{path_var}' not defined in keyword PATHS.")
|
|
625
|
+
include = folder + include[:path_i] + paths[path_var[1:]] + include[path_f:]
|
|
626
|
+
elif include.startswith('../') or include.startswith('./'):
|
|
627
|
+
include = folder + include
|
|
628
|
+
|
|
629
|
+
# reading the include file recursively
|
|
630
|
+
if verbose:
|
|
631
|
+
print(f"reading include: {include}")
|
|
632
|
+
include = read_data(include, paths=paths, folder=folder, verbose=verbose, start_date=_last_date(),
|
|
633
|
+
counter=counter, main=False)
|
|
634
|
+
# load the returned keywords dictionary into this keywords dictionary
|
|
635
|
+
extracted.update(include)
|
|
636
|
+
line += 1
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
# read the listed keywords, that doesn't have and ending line with /
|
|
640
|
+
elif _keyword() in skip0_keywords:
|
|
641
|
+
keyword_ = _keyword()
|
|
642
|
+
extracted[counter()] = {keyword_: None}
|
|
643
|
+
if verbose:
|
|
644
|
+
print(f"found {keyword_} keyword")
|
|
645
|
+
line += 1
|
|
646
|
+
elif _keyword() in skip1_keywords:
|
|
647
|
+
keyword_ = _keyword()
|
|
648
|
+
if verbose:
|
|
649
|
+
print(f"found {keyword_} keyword")
|
|
650
|
+
line += 1
|
|
651
|
+
# skip empty or commented lines
|
|
652
|
+
while _empty_line() or _comment_line():
|
|
653
|
+
line += 1
|
|
654
|
+
extracted[counter()] = {keyword_: _line_data()}
|
|
655
|
+
line += 1
|
|
656
|
+
elif _keyword() in skip3_keywords:
|
|
657
|
+
keyword_ = _keyword()
|
|
658
|
+
if verbose:
|
|
659
|
+
print(f"found {keyword_} keyword")
|
|
660
|
+
line += 1
|
|
661
|
+
for i in range(3):
|
|
662
|
+
# skip empty or commented lines
|
|
663
|
+
while _empty_line() or _comment_line():
|
|
664
|
+
line += 1
|
|
665
|
+
extracted[counter()] = {keyword_: _line_data()}
|
|
666
|
+
line += 1
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
# generic procedure to read any other COMPLETION, WELL, GROUP or USER DEFINED keyword (because they end with /)
|
|
670
|
+
elif _keyword()[0] in 'CWGU':
|
|
671
|
+
keyword_ = _keyword()
|
|
672
|
+
line += 1
|
|
673
|
+
_counter0 = counter.curr() + 1
|
|
674
|
+
if verbose:
|
|
675
|
+
print(f"found {keyword_} keyword")
|
|
676
|
+
|
|
677
|
+
while not _keyword_end():
|
|
678
|
+
|
|
679
|
+
# skip empty or commented lines
|
|
680
|
+
if _empty_line() or _comment_line():
|
|
681
|
+
line += 1
|
|
682
|
+
continue
|
|
683
|
+
|
|
684
|
+
# append lines until line slash
|
|
685
|
+
keyword_line = _line_data().split()
|
|
686
|
+
while '/' not in _this_line():
|
|
687
|
+
line += 1
|
|
688
|
+
keyword_line += _line_data().split()
|
|
689
|
+
|
|
690
|
+
# expand default values if needed
|
|
691
|
+
keyword_line_expanded = []
|
|
692
|
+
for each in keyword_line:
|
|
693
|
+
if len(each) >= 2 and each.endswith('*') and each[:-1].isdigit():
|
|
694
|
+
keyword_line_expanded = keyword_line_expanded + (['1*'] * int(each[:-1]))
|
|
695
|
+
else:
|
|
696
|
+
keyword_line_expanded.append(each)
|
|
697
|
+
keyword_line = keyword_line_expanded
|
|
698
|
+
extracted[counter()] = {keyword_: keyword_line}
|
|
699
|
+
line += 1
|
|
700
|
+
line += 1
|
|
701
|
+
|
|
702
|
+
# expand default values at the end if needed
|
|
703
|
+
keyword_max_ = [len(extracted[i_][keyword_]) for i_ in range(_counter0, counter.curr() + 1)]
|
|
704
|
+
if len(keyword_max_) > 0:
|
|
705
|
+
keyword_max_ = max([len(extracted[i_][keyword_]) for i_ in range(_counter0, counter.curr() + 1)])
|
|
706
|
+
for each in range(_counter0, counter.curr() + 1):
|
|
707
|
+
keyword_line = extracted[each][keyword_]
|
|
708
|
+
if len(keyword_line) < keyword_max_:
|
|
709
|
+
extracted[each][keyword_] = keyword_line + (['1*'] * (keyword_max_ - len(keyword_line)))
|
|
710
|
+
|
|
711
|
+
if verbose:
|
|
712
|
+
print(
|
|
713
|
+
f" for: {', '.join(set([extracted[i_][keyword_][0] for i_ in range(_counter0, counter.curr() + 1)]))}")
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
elif datafile[line].upper().startswith('VFPPROD'):
|
|
717
|
+
keyword_ = _keyword()
|
|
718
|
+
line += 1
|
|
719
|
+
if verbose:
|
|
720
|
+
print(f"found {keyword_} keyword")
|
|
721
|
+
|
|
722
|
+
vfp_tables, vfp_records, vfp_line, vfp_data = 1, 6, [], ''
|
|
723
|
+
while line < len(datafile) and vfp_tables > 0:
|
|
724
|
+
|
|
725
|
+
if _empty_line() or _comment_line():
|
|
726
|
+
line += 1
|
|
727
|
+
continue
|
|
728
|
+
|
|
729
|
+
vfp_data += datafile[line]
|
|
730
|
+
|
|
731
|
+
if vfp_records > 0:
|
|
732
|
+
if '/' not in datafile[line]:
|
|
733
|
+
vfp_line += _line_data().split()
|
|
734
|
+
elif '/' in datafile[line]:
|
|
735
|
+
if vfp_records == 6:
|
|
736
|
+
vfp_line = []
|
|
737
|
+
vfp_records -= 1
|
|
738
|
+
else:
|
|
739
|
+
vfp_line += _line_data().split()
|
|
740
|
+
vfp_tables *= len(vfp_line)
|
|
741
|
+
vfp_line = []
|
|
742
|
+
elif '/' in datafile[line]:
|
|
743
|
+
vfp_tables -= 1
|
|
744
|
+
else:
|
|
745
|
+
pass
|
|
746
|
+
line += 1
|
|
747
|
+
extracted[counter()] = {keyword_: vfp_data}
|
|
748
|
+
|
|
749
|
+
elif datafile[line].upper().startswith('VFPINJ'):
|
|
750
|
+
keyword_ = _keyword()
|
|
751
|
+
line += 1
|
|
752
|
+
if verbose:
|
|
753
|
+
print(f"found {keyword_} keyword")
|
|
754
|
+
|
|
755
|
+
vfp_tables, vfp_records, vfp_line = 1, 3, []
|
|
756
|
+
while line < len(datafile) and vfp_tables > 0:
|
|
757
|
+
|
|
758
|
+
if _empty_line() or _comment_line():
|
|
759
|
+
line += 1
|
|
760
|
+
continue
|
|
761
|
+
|
|
762
|
+
vfp_data += datafile[line]
|
|
763
|
+
|
|
764
|
+
if vfp_records > 0:
|
|
765
|
+
if '/' not in datafile[line]:
|
|
766
|
+
vfp_line += _line_data().split()
|
|
767
|
+
elif '/' in datafile[line]:
|
|
768
|
+
if vfp_records == 3:
|
|
769
|
+
vfp_line = []
|
|
770
|
+
vfp_records -= 1
|
|
771
|
+
elif vfp_records == 2:
|
|
772
|
+
vfp_line += _line_data().split()
|
|
773
|
+
vfp_line = []
|
|
774
|
+
vfp_records -= 1
|
|
775
|
+
else:
|
|
776
|
+
vfp_line += _line_data().split()
|
|
777
|
+
vfp_tables = len(vfp_line)
|
|
778
|
+
vfp_line = []
|
|
779
|
+
elif '/' in datafile[line]:
|
|
780
|
+
vfp_tables -= 1
|
|
781
|
+
else:
|
|
782
|
+
pass
|
|
783
|
+
line += 1
|
|
784
|
+
extracted[counter()] = {keyword_: vfp_data}
|
|
785
|
+
|
|
786
|
+
# skip everything else
|
|
787
|
+
else:
|
|
788
|
+
if verbose:
|
|
789
|
+
print(f"skipping {datafile[line]}")
|
|
790
|
+
line += 1
|
|
791
|
+
|
|
792
|
+
if verbose:
|
|
793
|
+
print(f"closing this file, {counter.curr() - keywords_before} keywords found here.")
|
|
794
|
+
print()
|
|
795
|
+
|
|
796
|
+
return extracted
|