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,81 @@
1
+ """
2
+ A set of functions to read and process the schedule data from a .DATA file, including functions to extract the WELSPECS, COMPDAT, WCONPROD, WCONINJE, WCONHIST, WCONINJH, and WLIST keywords from the schedule dictionary and return a DataFrame of the corresponding data by DATES. Also includes functions to read and process the property keywords in the .DATA file, such as DIMENS, PORO, PERMX, etc.
3
+
4
+ developed by: Martin Araya
5
+ email: martinaraya@gmail.com
6
+ """
7
+
8
+ import pandas as pd
9
+ from .data_reader import read_data
10
+ from .welspec import extract_welspecs, extract_welspecl, extract_wellspec, extract_welspec2
11
+ from .compdat import extract_compdat, extract_compdatl, extract_compdat2
12
+ from .wcon import extract_wconprod, extract_wconinje, extract_wconhist, extract_wconinjh
13
+ from .wlist import extract_wlist
14
+ from .property_keywords import read_keyword_from_include, expand_keyword, ijk_index, get_dimens
15
+ from .schedule_keywords import extract_keyword
16
+ from .counter import start_counter
17
+
18
+ __all__ = ['compdat2df', 'welspecs2df', 'property2df', 'start_counter']
19
+ __version__ = '0.7.0'
20
+ __release__ = 20260228
21
+
22
+
23
+ def compdat2df(path, encoding='cp1252', verbose=False):
24
+ if type(path) is dict:
25
+ return extract_compdat2(path)
26
+ return extract_compdat2(read_data(path, encoding=encoding, verbose=verbose))
27
+
28
+ def welspecs2df(path, encoding='cp1252', verbose=False):
29
+ if type(path) is dict:
30
+ return extract_welspec2(path)
31
+ return extract_welspec2(read_data(path, encoding=encoding, verbose=verbose))
32
+
33
+ def wconprod2df(path, encoding='cp1252', verbose=False):
34
+ if type(path) is dict:
35
+ return extract_wconprod(path)
36
+ return extract_wconprod(read_data(path, encoding=encoding, verbose=verbose))
37
+
38
+ def wconinje2df(path, encoding='cp1252', verbose=False):
39
+ if type(path) is dict:
40
+ return extract_wconinje(path)
41
+ return extract_wconinje(read_data(path, encoding=encoding, verbose=verbose))
42
+
43
+ def wconhist2df(path, encoding='cp1252', verbose=False):
44
+ if type(path) is dict:
45
+ return extract_wconhist(path)
46
+ return extract_wconhist(read_data(path, encoding=encoding, verbose=verbose))
47
+
48
+ def wconinjh2df(path, encoding='cp1252', verbose=False):
49
+ if type(path) is dict:
50
+ return extract_wconinjh(path)
51
+ return extract_wconinjh(read_data(path, encoding=encoding, verbose=verbose))
52
+
53
+ def wlist2df(path, encoding='cp1252', verbose=False):
54
+ if type(path) is dict:
55
+ return extract_wlist(path)
56
+ return extract_wlist(read_data(path, encoding=encoding, verbose=verbose))
57
+
58
+ def keyword2df(path, keyword, record_names=[], encoding='cp1252', verbose=False):
59
+ record_names = None if len(record_names) == 0 else record_names
60
+ if type(path) is dict:
61
+ return extract_keyword(path, keyword=keyword, record_names=record_names)
62
+ return extract_keyword(
63
+ read_data(path, encoding=encoding, verbose=verbose),
64
+ keyword=keyword, record_names=record_names)
65
+
66
+ def property2df(path, keyword, dimens=(None, None, None), encoding='cp1252', verbose=False, parse_to=None):
67
+ keyword_data = expand_keyword(read_keyword_from_include(path, keyword, encoding=encoding))
68
+ if dimens[0] is not None and dimens[1] is not None and dimens[2] is not None:
69
+ cells = ijk_index(dimens[0], dimens[1], dimens[2])
70
+ output = pd.Series(
71
+ keyword_data.split(),
72
+ index=pd.MultiIndex.from_tuples(cells),
73
+ name=keyword).reset_index()
74
+ output.columns = ['I', 'J', 'K', keyword]
75
+ output[['I', 'J', 'K']] = output[['I', 'J', 'K']].astype(int)
76
+ if parse_to is None:
77
+ parse_to = int if keyword.endswith('NUM') else float
78
+ output[keyword] = output[keyword].astype(parse_to)
79
+ return output
80
+ else:
81
+ return keyword_data
@@ -0,0 +1,153 @@
1
+ """
2
+ This module contains functions to extract and process the COMPDAT keyword from the schedule dictionary.
3
+ The COMPDAT keyword defines the completion data for wells in the reservoir simulation model. It includes information such as the well name, location, status, and other parameters related to the well completion.
4
+ The functions in this module will extract the COMPDAT data from the schedule dictionary, process it, and return it as a pandas DataFrame for further analysis and use in reservoir simulation models.
5
+
6
+ The main functions in this module are:
7
+ - `extract_compdat`: Extracts the COMPDAT keyword from the schedule dictionary and returns a DataFrame of COMPDAT data by DATES.
8
+ - `extract_compdatl`: Extracts the COMPDATL keyword from the schedule dictionary and returns a DataFrame of COMPDATL data by DATES.
9
+ - `extract_compdatm`: Alias for `extract_compdatl`.
10
+
11
+ developed by: Martin Araya
12
+ email: martinaraya@gmail.com
13
+ """
14
+
15
+ import pandas as pd
16
+ from .dates import parse_dates
17
+ from .schedule_keywords import extract_keyword
18
+ from .welspec import extract_welspecs, extract_welspecl
19
+
20
+ __version__ = '0.7.0'
21
+ __release__ = 20260228
22
+
23
+
24
+ def _defaultIJ(well, date, IJ, welspec_table):
25
+ """
26
+ Helper function to find the I and J coordinates for a well, from its WELSPECS definition.
27
+ Used when the I or J coordinates are defaulted in the COMPDAT keyword.
28
+
29
+ Params:
30
+ well: str
31
+ date: str or datetime
32
+ IJ: str 'I' 'J'
33
+ the coordinate to be extracted
34
+ welspecs_table: pandas.DataFrame
35
+ A DataFrame containing at least the 'date', 'well', 'I' and 'J' data from the WELSPEC keyword.
36
+ This DataFrame is prepared by the function `extract_welspecs`. It is automatically called by the function `extract_compdat` if required.
37
+ """
38
+ return welspec_table[(welspec_table['well'] == well) & (welspec_table['date'] <= date), IJ].iloc[-1]
39
+
40
+
41
+ def extract_compdat(schedule_dict:dict) -> pd.DataFrame:
42
+ """
43
+ Shortcut for `extract_keyword` for the COMPDAT keyword.
44
+ Extract the COMPDAT keyword from the schedule dictionary and return a DataFrame of COMPDAT data by DATES.
45
+
46
+ Params:
47
+ schedule_dict: dict
48
+ shedule dictionary prepared by the .data_reader.read_data function
49
+
50
+ Return:
51
+ pandas.DataFrame
52
+ """
53
+ compdat_columns = ['date', 'well', 'I', 'J', 'K_up', 'K_low', 'status', 'saturation table',
54
+ 'transimissibility factor', 'well bore diameter', 'Kh', 'skin', 'D-factor', 'direction',
55
+ 'pressure equivalent radius']
56
+ compdat_table = extract_keyword(schedule_dict, 'COMPDAT', compdat_columns) # {}
57
+ if len(compdat_table) > 0:
58
+ compdat_table['date'] = parse_dates(
59
+ compdat_table['date'].to_list()) # to parse dates exactly as stated by DATES eclipse format
60
+ compdat_table['well'] = [well.strip("'") for well in compdat_table['well']]
61
+ compdat_table['well'] = compdat_table['well'].astype('string').astype('category', errors='ignore')
62
+ compdat_table = compdat_table.replace('1*', None).replace("'1*'", None)
63
+ to_int = ['I', 'J', 'K_up', 'K_low']
64
+ compdat_table[to_int] = compdat_table[to_int].astype('string').fillna('0').astype(int, errors='ignore')
65
+ if 0 in compdat_table['I'].values or 0 in compdat_table['J'].values:
66
+ welspecs_table = extract_welspecs(schedule_dict)
67
+ if 0 in compdat_table['I'].values:
68
+ compdat_table['I'] = [compdat_table['I'].iloc[r] if compdat_table['I'].iloc[r] > 0 else _defaultIJ(
69
+ compdat_table['date'].iloc[r], compdat_table['date'].iloc[r], 'I', welspecs_table) for r in
70
+ len(compdat_table)]
71
+ if 0 in compdat_table['J'].values:
72
+ compdat_table['J'] = [compdat_table['I'].iloc[r] if compdat_table['I'].iloc[r] > 0 else _defaultIJ(
73
+ compdat_table['date'].iloc[r], compdat_table['date'].iloc[r], 'J', welspecs_table) for r in
74
+ len(compdat_table)]
75
+ to_float = ['transimissibility factor', 'well bore diameter', 'Kh', 'skin', 'D-factor',
76
+ 'pressure equivalent radius']
77
+ compdat_table[to_float] = compdat_table[to_float].astype(float, errors='ignore')
78
+ compdat_table['status'] = compdat_table['status'].astype('string').fillna('OPEN').astype('category', errors='ignore').cat.set_categories(['AUTO', 'OPEN', 'SHUT', 'HEAT'], rename=True)
79
+ compdat_table['skin'] = compdat_table['skin'].fillna(0.0)
80
+ compdat_table['direction'] = compdat_table['direction'].astype('string').fillna('Z').astype('category', errors='ignore').cat.set_categories(['X', 'Y', 'Z', 'FX', 'FY'], rename=True)
81
+ return compdat_table
82
+
83
+
84
+ def extract_compdatl(schedule_dict:dict) -> pd.DataFrame:
85
+ """
86
+ Shortcut for `extract_keyword` for the COMPDAT keyword.
87
+ Extract the COMPDAT keyword from the schedule dictionary and return a DataFrame of COMPDATL data by DATES.
88
+
89
+ Params:
90
+ schedule_dict: dict
91
+ schedule dictionary prepared by the .data_reader.read_data function
92
+
93
+ Return:
94
+ pandas.DataFrame
95
+ """
96
+ compdatl_columns = ['date', 'well', 'local grid', 'I', 'J', 'K_up', 'K_low', 'status', 'saturation table',
97
+ 'transimissibility factor', 'well bore diameter', 'Kh', 'skin', 'D-factor', 'direction',
98
+ 'pressure equivalent radius']
99
+ compdatl_table = extract_keyword(schedule_dict, 'COMPDATL', compdatl_columns) # {}
100
+ if len(compdatl_table) > 0:
101
+ compdatl_table['date'] = parse_dates(
102
+ compdatl_table['date'].to_list()) # to parse dates exactly as stated by DATES eclipse format
103
+ compdatl_table['well'] = [well.strip("'") for well in compdatl_table['well']]
104
+ compdatl_table['well'] = compdatl_table['well'].astype('category', errors='ignore')
105
+ compdat_table = compdat_table.replace('1*', None).replace("'1*'", None)
106
+ to_int = ['I', 'J', 'K_up', 'K_low']
107
+ compdatl_table[to_int] = compdatl_table[to_int].astype('string').fillna('0').astype(int, errors='ignore')
108
+ if 0 in compdatl_table['I'].values or 0 in compdatl_table['J'].values:
109
+ welspecl_table = extract_welspecl(schedule_dict)
110
+ if 0 in compdatl_table['I'].values:
111
+ compdatl_table['I'] = [compdatl_table['I'].iloc[r] if compdatl_table['I'].iloc[r] > 0 else _defaultIJ(
112
+ compdatl_table['date'].iloc[r], compdatl_table['date'].iloc[r], 'I', welspecl_table) for r in
113
+ len(compdatl_table)]
114
+ if 0 in compdatl_table['J'].values:
115
+ compdatl_table['J'] = [compdatl_table['I'].iloc[r] if compdatl_table['I'].iloc[r] > 0 else _defaultIJ(
116
+ compdatl_table['date'].iloc[r], compdatl_table['date'].iloc[r], 'J', welspecl_table) for r in
117
+ len(compdatl_table)]
118
+ to_float = ['transimissibility factor', 'well bore diameter', 'Kh', 'skin', 'D-factor',
119
+ 'pressure equivalent radius']
120
+ compdatl_table[to_float] = compdatl_table[to_float].astype(float, errors='ignore')
121
+ compdatl_table['status'] = compdatl_table['status'].astype('string').fillna('OPEN').astype('category', errors='ignore').cat.set_categories(['AUTO', 'OPEN', 'SHUT', 'HEAT'], rename=True)
122
+ compdatl_table['skin'] = compdatl_table['skin'].fillna(0.0)
123
+ compdatl_table['direction'] = compdatl_table['direction'].astype('string').fillna('Z').astype('category', errors='ignore').cat.set_categories(['X', 'Y', 'Z', 'FX', 'FY'], rename=True)
124
+ return compdatl_table
125
+
126
+
127
+ def extract_compdatm(schedule_dict:dict) -> pd.DataFrame:
128
+ """
129
+ alias for extract_compdatl
130
+ """
131
+ return extract_compdatl(schedule_dict)
132
+
133
+
134
+ def extract_compdat2(schedule_dict:dict) -> pd.DataFrame:
135
+ """
136
+ Extract COMPDAT, COMPDATL and COMPDATM from the schedule dictionary and return a DataFrame of COMPDAT(s) data by DATES.
137
+
138
+ Params:
139
+ schedule_dict: dict
140
+ schedule dictionary prepared by the .data_reader.read_data function
141
+
142
+ Return:
143
+ pandas.DataFrame
144
+ """
145
+ compdat = extract_compdat(schedule_dict)
146
+ compdatl = extract_compdatl(schedule_dict)
147
+
148
+ if len(compdat) > 0 and len(compdatl) > 0:
149
+ return pd.concat([compdat, compdatl], axis=0, ignore_index=False)
150
+ elif len(compdatl) > 0:
151
+ return compdatl
152
+ else:
153
+ return compdat
@@ -0,0 +1,66 @@
1
+ """
2
+ A simple counter class that can be used to count the number of iterations in a loop. It can be initialized with a starting value and a step size, and it has methods to increment, decrement, and get the current value of the counter. It also has a __call__ method that can be used to get the next value of the counter or the current value without incrementing it. The class also has __add__, __sub__, and __mult__ methods to perform arithmetic operations on the counter. The start_counter function is a helper function to create a new Counter instance with a given starting value.
3
+
4
+ developed by: Martin Araya
5
+ email: martinaraya@gmail.com
6
+ """
7
+ __version__ = '0.7.0'
8
+ __release__ = 20260228
9
+
10
+ class Counter(object):
11
+ """A simple counter that can be used to count the number of iterations in a loop."""
12
+ def __init__(self, start: int = 0, step: int = 1):
13
+ """Initialize the counter with a starting value and a step size."""
14
+ if step == 0:
15
+ raise ValueError(f"The `step` can't be zero!")
16
+ self.start = start
17
+ self.step = step
18
+ self.current = start - step
19
+
20
+ def next(self):
21
+ """Increment the counter by the step size and return the current value."""
22
+ self.current += self.step
23
+ return self.current
24
+
25
+ def curr(self):
26
+ """Return the current value of the counter without incrementing it."""
27
+ return self.current if self.current >= self.start else self.start
28
+
29
+ def prev(self):
30
+ """Decrement the counter by the step size and return the current value."""
31
+ self.current -= self.step
32
+
33
+ def __call__(self, count=True):
34
+ """Return the next value of the counter if `count` is True, otherwise return the current value."""
35
+ if count is None:
36
+ return None
37
+ elif count:
38
+ return self.next()
39
+ elif not count:
40
+ return self.curr()
41
+ else:
42
+ return None
43
+
44
+ def __add__(self, other: int):
45
+ """Add a value to the current count and return the new count."""
46
+ self.current = self.curr + other
47
+ return self.curr()
48
+
49
+ def __sub__(self, other: int):
50
+ """Subtract a value from the current count and return the new count."""
51
+ self.current = self.curr - other
52
+ return self.curr()
53
+
54
+ def __mult__(self, other: int):
55
+ """Multiply the current count by a value and return the new count."""
56
+ self.current = self.curr * other
57
+ return self.curr()
58
+
59
+ def __repr__(self):
60
+ """Return a string representation of the counter."""
61
+ return f"{self.curr()} counted"
62
+
63
+
64
+ def start_counter(start: int):
65
+ """Start a counter with a given starting value."""
66
+ return Counter(start)