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.
@@ -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