pyrestoolbox 2.2.1__tar.gz → 2.2.2__tar.gz
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.
- {pyrestoolbox-2.2.1/pyrestoolbox.egg-info → pyrestoolbox-2.2.2}/PKG-INFO +1 -1
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/gas.rst +3 -19
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/library.rst +2 -2
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/oil.rst +14 -15
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/simtools.rst +17 -13
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/library/library.py +10 -2
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/run_all_tests.py +1 -0
- pyrestoolbox-2.2.2/pyrestoolbox/tests/test_doc_examples.py +556 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2/pyrestoolbox.egg-info}/PKG-INFO +1 -1
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox.egg-info/SOURCES.txt +1 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/setup.cfg +1 -1
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/setup.py +1 -1
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/LICENSE +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/MANIFEST.in +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/README.md +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/README.rst +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyproject.toml +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/brine/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/brine/brine.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/classes/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/classes/classes.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/constants/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/constants/constants.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/brine.rst +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/changelist.rst +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/bot.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/bot_img.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/dry_gas.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/influence.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/properties_df.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/sgof.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/img/swof.png +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/docs/layer.rst +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/gas/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/gas/gas.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/layer/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/layer/layer.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/library/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/library/component_library.xlsx +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/oil/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/oil/oil.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/shared_fns/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/shared_fns/shared_fns.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/simtools/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/simtools/simtools.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/test_brine.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/test_gas.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/test_layer.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/test_oil.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/tests/test_simtools.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/validate/__init__.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox/validate/validate.py +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox.egg-info/dependency_links.txt +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox.egg-info/requires.txt +0 -0
- {pyrestoolbox-2.2.1 → pyrestoolbox-2.2.2}/pyrestoolbox.egg-info/top_level.txt +0 -0
|
@@ -210,22 +210,7 @@ Examples:
|
|
|
210
210
|
|
|
211
211
|
>>> gas.gas_z(p=[1000, 2000], sg=0.75, degf=160, cmethod='SUT', n2 = 0.02, co2 = 0.17)
|
|
212
212
|
array([0.91920553, 0.87196032])
|
|
213
|
-
|
|
214
|
-
def gas_ug(
|
|
215
|
-
p: npt.ArrayLike,
|
|
216
|
-
sg: float,
|
|
217
|
-
degf: float,
|
|
218
|
-
zmethod: z_method = z_method.DAK,
|
|
219
|
-
cmethod: c_method = c_method.PMC,
|
|
220
|
-
co2: float = 0,
|
|
221
|
-
h2s: float = 0,
|
|
222
|
-
n2: float = 0,
|
|
223
|
-
h2: float = 0,
|
|
224
|
-
tc: float = 0,
|
|
225
|
-
pc: float = 0,
|
|
226
|
-
zee: float = 0,
|
|
227
|
-
ugz = False
|
|
228
|
-
|
|
213
|
+
|
|
229
214
|
pyrestoolbox.gas.gas_ug
|
|
230
215
|
===================
|
|
231
216
|
|
|
@@ -741,7 +726,7 @@ pyrestoolbox.gas.gas_rate_radial
|
|
|
741
726
|
gas_rate_radial(k, h, pr, pwf, r_w, r_ext, degf, zmethod='DAK, cmethod='PMC', S = 0, D = 0, sg = 0.75, n2 = 0, co2 = 0, h2s = 0, tc = 0, pc = 0) -> float or np.array
|
|
742
727
|
|
|
743
728
|
Returns gas rate (mscf/day) for radial flow using Darcy pseudo steady state equation & gas pseudopressure.
|
|
744
|
-
Arrays can be used for any one of k, h, pr or pwf, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
729
|
+
Arrays can be used for any one of k, h, pr or pwf, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
745
730
|
|
|
746
731
|
.. list-table:: Inputs
|
|
747
732
|
:widths: 10 15 40
|
|
@@ -806,7 +791,6 @@ Examples:
|
|
|
806
791
|
|
|
807
792
|
.. code-block:: python
|
|
808
793
|
|
|
809
|
-
>>> from pyrestoolbox import pyrestoolbox as rtb
|
|
810
794
|
>>> gas.gas_rate_radial(k=5, h=50, pr=2000, pwf=750, r_w=0.3, r_ext=1500, degf=180, sg = 0.75, D = 0.01, S=5)
|
|
811
795
|
10269.669190157822
|
|
812
796
|
|
|
@@ -822,7 +806,7 @@ pyrestoolbox.gas.gas_rate_linear
|
|
|
822
806
|
gas_rate_linear(k, pr, pwf, area, length, degf, zmethod='DAK, cmethod='PMC', sg = 0.75, n2 = 0, co2 = 0, h2s = 0, tc = 0, pc = 0) -> float or np.array
|
|
823
807
|
|
|
824
808
|
Returns gas rate (mscf/day) for linear flow using Darcy steady state equation & gas pseudopressure.
|
|
825
|
-
Arrays can be used for any one of k, pr, pwf or area, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
809
|
+
Arrays can be used for any one of k, pr, pwf or area, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
826
810
|
|
|
827
811
|
|
|
828
812
|
.. list-table:: Inputs
|
|
@@ -65,7 +65,7 @@ Examples:
|
|
|
65
65
|
|
|
66
66
|
.. code-block:: python
|
|
67
67
|
|
|
68
|
-
>>> library.prop(comp = 'C3', prop = 'VTran'),
|
|
68
|
+
>>> library.prop(comp = 'C3', prop = 'VTran'), library.prop(comp = 'C3', prop = 'VTran', model='SRK')
|
|
69
69
|
(-0.06381, 0.09075)
|
|
70
70
|
|
|
71
71
|
|
|
@@ -158,5 +158,5 @@ Example:
|
|
|
158
158
|
|
|
159
159
|
>>> library.df
|
|
160
160
|
|
|
161
|
-
.. image::
|
|
161
|
+
.. image:: img/properties_df.png
|
|
162
162
|
:alt: DataFrame of Component Library data
|
|
@@ -57,7 +57,7 @@ pyResToolBox uses class objects to track calculation options through the functio
|
|
|
57
57
|
- Method for calculating oil formation volume factor. Defaults to 'MCAIN'
|
|
58
58
|
Options are:
|
|
59
59
|
+ 'STAN': Standing Correlation
|
|
60
|
-
+ 'MCAIN': McCain approach, calculating from densities � Default
|
|
60
|
+
+ 'MCAIN': McCain approach, calculating from densities � Default
|
|
61
61
|
|
|
62
62
|
Users can specify which calculation method to use either by passing an option string, or a class object to any given function. The implementation of class objects should make it easier to program in an IDE that supports type hinting
|
|
63
63
|
|
|
@@ -148,7 +148,7 @@ Examples:
|
|
|
148
148
|
|
|
149
149
|
.. code-block:: python
|
|
150
150
|
|
|
151
|
-
>>> oil.
|
|
151
|
+
>>> oil.oil_ja_sg(mw=150, ja=0.5)
|
|
152
152
|
0.8583666666666667
|
|
153
153
|
|
|
154
154
|
pyrestoolbox.oil.oil_twu_props
|
|
@@ -239,7 +239,7 @@ pyrestoolbox.oil.oil_pbub
|
|
|
239
239
|
|
|
240
240
|
.. code-block:: python
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
oil_pbub(api, degf, rsb, sg_g =0, sg_sp =0, pbmethod ='VALMC') -> float
|
|
243
243
|
|
|
244
244
|
Returns bubble point pressure (psia) calculated with different correlations.
|
|
245
245
|
At least one of sg_g and sg_sp must be supplied. This function will make simple assumption to estimate missing gas sg if only one is provided.
|
|
@@ -344,15 +344,15 @@ Returns solution gas oil ratio (scf/stb) calculated with different correlations.
|
|
|
344
344
|
* - degf
|
|
345
345
|
- float
|
|
346
346
|
- Oil Temperature (deg F)
|
|
347
|
-
* -
|
|
347
|
+
* - sg_sp
|
|
348
348
|
- float
|
|
349
|
-
-
|
|
349
|
+
- Separator gas gravity (relative to air).
|
|
350
350
|
* - p
|
|
351
351
|
- float
|
|
352
|
-
- Pressure (psia).
|
|
352
|
+
- Pressure (psia).
|
|
353
353
|
* - pb
|
|
354
354
|
- float
|
|
355
|
-
- Original bubble point pressure (psia)
|
|
355
|
+
- Original bubble point pressure (psia)
|
|
356
356
|
* - rsb
|
|
357
357
|
- float
|
|
358
358
|
- Original solution GOR at original bubble point pressure (scf/stb)
|
|
@@ -367,7 +367,7 @@ Examples:
|
|
|
367
367
|
|
|
368
368
|
.. code-block:: python
|
|
369
369
|
|
|
370
|
-
>>> oil.oil_rs(api = 43, degf = 185, sg_sp
|
|
370
|
+
>>> oil.oil_rs(api = 43, degf = 185, sg_sp=0.72, p = 3000, pb = 5179.5, rsb = 2370)
|
|
371
371
|
1017.9424240354475
|
|
372
372
|
|
|
373
373
|
>>> oil.oil_rs(api=43, degf=185, sg_sp=0.72, p=3000, rsb =2370)
|
|
@@ -610,7 +610,7 @@ pyrestoolbox.oil.make_bot_og
|
|
|
610
610
|
|
|
611
611
|
.. code-block:: python
|
|
612
612
|
|
|
613
|
-
make_bot_og(pi, api, degf, sg_g, pmax, pb =0, rsb =0, pmin =14.7, nrows = 20, wt =0, ch4_sat =0, comethod='EXPLT', zmethod='DAK', rsmethod='VELAR', cmethod'PMC', denomethod='SWMH', bomethod='MCAIN', pbmethod='VALMC', export=False) -> tuple
|
|
613
|
+
make_bot_og(pi, api, degf, sg_g, pmax, pb =0, rsb =0, pmin =14.7, nrows = 20, wt =0, ch4_sat =0, comethod='EXPLT', zmethod='DAK', rsmethod='VELAR', cmethod='PMC', denomethod='SWMH', bomethod='MCAIN', pbmethod='VALMC', export=False) -> tuple
|
|
614
614
|
|
|
615
615
|
Creates data required for Oil-Gas-Water black oil tables. Returns dictionary of results, with index:
|
|
616
616
|
- bot: Pandas table of blackoil data (for PVTO == False), or Saturated properties to pmax (if PVTO == True)
|
|
@@ -709,7 +709,7 @@ Examples:
|
|
|
709
709
|
>>> results = oil.make_bot_og(pvto=False, pi=4000, api=38, degf=175, sg_g=0.68, pmax=5500, pb=4500, nrows=10, export=True)
|
|
710
710
|
>>> df, st_deno, st_deng, res_denw, res_cw, visw, pb, rsb, rsb_frac, usat = results['bot'], results['deno'], results['deng'], results['denw'], results['cw'], results['uw'], results['pb'], results['rsb'], results['rsb_scale'], results['usat']
|
|
711
711
|
>>> df
|
|
712
|
-
.. image::
|
|
712
|
+
.. image:: img/bot_img.png
|
|
713
713
|
:alt: Black Oil Table DataFrame
|
|
714
714
|
|
|
715
715
|
pyrestoolbox.oil.sg_evolved_gas
|
|
@@ -749,9 +749,8 @@ Examples:
|
|
|
749
749
|
|
|
750
750
|
.. code-block:: python
|
|
751
751
|
|
|
752
|
-
>>> oil.
|
|
753
|
-
|
|
754
|
-
|
|
752
|
+
>>> oil.sg_evolved_gas(p=2000, degf=185, rsb=2370, api=43, sg_sp=0.72)
|
|
753
|
+
0.7872810977386344
|
|
755
754
|
|
|
756
755
|
pyrestoolbox.oil.sg_st_gas
|
|
757
756
|
=======================
|
|
@@ -891,7 +890,7 @@ pyrestoolbox.oil.oil_rate_radial
|
|
|
891
890
|
oil_rate_radial(k, h, pr, pwf, r_w, r_ext, uo, bo, S = 0, vogel = False, pb = 0) -> float or np.array
|
|
892
891
|
|
|
893
892
|
Returns liquid rate (stb/day) for radial flow using Darcy pseudo steady state equation with optional Vogel correction.
|
|
894
|
-
Arrays can be used for any one of k, h, pr or pwf, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
893
|
+
Arrays can be used for any one of k, h, pr or pwf, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
895
894
|
|
|
896
895
|
.. list-table:: Inputs
|
|
897
896
|
:widths: 10 15 40
|
|
@@ -952,7 +951,7 @@ pyrestoolbox.oil.oil_rate_linear
|
|
|
952
951
|
oil_rate_linear(k, pr, pwf, area, length, uo, bo, vogel = False, pb = 0) -> float or np.array
|
|
953
952
|
|
|
954
953
|
Returns liquid rate (stb/day) for linear flow using Darcy steady state equation with optional Vogel correction.
|
|
955
|
-
Arrays can be used for any one of k, pr, pwf or area, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
954
|
+
Arrays can be used for any one of k, pr, pwf or area, returning corresponding 1-D array of rates. Using more than one input array � while not prohibited - will not return expected results
|
|
956
955
|
|
|
957
956
|
.. list-table:: Inputs
|
|
958
957
|
:widths: 10 15 40
|
|
@@ -52,7 +52,8 @@ Examples:
|
|
|
52
52
|
|
|
53
53
|
.. code-block:: python
|
|
54
54
|
|
|
55
|
-
>>>
|
|
55
|
+
>>> from pyrestoolbox import simtools
|
|
56
|
+
>>> results = simtools.ix_extract_problem_cells()
|
|
56
57
|
>>> wells, grid_pres, grid_sat, grid_comp = results
|
|
57
58
|
>>> grid_sat
|
|
58
59
|
Processing TEST.PRT
|
|
@@ -64,7 +65,7 @@ Examples:
|
|
|
64
65
|
Grid Saturation Change 310 32,121,24 13
|
|
65
66
|
Grid Composition Change 1627 35,212,25 544
|
|
66
67
|
|
|
67
|
-
.. image::
|
|
68
|
+
.. image:: img/grid_sat_df.png
|
|
68
69
|
:alt: DSorted ataFrame of grid blocks with saturation related convergence issues
|
|
69
70
|
|
|
70
71
|
|
|
@@ -112,10 +113,10 @@ Examples:
|
|
|
112
113
|
|
|
113
114
|
.. code-block:: python
|
|
114
115
|
|
|
115
|
-
>>> from pyrestoolbox import
|
|
116
|
+
>>> from pyrestoolbox import simtools
|
|
116
117
|
>>> import matplotlib.pyplot as plt
|
|
117
118
|
>>> ReDs = [1.5, 2, 3, 5, 10, 25, 1000]
|
|
118
|
-
>>> tds, pds =
|
|
119
|
+
>>> tds, pds = simtools.influence_tables(ReDs=ReDs, export=True)
|
|
119
120
|
>>>
|
|
120
121
|
>>> for p, pd in enumerate(pds):
|
|
121
122
|
>>> plt.plot(tds, pd, label = str(ReDs[p]))
|
|
@@ -129,7 +130,7 @@ Examples:
|
|
|
129
130
|
>>> plt.title('Constant Terminal Rate Solution')
|
|
130
131
|
>>> plt.show()
|
|
131
132
|
|
|
132
|
-
.. image::
|
|
133
|
+
.. image:: img/influence.png
|
|
133
134
|
:alt: Constant Terminal Rate influence tables
|
|
134
135
|
|
|
135
136
|
|
|
@@ -173,10 +174,10 @@ Examples:
|
|
|
173
174
|
|
|
174
175
|
.. code-block:: python
|
|
175
176
|
|
|
176
|
-
>>>
|
|
177
|
+
>>> simtools.zip_check_sim_deck(['FIELD_A.DATA', 'FIELD_B.afi'], console_summary=False)
|
|
177
178
|
['INCLUDE/GridOpts.inc', 'INCLUDE/ZCORN_COORD.GRDECL', 'EPS.ixf']
|
|
178
179
|
|
|
179
|
-
>>>
|
|
180
|
+
>>> simtools.zip_check_sim_deck()
|
|
180
181
|
Index File Name
|
|
181
182
|
------- ------------
|
|
182
183
|
0 FIELD_A.DATA
|
|
@@ -247,7 +248,7 @@ Examples:
|
|
|
247
248
|
|
|
248
249
|
.. code-block:: python
|
|
249
250
|
|
|
250
|
-
>>>
|
|
251
|
+
>>> simtools.rr_solver(zi =np.array([0.7, 0.15, 0.1, 0.05]), ki = np.array([50, 5, 0.5, 0.01]))
|
|
251
252
|
(6,
|
|
252
253
|
array([0.7406252 , 0.1570315 , 0.09469948, 0.00764382]),
|
|
253
254
|
array([0.0148125 , 0.0314063 , 0.18939896, 0.76438224]),
|
|
@@ -342,9 +343,12 @@ pyrestoolbox.simtools.rel_perm_table
|
|
|
342
343
|
|
|
343
344
|
|
|
344
345
|
Examples:
|
|
345
|
-
|
|
346
|
+
|
|
347
|
+
.. code-block:: python
|
|
348
|
+
|
|
349
|
+
>>> from pyrestoolbox import simtools
|
|
346
350
|
>>> import matplotlib.pyplot as plt
|
|
347
|
-
>>> df =
|
|
351
|
+
>>> df = simtools.rel_perm_table(rows=25, krtable='SGOF', krfamily='LET', kromax =1, krgmax =1, swc =0.2, sorg =0.15, Lo=2.5, Eo = 1.25, To = 1.75, Lg = 1.2, Eg = 1.5, Tg = 2.0)
|
|
348
352
|
>>> plt.plot(df['Sg'], df['Krgo'], c = 'r', label='Gas')
|
|
349
353
|
>>> plt.plot(df['Sg'], df['Krog'], c = 'g', label='Oil')
|
|
350
354
|
>>> plt.title('SGOF Gas Oil LET Relative Permeability Curves')
|
|
@@ -354,12 +358,12 @@ Examples:
|
|
|
354
358
|
>>> plt.grid('both')
|
|
355
359
|
>>> plt.plot()
|
|
356
360
|
|
|
357
|
-
.. image::
|
|
361
|
+
.. image:: img/sgof.png
|
|
358
362
|
:alt: SGOF Relative Permeability Curves
|
|
359
363
|
|
|
360
364
|
.. code-block:: python
|
|
361
365
|
|
|
362
|
-
>>> df =
|
|
366
|
+
>>> df = simtools.rel_perm_table(rows=25, krtable='SWOF', kromax =1, krwmax =0.25, swc =0.15, swcr = 0.2, sorw =0.15, no=2.5, nw=1.5)
|
|
363
367
|
>>> plt.plot(df['Sw'], df['Krow'], c = 'g', label='Oil')
|
|
364
368
|
>>> plt.plot(df['Sw'], df['Krwo'], c = 'b', label='Water')
|
|
365
369
|
>>> plt.title('SWOF Water Oil Corey Relative Permeability Curves')
|
|
@@ -369,7 +373,7 @@ Examples:
|
|
|
369
373
|
>>> plt.grid('both')
|
|
370
374
|
>>> plt.plot()
|
|
371
375
|
|
|
372
|
-
.. image::
|
|
376
|
+
.. image:: img/swof.png
|
|
373
377
|
:alt: SWOF Relative Permeability Curves
|
|
374
378
|
|
|
375
379
|
|
|
@@ -38,7 +38,7 @@ class component_library:
|
|
|
38
38
|
def __init__(self, model='PR79'):
|
|
39
39
|
path = 'component_library.xlsx'
|
|
40
40
|
#filepath = pkg_resources.resource_filename(__name__, path)
|
|
41
|
-
filepath = str(files(
|
|
41
|
+
filepath = str(files('pyrestoolbox.library').joinpath(path))
|
|
42
42
|
self.df = pd.read_excel(filepath, engine="openpyxl")
|
|
43
43
|
self.model = model
|
|
44
44
|
self.all_cols = ['Name', 'MW', 'Tc_R', 'Pc_psia',
|
|
@@ -82,4 +82,12 @@ class component_library:
|
|
|
82
82
|
return dic[prop][comp]
|
|
83
83
|
return 'Component or Property not in library'
|
|
84
84
|
|
|
85
|
-
comp_library = component_library()
|
|
85
|
+
comp_library = component_library()
|
|
86
|
+
|
|
87
|
+
# Module-level convenience aliases matching documented API
|
|
88
|
+
prop = comp_library.prop
|
|
89
|
+
components = comp_library.components
|
|
90
|
+
names = comp_library.names
|
|
91
|
+
property_list = comp_library.property_list
|
|
92
|
+
models = comp_library.models
|
|
93
|
+
df = comp_library.df
|
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Tests for every documented code example in the RST documentation files.
|
|
4
|
+
Ensures that documented API calls actually work and return expected results.
|
|
5
|
+
Run with: PYTHONPATH=/home/mark/projects python3 -m pytest tests/test_doc_examples.py -v
|
|
6
|
+
Or standalone: PYTHONPATH=/home/mark/projects python3 tests/test_doc_examples.py
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
14
|
+
import pyrestoolbox.gas as gas
|
|
15
|
+
import pyrestoolbox.oil as oil
|
|
16
|
+
import pyrestoolbox.brine as brine
|
|
17
|
+
import pyrestoolbox.layer as layer
|
|
18
|
+
import pyrestoolbox.simtools as simtools
|
|
19
|
+
import pyrestoolbox.library as library
|
|
20
|
+
|
|
21
|
+
RTOL = 1e-4 # Relative tolerance for floating point comparisons
|
|
22
|
+
|
|
23
|
+
# =============================================================================
|
|
24
|
+
# Gas Module Documentation Examples (docs/gas.rst)
|
|
25
|
+
# =============================================================================
|
|
26
|
+
|
|
27
|
+
def test_doc_gas_z_dak_pmc():
|
|
28
|
+
"""gas.rst: gas_z with DAK/PMC for sg=0.68"""
|
|
29
|
+
result = gas.gas_z(p=2350, sg=0.68, degf=180, zmethod='DAK', cmethod='PMC')
|
|
30
|
+
assert isinstance(result, float)
|
|
31
|
+
assert abs(result - 0.8785399927100872) / 0.8785399927100872 < RTOL
|
|
32
|
+
|
|
33
|
+
def test_doc_gas_z_bur_co2():
|
|
34
|
+
"""gas.rst: gas_z for pure CO2 with BUR method"""
|
|
35
|
+
result = gas.gas_z(p=2350, sg=0.68, degf=180, co2=1.0, zmethod='BUR', cmethod='BUR')
|
|
36
|
+
assert isinstance(result, float)
|
|
37
|
+
assert abs(result - 0.5258309021348752) / 0.5258309021348752 < RTOL
|
|
38
|
+
|
|
39
|
+
def test_doc_gas_sg():
|
|
40
|
+
"""gas.rst: gas_sg for mixture with H2"""
|
|
41
|
+
result = gas.gas_sg(hc_mw=19.0, co2=0.05, h2s=0.10, n2=0, h2=0.20)
|
|
42
|
+
assert isinstance(result, float)
|
|
43
|
+
assert abs(result - 0.6338246461857093) / 0.6338246461857093 < RTOL
|
|
44
|
+
|
|
45
|
+
def test_doc_gas_z_bur_mixture():
|
|
46
|
+
"""gas.rst: gas_z BUR for complex mixture"""
|
|
47
|
+
gsg = gas.gas_sg(hc_mw=19.0, co2=0.05, h2s=0.10, n2=0, h2=0.20)
|
|
48
|
+
result = gas.gas_z(p=2350, sg=gsg, degf=180, co2=0.05, h2s=0.10, n2=0, h2=0.20, zmethod='BUR', cmethod='BUR')
|
|
49
|
+
assert isinstance(result, float)
|
|
50
|
+
assert abs(result - 0.9048153036714465) / 0.9048153036714465 < RTOL
|
|
51
|
+
|
|
52
|
+
def test_doc_gas_tc_pc_pmc():
|
|
53
|
+
"""gas.rst: gas_tc_pc with PMC defaults"""
|
|
54
|
+
tc, pc = gas.gas_tc_pc(sg=0.7, co2=0.15)
|
|
55
|
+
assert abs(tc - 363.9387708314338) / 363.9387708314338 < RTOL
|
|
56
|
+
assert abs(pc - 738.3190067714969) / 738.3190067714969 < RTOL
|
|
57
|
+
|
|
58
|
+
def test_doc_gas_tc_pc_sut_fixed_tc():
|
|
59
|
+
"""gas.rst: gas_tc_pc with SUT and fixed tc"""
|
|
60
|
+
tc, pc = gas.gas_tc_pc(sg=0.7, co2=0.15, tc=365, cmethod='SUT')
|
|
61
|
+
assert tc == 365 # Should be returned unchanged
|
|
62
|
+
assert abs(pc - 709.2356299485114) / 709.2356299485114 < RTOL
|
|
63
|
+
|
|
64
|
+
def test_doc_gas_z_n2_co2():
|
|
65
|
+
"""gas.rst: gas_z with N2 and CO2"""
|
|
66
|
+
result = gas.gas_z(p=1000, sg=0.75, degf=160, n2=0.02, co2=0.17)
|
|
67
|
+
assert isinstance(result, float)
|
|
68
|
+
assert abs(result - 0.9138558878125714) / 0.9138558878125714 < RTOL
|
|
69
|
+
|
|
70
|
+
def test_doc_gas_z_hy():
|
|
71
|
+
"""gas.rst: gas_z with HY method"""
|
|
72
|
+
result = gas.gas_z(p=1000, sg=0.75, degf=160, n2=0.02, co2=0.17, zmethod='HY')
|
|
73
|
+
assert isinstance(result, float)
|
|
74
|
+
assert abs(result - 0.9142136711443208) / 0.9142136711443208 < RTOL
|
|
75
|
+
|
|
76
|
+
def test_doc_gas_z_sut_array():
|
|
77
|
+
"""gas.rst: gas_z array with SUT"""
|
|
78
|
+
result = gas.gas_z(p=[1000, 2000], sg=0.75, degf=160, cmethod='SUT', n2=0.02, co2=0.17)
|
|
79
|
+
assert isinstance(result, np.ndarray)
|
|
80
|
+
assert len(result) == 2
|
|
81
|
+
expected = np.array([0.91900003, 0.87160514])
|
|
82
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
83
|
+
|
|
84
|
+
def test_doc_gas_ug_hy_sut():
|
|
85
|
+
"""gas.rst: gas_ug with HY/SUT"""
|
|
86
|
+
result = gas.gas_ug(p=1000, sg=0.75, degf=180, zmethod='HY', cmethod='SUT')
|
|
87
|
+
assert isinstance(result, float)
|
|
88
|
+
assert abs(result - 0.014118890100250796) / 0.014118890100250796 < RTOL
|
|
89
|
+
|
|
90
|
+
def test_doc_gas_ug_default():
|
|
91
|
+
"""gas.rst: gas_ug with defaults"""
|
|
92
|
+
result = gas.gas_ug(p=1000, sg=0.75, degf=180)
|
|
93
|
+
assert isinstance(result, float)
|
|
94
|
+
assert abs(result - 0.014110092961853301) / 0.014110092961853301 < RTOL
|
|
95
|
+
|
|
96
|
+
def test_doc_gas_cg_scalar():
|
|
97
|
+
"""gas.rst: gas_cg scalar"""
|
|
98
|
+
result = gas.gas_cg(p=2000, sg=0.68, degf=120, co2=0.05)
|
|
99
|
+
assert isinstance(result, float)
|
|
100
|
+
assert abs(result - 0.0005374854430839333) / 0.0005374854430839333 < RTOL
|
|
101
|
+
|
|
102
|
+
def test_doc_gas_cg_array():
|
|
103
|
+
"""gas.rst: gas_cg array"""
|
|
104
|
+
result = gas.gas_cg(p=np.array([1000, 2000]), sg=0.68, degf=120, co2=0.05)
|
|
105
|
+
assert isinstance(result, np.ndarray)
|
|
106
|
+
expected = np.array([0.00110369, 0.00053749])
|
|
107
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
108
|
+
|
|
109
|
+
def test_doc_gas_bg_scalar():
|
|
110
|
+
"""gas.rst: gas_bg scalar"""
|
|
111
|
+
result = gas.gas_bg(p=3000, sg=0.78, degf=240)
|
|
112
|
+
assert isinstance(result, float)
|
|
113
|
+
assert abs(result - 0.005927563975073749) / 0.005927563975073749 < RTOL
|
|
114
|
+
|
|
115
|
+
def test_doc_gas_bg_array_inverse():
|
|
116
|
+
"""gas.rst: 1/gas_bg array"""
|
|
117
|
+
result = 1 / gas.gas_bg(p=[3000, 5000], sg=0.78, degf=240)
|
|
118
|
+
assert isinstance(result, np.ndarray)
|
|
119
|
+
expected = np.array([168.70336688, 249.54573283])
|
|
120
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
121
|
+
|
|
122
|
+
def test_doc_gas_den():
|
|
123
|
+
"""gas.rst: gas_den with impurities"""
|
|
124
|
+
result = gas.gas_den(p=2000, sg=0.75, degf=150, zmethod='HY', cmethod='SUT', n2=0.02, co2=0.15, h2s=0.02)
|
|
125
|
+
assert isinstance(result, float)
|
|
126
|
+
assert abs(result - 7.736656004563576) / 7.736656004563576 < RTOL
|
|
127
|
+
|
|
128
|
+
def test_doc_gas_water_content():
|
|
129
|
+
"""gas.rst: gas_water_content"""
|
|
130
|
+
result = gas.gas_water_content(p=1500, degf=165)
|
|
131
|
+
assert isinstance(result, float)
|
|
132
|
+
assert abs(result - 0.6474226409378979) / 0.6474226409378979 < RTOL
|
|
133
|
+
|
|
134
|
+
def test_doc_gas_ponz2p_scalar():
|
|
135
|
+
"""gas.rst: gas_ponz2p scalar"""
|
|
136
|
+
result = gas.gas_ponz2p(poverz=2500, sg=0.75, degf=165)
|
|
137
|
+
assert isinstance(result, float)
|
|
138
|
+
assert abs(result - 2081.5489292144775) / 2081.5489292144775 < RTOL
|
|
139
|
+
|
|
140
|
+
def test_doc_gas_ponz2p_array():
|
|
141
|
+
"""gas.rst: gas_ponz2p array"""
|
|
142
|
+
result = gas.gas_ponz2p(poverz=[2500, 5000], sg=0.75, degf=165)
|
|
143
|
+
assert isinstance(result, np.ndarray)
|
|
144
|
+
expected = np.array([2081.54892921, 4856.97983205])
|
|
145
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
146
|
+
|
|
147
|
+
def test_doc_gas_grad2sg():
|
|
148
|
+
"""gas.rst: gas_grad2sg"""
|
|
149
|
+
result = gas.gas_grad2sg(grad=0.0657, p=2500, degf=175)
|
|
150
|
+
assert isinstance(result, float)
|
|
151
|
+
assert abs(result - 0.7495803994806547) / 0.7495803994806547 < RTOL
|
|
152
|
+
|
|
153
|
+
def test_doc_gas_dmp_positive():
|
|
154
|
+
"""gas.rst: gas_dmp positive (p1 < p2)"""
|
|
155
|
+
result = gas.gas_dmp(p1=1000, p2=2000, degf=185, sg=0.78, zmethod='HY', cmethod='SUT', n2=0.05, co2=0.1, h2s=0.02)
|
|
156
|
+
assert isinstance(result, float)
|
|
157
|
+
assert result > 0
|
|
158
|
+
assert abs(result - 213690308.9907268) / 213690308.9907268 < RTOL
|
|
159
|
+
|
|
160
|
+
def test_doc_gas_dmp_negative():
|
|
161
|
+
"""gas.rst: gas_dmp negative (p1 > p2) with fixed tc/pc"""
|
|
162
|
+
result = gas.gas_dmp(p1=2000, p2=1000, degf=185, sg=0.78, tc=371, pc=682)
|
|
163
|
+
assert isinstance(result, float)
|
|
164
|
+
assert result < 0
|
|
165
|
+
assert abs(result - (-213713909.36339885)) / 213713909.36339885 < RTOL
|
|
166
|
+
|
|
167
|
+
def test_doc_gas_fws_sg():
|
|
168
|
+
"""gas.rst: gas_fws_sg"""
|
|
169
|
+
result = gas.gas_fws_sg(sg_g=0.855, cgr=30, api_st=53)
|
|
170
|
+
assert isinstance(result, float)
|
|
171
|
+
assert abs(result - 0.937116010334538) / 0.937116010334538 < RTOL
|
|
172
|
+
|
|
173
|
+
def test_doc_gas_rate_radial_scalar():
|
|
174
|
+
"""gas.rst: gas_rate_radial scalar"""
|
|
175
|
+
result = gas.gas_rate_radial(k=5, h=50, pr=2000, pwf=750, r_w=0.3, r_ext=1500, degf=180, sg=0.75, D=0.01, S=5)
|
|
176
|
+
assert isinstance(result, float)
|
|
177
|
+
assert abs(result - 2078.9101970773477) / 2078.9101970773477 < RTOL
|
|
178
|
+
|
|
179
|
+
def test_doc_gas_rate_radial_array():
|
|
180
|
+
"""gas.rst: gas_rate_radial array"""
|
|
181
|
+
result = gas.gas_rate_radial(k=1, h=50, pr=[2000, 1000], pwf=750, r_w=0.3, r_ext=1500, degf=180, sg=0.75, D=0.01, S=5)
|
|
182
|
+
assert isinstance(result, np.ndarray)
|
|
183
|
+
expected = np.array([704.29202227, 135.05317439])
|
|
184
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
185
|
+
|
|
186
|
+
def test_doc_gas_rate_linear_scalar():
|
|
187
|
+
"""gas.rst: gas_rate_linear scalar"""
|
|
188
|
+
result = gas.gas_rate_linear(k=0.1, area=50, length=200, pr=2000, pwf=250, degf=180, sg=0.8)
|
|
189
|
+
assert isinstance(result, float)
|
|
190
|
+
assert abs(result - 8.202200317597859) / 8.202200317597859 < RTOL
|
|
191
|
+
|
|
192
|
+
def test_doc_gas_rate_linear_array():
|
|
193
|
+
"""gas.rst: gas_rate_linear array"""
|
|
194
|
+
result = gas.gas_rate_linear(k=0.1, area=50, length=200, pr=[2000, 1000, 500], pwf=250, degf=180, sg=0.8)
|
|
195
|
+
assert isinstance(result, np.ndarray)
|
|
196
|
+
expected = np.array([8.20220032, 2.10691337, 0.42685002])
|
|
197
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
198
|
+
|
|
199
|
+
# =============================================================================
|
|
200
|
+
# Oil Module Documentation Examples (docs/oil.rst)
|
|
201
|
+
# =============================================================================
|
|
202
|
+
|
|
203
|
+
def test_doc_oil_ja_sg():
|
|
204
|
+
"""oil.rst: oil_ja_sg"""
|
|
205
|
+
result = oil.oil_ja_sg(mw=150, ja=0.5)
|
|
206
|
+
assert isinstance(result, float)
|
|
207
|
+
assert abs(result - 0.8583666666666667) / 0.8583666666666667 < RTOL
|
|
208
|
+
|
|
209
|
+
def test_doc_oil_twu_props():
|
|
210
|
+
"""oil.rst: oil_twu_props"""
|
|
211
|
+
result = oil.oil_twu_props(mw=225, ja=0.5)
|
|
212
|
+
assert isinstance(result, tuple)
|
|
213
|
+
assert len(result) == 5
|
|
214
|
+
expected = (0.8954444444444445, 1068.3961103813851, 1422.4620493584146, 264.23402773211745, 13.498328588856445)
|
|
215
|
+
for r, e in zip(result, expected):
|
|
216
|
+
assert abs(float(r) - e) / abs(e) < RTOL
|
|
217
|
+
|
|
218
|
+
def test_doc_oil_rs_st():
|
|
219
|
+
"""oil.rst: oil_rs_st"""
|
|
220
|
+
result = oil.oil_rs_st(psp=114.7, degf_sp=80, api=38)
|
|
221
|
+
assert isinstance(result, float)
|
|
222
|
+
assert abs(result - 4.176458005559282) / 4.176458005559282 < RTOL
|
|
223
|
+
|
|
224
|
+
def test_doc_oil_pbub_valmc():
|
|
225
|
+
"""oil.rst: oil_pbub with VALMC default"""
|
|
226
|
+
result = oil.oil_pbub(api=43, degf=185, rsb=2350, sg_g=0.72)
|
|
227
|
+
assert isinstance(result, float)
|
|
228
|
+
assert abs(result - 5199.2406069808885) / 5199.2406069808885 < RTOL
|
|
229
|
+
|
|
230
|
+
def test_doc_oil_pbub_stan():
|
|
231
|
+
"""oil.rst: oil_pbub with Standing via sg_sp"""
|
|
232
|
+
result = oil.oil_pbub(api=43, degf=185, rsb=2350, sg_sp=0.72, pbmethod='STAN')
|
|
233
|
+
assert isinstance(result, float)
|
|
234
|
+
assert abs(result - 6390.281894698239) / 6390.281894698239 < RTOL
|
|
235
|
+
|
|
236
|
+
def test_doc_oil_pbub_class_object():
|
|
237
|
+
"""oil.rst: oil_pbub using class object"""
|
|
238
|
+
result = oil.oil_pbub(api=43, degf=185, rsb=2350, sg_g=0.72, pbmethod=oil.pb_method.STAN)
|
|
239
|
+
assert isinstance(result, float)
|
|
240
|
+
assert result > 0
|
|
241
|
+
|
|
242
|
+
def test_doc_oil_rs_bub():
|
|
243
|
+
"""oil.rst: oil_rs_bub"""
|
|
244
|
+
result = oil.oil_rs_bub(api=43, degf=185, pb=5179.5, sg_sp=0.72)
|
|
245
|
+
assert isinstance(result, float)
|
|
246
|
+
assert abs(result - 1872.666133282599) / 1872.666133282599 < RTOL
|
|
247
|
+
|
|
248
|
+
def test_doc_oil_rs_with_pb_rsb():
|
|
249
|
+
"""oil.rst: oil_rs with both pb and rsb"""
|
|
250
|
+
result = oil.oil_rs(api=43, degf=185, sg_sp=0.72, p=3000, pb=5179.5, rsb=2370)
|
|
251
|
+
assert isinstance(result, float)
|
|
252
|
+
assert abs(result - 1017.9424383646037) / 1017.9424383646037 < RTOL
|
|
253
|
+
|
|
254
|
+
def test_doc_oil_rs_with_rsb_only():
|
|
255
|
+
"""oil.rst: oil_rs with rsb only"""
|
|
256
|
+
result = oil.oil_rs(api=43, degf=185, sg_sp=0.72, p=3000, rsb=2370)
|
|
257
|
+
assert isinstance(result, float)
|
|
258
|
+
assert abs(result - 1010.0669567201218) / 1010.0669567201218 < RTOL
|
|
259
|
+
|
|
260
|
+
def test_doc_oil_rs_with_pb_only():
|
|
261
|
+
"""oil.rst: oil_rs with pb only"""
|
|
262
|
+
result = oil.oil_rs(api=43, degf=185, sg_sp=0.72, p=3000, pb=5180)
|
|
263
|
+
assert isinstance(result, float)
|
|
264
|
+
assert abs(result - 804.2857187814161) / 804.2857187814161 < RTOL
|
|
265
|
+
|
|
266
|
+
def test_doc_oil_rs_stan():
|
|
267
|
+
"""oil.rst: oil_rs with Standing method"""
|
|
268
|
+
result = oil.oil_rs(api=43, degf=185, sg_sp=0.72, p=3000, pb=5180, rsmethod='STAN')
|
|
269
|
+
assert isinstance(result, float)
|
|
270
|
+
assert abs(result - 947.1133546937306) / 947.1133546937306 < RTOL
|
|
271
|
+
|
|
272
|
+
def test_doc_oil_co_above_pb():
|
|
273
|
+
"""oil.rst: oil_co above bubble point"""
|
|
274
|
+
result = oil.oil_co(p=4500, api=47, degf=180, sg_sp=0.72, rsb=2750)
|
|
275
|
+
assert isinstance(result, float)
|
|
276
|
+
assert abs(result - 0.0007587726853322233) / 0.0007587726853322233 < RTOL
|
|
277
|
+
|
|
278
|
+
def test_doc_oil_co_below_pb():
|
|
279
|
+
"""oil.rst: oil_co below bubble point"""
|
|
280
|
+
result = oil.oil_co(p=2000, api=47, degf=180, sg_sp=0.72, rsb=2750, pb=4945)
|
|
281
|
+
assert isinstance(result, float)
|
|
282
|
+
assert abs(result - 0.0009245540028053584) / 0.0009245540028053584 < RTOL
|
|
283
|
+
|
|
284
|
+
def test_doc_oil_deno():
|
|
285
|
+
"""oil.rst: oil_deno"""
|
|
286
|
+
result = oil.oil_deno(p=2000, degf=165, rs=1000, rsb=2000, sg_g=0.72, api=38)
|
|
287
|
+
assert isinstance(result, float)
|
|
288
|
+
assert abs(result - 40.98349866963842) / 40.98349866963842 < RTOL
|
|
289
|
+
|
|
290
|
+
def test_doc_oil_bo_mcain():
|
|
291
|
+
"""oil.rst: oil_bo with McCain default"""
|
|
292
|
+
result = oil.oil_bo(p=2000, pb=3000, degf=165, rs=1000, rsb=2000, sg_o=0.8, sg_g=0.68)
|
|
293
|
+
assert isinstance(result, float)
|
|
294
|
+
assert abs(result - 1.5075107735318138) / 1.5075107735318138 < RTOL
|
|
295
|
+
|
|
296
|
+
def test_doc_oil_bo_stan():
|
|
297
|
+
"""oil.rst: oil_bo with Standing"""
|
|
298
|
+
result = oil.oil_bo(p=2000, pb=3000, degf=165, rs=1000, rsb=2000, sg_o=0.8, sg_g=0.68, bomethod='STAN')
|
|
299
|
+
assert isinstance(result, float)
|
|
300
|
+
assert abs(result - 1.5393786735904431) / 1.5393786735904431 < RTOL
|
|
301
|
+
|
|
302
|
+
def test_doc_oil_viso():
|
|
303
|
+
"""oil.rst: oil_viso"""
|
|
304
|
+
result = oil.oil_viso(p=2000, api=38, degf=165, pb=3500, rs=1000)
|
|
305
|
+
assert isinstance(result, float)
|
|
306
|
+
assert abs(result - 0.416858469042502) / 0.416858469042502 < RTOL
|
|
307
|
+
|
|
308
|
+
def test_doc_sg_evolved_gas():
|
|
309
|
+
"""oil.rst: sg_evolved_gas"""
|
|
310
|
+
result = oil.sg_evolved_gas(p=2000, degf=185, rsb=2370, api=43, sg_sp=0.72)
|
|
311
|
+
assert isinstance(result, float)
|
|
312
|
+
assert abs(result - 0.7872810977386344) / 0.7872810977386344 < RTOL
|
|
313
|
+
|
|
314
|
+
def test_doc_sg_st_gas():
|
|
315
|
+
"""oil.rst: sg_st_gas"""
|
|
316
|
+
result = oil.sg_st_gas(114.7, rsp=1500, api=42, sg_sp=0.72, degf_sp=80)
|
|
317
|
+
assert isinstance(result, float)
|
|
318
|
+
assert abs(result - 1.1923932340625523) / 1.1923932340625523 < RTOL
|
|
319
|
+
|
|
320
|
+
def test_doc_sgg_wt_avg():
|
|
321
|
+
"""oil.rst: sgg_wt_avg"""
|
|
322
|
+
result = oil.sgg_wt_avg(sg_sp=0.72, rsp=1000, sg_st=1.1, rst=5)
|
|
323
|
+
assert isinstance(result, float)
|
|
324
|
+
assert abs(result - 0.7218905472636816) / 0.7218905472636816 < RTOL
|
|
325
|
+
|
|
326
|
+
def test_doc_oil_api():
|
|
327
|
+
"""oil.rst: oil_api"""
|
|
328
|
+
result = oil.oil_api(sg_value=0.82)
|
|
329
|
+
assert isinstance(result, float)
|
|
330
|
+
assert abs(result - 41.0609756097561) / 41.0609756097561 < RTOL
|
|
331
|
+
|
|
332
|
+
def test_doc_oil_sg():
|
|
333
|
+
"""oil.rst: oil_sg"""
|
|
334
|
+
result = oil.oil_sg(api_value=45)
|
|
335
|
+
assert isinstance(result, float)
|
|
336
|
+
assert abs(result - 0.8016997167138811) / 0.8016997167138811 < RTOL
|
|
337
|
+
|
|
338
|
+
def test_doc_oil_rate_radial_scalar():
|
|
339
|
+
"""oil.rst: oil_rate_radial scalar with Vogel"""
|
|
340
|
+
result = oil.oil_rate_radial(k=20, h=20, pr=1500, pwf=250, r_w=0.3, r_ext=1500, uo=0.8, bo=1.4, vogel=True, pb=1800)
|
|
341
|
+
assert isinstance(result, float)
|
|
342
|
+
assert abs(result - 213.8147848023242) / 213.8147848023242 < RTOL
|
|
343
|
+
|
|
344
|
+
def test_doc_oil_rate_radial_array():
|
|
345
|
+
"""oil.rst: oil_rate_radial array with Vogel"""
|
|
346
|
+
result = oil.oil_rate_radial(k=20, h=20, pr=[1500, 2000], pwf=250, r_w=0.3, r_ext=1500, uo=0.8, bo=1.4, vogel=True, pb=1800)
|
|
347
|
+
assert isinstance(result, np.ndarray)
|
|
348
|
+
expected = np.array([213.8147848, 376.58731835])
|
|
349
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
350
|
+
|
|
351
|
+
def test_doc_oil_rate_linear_scalar():
|
|
352
|
+
"""oil.rst: oil_rate_linear scalar"""
|
|
353
|
+
result = oil.oil_rate_linear(k=0.1, area=15000, pr=3000, pwf=500, length=500, uo=0.4, bo=1.5)
|
|
354
|
+
assert isinstance(result, float)
|
|
355
|
+
assert abs(result - 14.08521246363274) / 14.08521246363274 < RTOL
|
|
356
|
+
|
|
357
|
+
def test_doc_oil_rate_linear_array():
|
|
358
|
+
"""oil.rst: oil_rate_linear array"""
|
|
359
|
+
result = oil.oil_rate_linear(k=[0.1, 1, 5, 10], area=15000, pr=3000, pwf=500, length=500, uo=0.4, bo=1.5)
|
|
360
|
+
assert isinstance(result, np.ndarray)
|
|
361
|
+
expected = np.array([14.08521246, 140.85212464, 704.26062318, 1408.52124636])
|
|
362
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
363
|
+
|
|
364
|
+
def test_doc_make_bot_og():
|
|
365
|
+
"""oil.rst: make_bot_og returns correct structure"""
|
|
366
|
+
results = oil.make_bot_og(pvto=False, pi=4000, api=38, degf=175, sg_g=0.68, pmax=5500, pb=4500, nrows=10, export=False)
|
|
367
|
+
assert isinstance(results, dict)
|
|
368
|
+
for key in ['bot', 'deno', 'deng', 'denw', 'cw', 'uw', 'pb', 'rsb', 'rsb_scale', 'usat']:
|
|
369
|
+
assert key in results, f"Missing key: {key}"
|
|
370
|
+
assert results['pb'] == 4500
|
|
371
|
+
assert results['bot'].shape[0] == 10
|
|
372
|
+
|
|
373
|
+
# =============================================================================
|
|
374
|
+
# Brine Module Documentation Examples (docs/brine.rst)
|
|
375
|
+
# =============================================================================
|
|
376
|
+
|
|
377
|
+
def test_doc_brine_props():
|
|
378
|
+
"""brine.rst: brine_props"""
|
|
379
|
+
bw, lsg, visw, cw, rsw = brine.brine_props(p=160, degf=135, wt=1.5, ch4_sat=1.0)
|
|
380
|
+
assert abs(bw - 1.0151710978322923) / 1.0151710978322923 < RTOL
|
|
381
|
+
assert abs(lsg - 0.9950036658248123) / 0.9950036658248123 < RTOL
|
|
382
|
+
assert abs(visw - 0.4993957925685823) / 0.4993957925685823 < RTOL
|
|
383
|
+
assert abs(cw - 0.00015465242842085548) / 0.00015465242842085548 < RTOL
|
|
384
|
+
assert abs(rsw - 1.2548933067431638) / 1.2548933067431638 < RTOL
|
|
385
|
+
|
|
386
|
+
def test_doc_co2_brine_field():
|
|
387
|
+
"""brine.rst: CO2_Brine_Mixture field units"""
|
|
388
|
+
mix = brine.CO2_Brine_Mixture(pres=5000, temp=275, ppm=30000, metric=False)
|
|
389
|
+
assert isinstance(mix.bw, list)
|
|
390
|
+
assert len(mix.bw) == 3
|
|
391
|
+
assert abs(float(mix.bw[0]) - 1.108579075130017) / 1.108579075130017 < RTOL
|
|
392
|
+
assert isinstance(mix.x, np.ndarray)
|
|
393
|
+
assert abs(mix.x[0] - 0.02431225) / 0.02431225 < RTOL
|
|
394
|
+
|
|
395
|
+
def test_doc_co2_brine_metric():
|
|
396
|
+
"""brine.rst: CO2_Brine_Mixture metric units"""
|
|
397
|
+
mix = brine.CO2_Brine_Mixture(pres=175, temp=85)
|
|
398
|
+
assert abs(mix.Rs - 24.742717860296057) / 24.742717860296057 < RTOL
|
|
399
|
+
|
|
400
|
+
def test_doc_make_pvtw_table():
|
|
401
|
+
"""brine.rst: make_pvtw_table"""
|
|
402
|
+
result = brine.make_pvtw_table(pi=3000, degf=200, wt=0, ch4_sat=0)
|
|
403
|
+
assert isinstance(result, dict)
|
|
404
|
+
for key in ['table', 'pref', 'bw_ref', 'cw_ref', 'visw_ref', 'rsw_ref', 'den_ref']:
|
|
405
|
+
assert key in result, f"Missing key: {key}"
|
|
406
|
+
assert abs(result['bw_ref'] - 1.0275744009507692) / 1.0275744009507692 < RTOL
|
|
407
|
+
|
|
408
|
+
# =============================================================================
|
|
409
|
+
# Layer Module Documentation Examples (docs/layer.rst)
|
|
410
|
+
# =============================================================================
|
|
411
|
+
|
|
412
|
+
def test_doc_lorenz2b_lang():
|
|
413
|
+
"""layer.rst: lorenz2b with Langmuir"""
|
|
414
|
+
result = layer.lorenz2b(0.75, lrnz_method='LANG')
|
|
415
|
+
assert abs(result - 16.139518537603912) / 16.139518537603912 < RTOL
|
|
416
|
+
|
|
417
|
+
def test_doc_lorenz2b_exp():
|
|
418
|
+
"""layer.rst: lorenz2b with Exponential default"""
|
|
419
|
+
result = layer.lorenz2b(0.75)
|
|
420
|
+
assert abs(result - 7.978108090962671) / 7.978108090962671 < RTOL
|
|
421
|
+
|
|
422
|
+
def test_doc_lorenzfromb_lang():
|
|
423
|
+
"""layer.rst: lorenzfromb with Langmuir"""
|
|
424
|
+
result = layer.lorenzfromb(16.139518537603912, lrnz_method='LANG')
|
|
425
|
+
assert abs(result - 0.750000182307895) / 0.750000182307895 < RTOL
|
|
426
|
+
|
|
427
|
+
def test_doc_lorenzfromb_exp():
|
|
428
|
+
"""layer.rst: lorenzfromb with Exponential default"""
|
|
429
|
+
result = layer.lorenzfromb(7.978108090962671)
|
|
430
|
+
assert abs(result - 0.7500000108799212) / 0.7500000108799212 < RTOL
|
|
431
|
+
|
|
432
|
+
def test_doc_lorenz_from_flow_fraction():
|
|
433
|
+
"""layer.rst: lorenz_from_flow_fraction"""
|
|
434
|
+
result = layer.lorenz_from_flow_fraction(kh_frac=0.6, phih_frac=0.15)
|
|
435
|
+
assert abs(result - 0.6759312029093838) / 0.6759312029093838 < RTOL
|
|
436
|
+
|
|
437
|
+
def test_doc_lorenz_2_flow_frac():
|
|
438
|
+
"""layer.rst: lorenz_2_flow_frac"""
|
|
439
|
+
result = layer.lorenz_2_flow_frac(lorenz=0.6759312029093838, phih_frac=0.15)
|
|
440
|
+
assert abs(result - 0.6000001346893536) / 0.6000001346893536 < RTOL
|
|
441
|
+
|
|
442
|
+
def test_doc_lorenz_2_layers_nlayers():
|
|
443
|
+
"""layer.rst: lorenz_2_layers with nlayers"""
|
|
444
|
+
result = layer.lorenz_2_layers(lorenz=0.67, nlayers=5, k_avg=10, shuffle=False)
|
|
445
|
+
assert isinstance(result, np.ndarray)
|
|
446
|
+
assert len(result) == 5
|
|
447
|
+
# With shuffle=False, should be sorted descending
|
|
448
|
+
assert all(result[i] >= result[i+1] for i in range(len(result)-1))
|
|
449
|
+
# Average should be close to 10
|
|
450
|
+
assert abs(np.mean(result) - 10) / 10 < 0.01
|
|
451
|
+
expected = np.array([34.9323596, 10.58944038, 3.21009656, 0.9731128, 0.29499066])
|
|
452
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
453
|
+
|
|
454
|
+
def test_doc_lorenz_2_layers_phi_h_fracs():
|
|
455
|
+
"""layer.rst: lorenz_2_layers with phi_h_fracs"""
|
|
456
|
+
result = layer.lorenz_2_layers(lorenz=0.67, k_avg=10, phi_h_fracs=[0.05, 0.5])
|
|
457
|
+
assert isinstance(result, np.ndarray)
|
|
458
|
+
assert len(result) == 3
|
|
459
|
+
expected = np.array([51.72990694, 14.12556056, 0.77938749])
|
|
460
|
+
np.testing.assert_allclose(result, expected, rtol=RTOL)
|
|
461
|
+
|
|
462
|
+
# =============================================================================
|
|
463
|
+
# SimTools Module Documentation Examples (docs/simtools.rst)
|
|
464
|
+
# =============================================================================
|
|
465
|
+
|
|
466
|
+
def test_doc_rel_perm_table_sgof():
|
|
467
|
+
"""simtools.rst: rel_perm_table SGOF with LET"""
|
|
468
|
+
df = simtools.rel_perm_table(rows=25, krtable='SGOF', krfamily='LET', kromax=1, krgmax=1, swc=0.2, sorg=0.15, Lo=2.5, Eo=1.25, To=1.75, Lg=1.2, Eg=1.5, Tg=2.0)
|
|
469
|
+
assert 'Sg' in df.columns
|
|
470
|
+
assert 'Krgo' in df.columns
|
|
471
|
+
assert 'Krog' in df.columns
|
|
472
|
+
assert df.shape[0] >= 25
|
|
473
|
+
|
|
474
|
+
def test_doc_rel_perm_table_swof():
|
|
475
|
+
"""simtools.rst: rel_perm_table SWOF with Corey"""
|
|
476
|
+
df = simtools.rel_perm_table(rows=25, krtable='SWOF', kromax=1, krwmax=0.25, swc=0.15, swcr=0.2, sorw=0.15, no=2.5, nw=1.5)
|
|
477
|
+
assert 'Sw' in df.columns
|
|
478
|
+
assert 'Krwo' in df.columns
|
|
479
|
+
assert 'Krow' in df.columns
|
|
480
|
+
assert df.shape[0] == 25
|
|
481
|
+
|
|
482
|
+
def test_doc_rr_solver():
|
|
483
|
+
"""simtools.rst: rr_solver"""
|
|
484
|
+
n_it, yi, xi, V, L = simtools.rr_solver(zi=np.array([0.7, 0.15, 0.1, 0.05]), ki=np.array([50, 5, 0.5, 0.01]))
|
|
485
|
+
assert n_it == 6
|
|
486
|
+
assert abs(V - 0.9440279802330239) / 0.9440279802330239 < RTOL
|
|
487
|
+
assert abs(L - 0.05597201976697608) / 0.05597201976697608 < RTOL
|
|
488
|
+
expected_yi = np.array([0.7406252, 0.1570315, 0.09469948, 0.00764382])
|
|
489
|
+
expected_xi = np.array([0.0148125, 0.0314063, 0.18939896, 0.76438224])
|
|
490
|
+
np.testing.assert_allclose(yi, expected_yi, rtol=RTOL)
|
|
491
|
+
np.testing.assert_allclose(xi, expected_xi, rtol=RTOL)
|
|
492
|
+
|
|
493
|
+
# =============================================================================
|
|
494
|
+
# Library Module Documentation Examples (docs/library.rst)
|
|
495
|
+
# =============================================================================
|
|
496
|
+
|
|
497
|
+
def test_doc_library_prop_pc():
|
|
498
|
+
"""library.rst: library.prop for CH4 Pc_psia"""
|
|
499
|
+
result = library.prop(comp='CH4', prop='Pc_psia')
|
|
500
|
+
assert result == 667.029
|
|
501
|
+
|
|
502
|
+
def test_doc_library_prop_vtran_pr79():
|
|
503
|
+
"""library.rst: library.prop for C3 VTran PR79"""
|
|
504
|
+
result = library.prop(comp='C3', prop='VTran')
|
|
505
|
+
assert result == -0.06381
|
|
506
|
+
|
|
507
|
+
def test_doc_library_prop_vtran_srk():
|
|
508
|
+
"""library.rst: library.prop for C3 VTran SRK"""
|
|
509
|
+
result = library.prop(comp='C3', prop='VTran', model='SRK')
|
|
510
|
+
assert result == 0.09075
|
|
511
|
+
|
|
512
|
+
def test_doc_library_components():
|
|
513
|
+
"""library.rst: library.components is a list with CH4"""
|
|
514
|
+
assert isinstance(library.components, list)
|
|
515
|
+
assert 'CH4' in library.components
|
|
516
|
+
|
|
517
|
+
def test_doc_library_property_list():
|
|
518
|
+
"""library.rst: library.property_list"""
|
|
519
|
+
assert isinstance(library.property_list, list)
|
|
520
|
+
assert 'MW' in library.property_list
|
|
521
|
+
assert 'Tc_R' in library.property_list
|
|
522
|
+
assert 'Pc_psia' in library.property_list
|
|
523
|
+
|
|
524
|
+
def test_doc_library_models():
|
|
525
|
+
"""library.rst: library.models"""
|
|
526
|
+
assert library.models == ['PR79', 'PR77', 'SRK', 'RK']
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
# =============================================================================
|
|
530
|
+
# Main runner
|
|
531
|
+
# =============================================================================
|
|
532
|
+
|
|
533
|
+
if __name__ == '__main__':
|
|
534
|
+
import traceback
|
|
535
|
+
tests = [(k, v) for k, v in sorted(globals().items()) if k.startswith('test_') and callable(v)]
|
|
536
|
+
passed = failed = 0
|
|
537
|
+
errors = []
|
|
538
|
+
for name, func in tests:
|
|
539
|
+
try:
|
|
540
|
+
func()
|
|
541
|
+
passed += 1
|
|
542
|
+
print(f" PASS: {name}")
|
|
543
|
+
except Exception as e:
|
|
544
|
+
failed += 1
|
|
545
|
+
errors.append((name, str(e)))
|
|
546
|
+
print(f" FAIL: {name}")
|
|
547
|
+
print(f" {e}")
|
|
548
|
+
traceback.print_exc()
|
|
549
|
+
|
|
550
|
+
print(f"\n{'='*60}")
|
|
551
|
+
print(f"TOTAL: {passed} passed, {failed} failed out of {passed + failed}")
|
|
552
|
+
if errors:
|
|
553
|
+
print(f"\nFailed tests:")
|
|
554
|
+
for name, msg in errors:
|
|
555
|
+
print(f" - {name}: {msg}")
|
|
556
|
+
print("="*60)
|
|
@@ -49,6 +49,7 @@ pyrestoolbox/simtools/simtools.py
|
|
|
49
49
|
pyrestoolbox/tests/__init__.py
|
|
50
50
|
pyrestoolbox/tests/run_all_tests.py
|
|
51
51
|
pyrestoolbox/tests/test_brine.py
|
|
52
|
+
pyrestoolbox/tests/test_doc_examples.py
|
|
52
53
|
pyrestoolbox/tests/test_gas.py
|
|
53
54
|
pyrestoolbox/tests/test_layer.py
|
|
54
55
|
pyrestoolbox/tests/test_oil.py
|
|
@@ -12,7 +12,7 @@ with open(os.path.join(ROOT, 'README.md'), 'r', encoding='utf-8') as f:
|
|
|
12
12
|
setup(
|
|
13
13
|
name='pyrestoolbox',
|
|
14
14
|
include_package_data=True,
|
|
15
|
-
version='2.2.
|
|
15
|
+
version='2.2.2', # Ideally should be same as your GitHub release tag version
|
|
16
16
|
packages=find_packages(),
|
|
17
17
|
description='pyResToolbox - A collection of Reservoir Engineering Utilities',
|
|
18
18
|
license="GNU General Public License v3 or later (GPLv3+)",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|