# pyscal package¶

## pyscal.constants module¶

Constants used for pyscal modules:

• SWINTEGERS: Number of different Sw values within [0,1] we allow This is used to create integer indices of Sw, since Floating Point indices are flaky in Pandas (and in general on computers)

• EPSILON: Used as “a small number” for ensuring no floating point comparisons/errors pop up. You cannot have the h parameter less than this when generating relperm tables

• MAX_EXPONENT: Maximal number for exponents in relperm parametrizations. Used to avoid numerical instabilities. It could probably be much higher than the chosen number in most circumstances, but such high numbers should not be relevant for relative permeability

## pyscal.factory module¶

Factory functions for creating the pyscal objects

class pyscal.factory.PyscalFactory[source]

Bases: object

Class for implementing the factory pattern for Pyscal objects

The factory functions herein can take multiple parameter sets, determine what kind of parametrization to be used, and set up the full objects based on these parameters, instead of explicitly having to call the API for each task.

Example:

wo = WaterOil(sorw=0.05)
# is equivalent to:
wo = factory.create_water_oil(dict(sorw=0.05, nw=3, now=2))


Parameter names to factory functions are case insensitive, while the add_*() parameters are not. This is because the add_*() parameters are meant as a Python API, while the factory class is there to aid users when input is written in a different context, like an Excel spreadsheet.

static create_gas_oil(params=None)[source]

Create a GasOil object from a dictionary of parameters.

Parameterization (Corey/LET) is inferred from presence of certain parameters in the dictionary.

Don’t rely on behaviour of you supply both Corey and LET at the same time.

NB: the add_LET_* methods have the names ‘l’, ‘e’ and ‘t’ in their signatures, which is not precise enough in this context, so we require e.g. ‘Lg’ and ‘Log’ (which both will be translated to ‘l’).

Recognized parameters:

swirr, sgcr, sorg, swl, krgendanchor, h, tag, ng, krgend, krgmax, nog, kroend, lg, eg, tg, log, eog, tog

static create_gas_water(params=None)[source]

Create a GasWater object.

Parameterization (Corey/LET) is inferred from presence of certain parameters in the dictionary.

Parameters

params (dict) – Dictionary with parameters for GasWater.

Returns

GasWater

static create_gasoil_list(relperm_params_df, h=None)[source]

Create a PyscalList with GasOil objects from a dataframe

Parameters
• relperm_params_df (pd.DataFrame) – A valid dataframe with GasOil parameters, processed through load_relperm_df()

• h (float) – Saturation steplength

Returns

PyscalList, consisting of GasOil objects

static create_gaswater_list(relperm_params_df, h=None)[source]

Create a PyscalList with WaterOilGas objects from a dataframe, to be used for GasWater

Parameters
• relperm_params_df (pd.DataFrame) – A valid dataframe with GasWater parameters, processed through load_relperm_df()

• h (float) – Saturation steplength

Returns

PyscalList, consisting of GasWater objects

static create_pyscal_list(relperm_params_df, h=None)[source]

Create WaterOilGas, WaterOil, GasOil or GasWater list based on what is available

Parameters
• relperm_params_df (pd.DataFrame) – Input data, should have been processed through load_relperm_df().

• h (float) – Saturation step-value

Returns

PyscalList, consisting of either WaterOil, GasOil or WaterOilGas objects

static create_scal_recommendation(params, tag='', h=None)[source]

Set up a SCAL recommendation curve set from input as a dictionary of dictionary.

The keys in in the dictionary must be “low”, “base” and “high”.

The value for “low” must be a new dictionary with saturation endpoints and LET/Corey parameters, as you would feed it to the create_water_oil_gas() factory function, and then similarly for base and high.

For oil-water only, you may omit the parameters for gas-oil. A WaterOilGas object for each case is created, but only the WaterOil part of it will be used.

For gas-water, a GasWater object is created for each pess, base and high.

Parameters
• params (dict) – keys low, base and high. The value for “low” must be a new dictionary with saturation endpoints and LET/Corey parameters, as you would feed it to the create_water_oil_gas() factory function, and then similarly for base and high.

• tag (string) – String to be used as the tag, will end up in comments.

• h (float) – Saturation step length

Returns

SCALrecommendation

static create_scal_recommendation_list(input_df, h=None)[source]

Requires SATNUM and CASE to be defined in the input data

Parameters
• input_df (pd.DataFrame) – Input data, should have been processed through load_relperm_df().

• h (float) – Saturation step-value

Returns

PyscalList, consisting of SCALrecommendation objects

static create_water_oil(params=None)[source]

Create a WaterOil object from a dictionary of parameters.

Parameterization (Corey/LET) is inferred from presence of certain parameters in the dictionary.

Don’t rely on behaviour of you supply both Corey and LET at the same time.

Parameter names in the dictionary are case insensitive. You can use Swirr, swirr, sWirR, swiRR etc.

NB: the add_LET_* methods have the names ‘l’, ‘e’ and ‘t’ in their signatures, which is not precise enough in this context, so we require e.g. ‘Lw’ and ‘Low’ (which both will be translated to ‘l’)

Recognized parameters:

swirr, swl, swcr, sorw, h, tag, nw, now, krwmax, krwend, lw, ew, tw, low, eow, tow, lo, eo, to, kroend, a, a_petro, b, b_petro, poro_ref, perm_ref, drho, a, b, poro, perm, sigma_costau

Parameters

params (dict) – Dictionary with parameters describing the WaterOil object.

static create_water_oil_gas(params=None)[source]

Create a WaterOilGas object from a dictionary of parameters

Parameterization (Corey/LET) is inferred from presence of certain parameters in the dictionary.

Check create_water_oil() and create_gas_oil() for lists of supported parameters (case insensitive)

Params:

params (dict): parameteres gaswater (bool): Flag to indicate if is to be used for GasWater

static create_wateroil_list(relperm_params_df, h=None)[source]

Create a PyscalList with WaterOil objects from a dataframe

Parameters
• relperm_params_df (pd.DataFrame) – A valid dataframe with WaterOil parameters, processed through load_relperm_df()

• h (float) – Saturation steplength

Returns

PyscalList, consisting of WaterOil objects

static create_wateroilgas_list(relperm_params_df, h=None)[source]

Create a PyscalList with WaterOilGas objects from a dataframe

Parameters
• relperm_params_df (pd.DataFrame) – Input data, should have been processed through load_relperm_df().

• h (float) – Saturation step-value

Returns

PyscalList, consisting of WaterOilGas objects

static load_relperm_df(inputfile, sheet_name=None)[source]

Read CSV or XLSX from file and return scal/relperm data a dataframe.

Checks validity in SATNUM and CASE columns. Ensures case-insensitivenes SATNUM, CASE, TAG and COMMENT

Merges COMMENT into TAG column, as only TAG is picked up downstream. Adds a prexix “SATNUM <number>” to all tags.

All strings in CASE column are converted to lowercase. Applies aliasing in the CASE column so that “pessimistic” and “pess” map to “low”, and “optimistic” and “opt” map to “high”.

Parameters
• inputfile (str or pd.DataFrame) – Filename for XLSX or CSV file, or a pandas DataFrame.

• sheet_name (str) – Sheet-name, only used when loading xlsx files.

Returns

pd.DataFrame. To be handed over to pyscal list factory methods.

static remap_validate_cases(casevalues)[source]

Remap values in the CASE column so that we can use aliases.

All values are first made lower case, then “pessimistic” and “pess” are mapped to “low” and “optimistic” and “opt” are mapped to “high”.

Will raise ValueError if some values are not understood, and if we don’t have exactly three unique values.

Parameters

casevalues (list of str) – values to remap.

pyscal.factory.check_deprecated(params)[source]

Check for deprecated parameter names

Parameters

params – Dictionary of parameters for which only the keys are used here.

pyscal.factory.filter_nan_from_dict(params)[source]

Clean out keys with NaN values in a dict.

Key with string values are passed through (empty strings are allowed)

Parameters

params (dict) – Any dictionary

Returns

dict, with as many or fewer keys.

pyscal.factory.slicedict(dct, keys)[source]

Slice a dictionary for a set of keys. Keys not existing will be ignored.

pyscal.factory.sufficient_gas_oil_params(params, failhard=False)[source]

Determine if the supplied parameters are sufficient for attempting at creating a GasOil object.

In the factory context, relying on the defaults in the API is not allowed, as that would leave the tasks for the factory undefined (Corey or LET, and which pc?)

Parameters
• params (dict) – Dictionary of parameters to a GasOil object.

• failhard (bool) – If True, will raise ValueError when parameters are insufficient. If defaulted, no exception is raised.

Returns

True if a GasOil object should be attempted constructed

(but no guarantee for validity of numerical values)

pyscal.factory.sufficient_gas_water_params(params, failhard=False)[source]

Determine if the supplied parameters are sufficient for attempting creating a WaterOilGas object to be used for gas water.

In the factory context, relying on the defaults in the API (wateroilgas.py) is not allowed, as that would leave the tasks for the factory undefined (Corey or LET, and which pc?)

Parameters
• params (dict) – Dictionary of parameters to a GasWater object.

• failhard (bool) – If True, will raise ValueError when parameters are insufficient. If defaulted, no exception is raised.

Returns

True if a GasWater object should be attempted constructed

(but no guarantee for validity of numerical values)

pyscal.factory.sufficient_water_oil_params(params, failhard=False)[source]

Determine if the supplied parameters are sufficient for attempting creating a WaterOil object.

In the factory context, relying on the defaults in the API is not allowed, as that would leave the tasks for the factory undefined (Corey or LET, and which pc?)

Parameters
• params (dict) – Dictionary of parameters to a WaterOil object.

• failhard (bool) – If True, will raise ValueError when parameters are insufficient. If defaulted, no exception is raised.

Returns

True if a WaterOil object should be attempted constructed

(but no guarantee for validity of numerical values)

## pyscal.gasoil module¶

Representing a GasOil object

class pyscal.gasoil.GasOil(swirr=0, sgcr=0.0, h=0.01, swl=0.0, sorg=0.0, tag='', krgendanchor='sorg', fast=False)[source]

Bases: object

Object to represent two-phase properties for gas and oil.

Parametrizations available for relative permeability:

• Corey

• LET

or data can alternatively be read in from tabulated data (as Pandas DataFrame).

No support (yet) to add capillary pressure.

krgend is by default anchored both to 1-swl-sorg, but can be set to anchor to 1-swl instead. If the krgendanchor argument is something else than the string sorg, it will be anchored to 1-swl.

Parameters
• swirr (float) – Absolute minimal water saturation at infinite capillary pressure. Not in use currently, except for in informational headers and for consistency checks.

• swl (float) – First water saturation point in water tables. In GasOil, it is used to obtain the normalized oil and gas saturation.

• sgcr (float) – Critical gas saturation. Gas will not be mobile before the gas saturation is above this value.

• sorg (float) – Residual oil saturation after gas flooding. At this oil saturation, the oil has zero relative permeability.

• krgendanchor (str) – Set to sorg (default) or something else, where to anchor krgend. If sorg, then the normalized gas saturation will be equal to 1 at 1 - swl - sorg, if not, it will be 1 at 1 - swl. If sorg is zero it does not matter. krgmax is only relevant when this anchor is sorg.

• h (float) – Saturation step-length in the outputted table.

• tag (str) – Optional string identifier, only used in comments.

• fast (bool) – Set to True if in order to skip some integrity checks and nice-to-have features. Not needed to set for normal pyscal runs, as speed is seldom crucial. Default False

GOTABLE(header=True, dataincommentrow=True)[source]

Produce GOTABLE input for the Nexus reservoir simulator.

The columns sg, krg, krog and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SGOF string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SGOF yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

SGFN(header=True, dataincommentrow=True, sgcomment=None, crosspointcomment=None)[source]

Produce SGFN input for Eclipse reservoir simulator.

The columns sg, krg, and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SGFN string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SGFN yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

• sgcomment (str) – Provide the string to include in the comment section for describing the saturation endpoints. Used by GasWater.

• crosspointcomment (str) – String to be used for crosspoint comment string, overrides what this object can provide. Used by GasWater. If None, it will be computed, use empty string to avoid.

SGOF(header=True, dataincommentrow=True)[source]

Produce SGOF input for Eclipse reservoir simulator.

The columns sg, krg, krog and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header (bool) – Whether the SGOF string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SGOF yourself). Defaults to True.

• dataincommentrow (bool) – Whether metadata should be printed, defaults to True.

SLGOF(header=True, dataincommentrow=True)[source]

Produce SLGOF input for Eclipse reservoir simulator.

The columns sl (liquid saturation), krg, krog and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SLGOF string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SGOF yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

add_LET_gas(l=2, e=2, t=2, krgend=1, krgmax=None)[source]

Add gas relative permability data through the LET parametrization

A column called ‘krg’ will be added, replaced if it does not exist

If krgendanchor is sorg, the LET curve ends at krgend at sg = 1 - swl - sorg, and then linear up to krgmax at sg = 1 - swl. If not, it ends at krgend at sg = 1 - swl.

Parameters
• l (float) – L parameter in LET

• e (float) – E parameter in LET

• t (float) – T parameter in LET

• krgend (float) – Value of krg at normalized gas saturation 1

• krgmax (float) – Value of krg at gas saturation 1

Returns

None (modifies internal state)

add_LET_oil(l=2, e=2, t=2, kroend=1, kromax=None)[source]

Add oil (vs gas) relative permeability data through the Corey parametrization.

A column named ‘krog’ will be added, replaced if it exists.

All values where sg > 1 - sorg - swl are set to zero.

Parameters
• l (float) – L parameter

• e (float) – E parameter

• t (float) – T parameter

• kroend (float) – The value at gas saturation sgcr

add_corey_gas(ng=2, krgend=1, krgmax=None)[source]

Add krg data through the Corey parametrization

A column called ‘krg’ will be added. If it exists, it will be replaced.

If krgendanchor is sorg, the Corey curve ends at krgend at sg = 1 - swl - sorg, and then linear up to krgmax at sg = 1 - swl. If not, it ends at krgend at sg = 1 - swl.

krgmax is only relevant if krgendanchor is ‘sorg’

add_corey_oil(nog=2, kroend=1, kromax=None)[source]

Add kro data through the Corey parametrization

A column named ‘kro’ will be added to the internal DataFrame, replaced if it exists.

All values above 1 - sorg - swl are set to zero.

Parameters
• nog (float) – Corey exponent for oil

• kroend (float) – Value for krog at normalized oil saturation 1

Returns

None (modifies internal class state)

add_fromtable(dframe, sgcolname='Sg', krgcolname='krg', krogcolname='krog', pccolname='pcog', krgcomment='', krogcomment='', pccomment='')[source]

Interpolate relpermdata from a dataframe.

The saturation range with endpoints must be set up beforehand, and must be compatible with the tabular input. The tabular input will be interpolated to the initialized Sg-table.

If you have krg and krog in different dataframes, call this function twice

Calling function is responsible for checking if any data was actually added to the table.

add_gasoil_fromtable(*args, **kwargs)[source]

Deprecated. Use add_fromtable()

crosspoint()[source]

Locate and return the saturation point where krg = krog

Accuracy of this crosspoint depends on the resolution chosen when initializing the saturation range (it uses linear interpolation to solve for the zero)

Returns

the gas saturation where krg == krog, for relperm

linearly interpolated in gas saturation.

Return type

float

estimate_sgcr(curve='krog')[source]

Estimate sgcr of the current krog data.

sgcr is estimated by searching for a linear part in krog upwards from sg=0. In practice it is impossible to infer sgcr = 0, since we are limited by h, and we always have to assume that the first segment is linear.

If the curve is linear everywhere, sgcr will be returned as the right endpoint.

Parameters

curve (str) – Column name to use for search for linearity. Default is krog, if all of that is linear, you may try krg instead.

Returns

The estimated sgcr.

Return type

float

estimate_sorg()[source]

Estimate sorg of the current krg or krog data.

sorg is estimated by searching for a linear part in krg downwards from sg=1-swl. In practice it is impossible to infer sorg = 0, since we are limited by h, and the last segment from sg=1-swl-h to sg=1-swl can always be assumed linear.

If krgend is anchored to sorg, krg data is used to infer sorg. If not, krg cannot be used for this, and krog is used. sorg might be overestimated when krog is used if it very close to zero before reaching sorw.

If the curve is linear everywhere, sorg will be returned as sgcr + h

Parameters

None

Returns

The estimated sorg.

Return type

float

plotkrgkrog(mpl_ax=None, color='blue', alpha=1, linewidth=1, linestyle='-', marker=None, label=None, logyscale=False)[source]

Plot krg and krog

If mpl_ax is not None, it will be used as a matplotlib axis to plot on, if None, a fresh plot will be made.

resetsorg()[source]

Recalculate sorg in case it has table data has been manipulated

selfcheck(mode='SGOF')[source]

Check validities of the data in the table.

This is to catch errors that are either physically wrong or at least causes Eclipse 100 to stop.

Returns True if no errors are found, False if at least one is found.

If you call SGOF/SLGOF, this function must not return False.

Parameters

mode (str) – If mode is “SGFN”, krog is not required.

set_endpoints_linearpart_krg(krgend, krgmax=None)[source]

Set linear parts of krg outside endpoints.

Curve is set to zero in [0, sgcr].

Given the default krgendanchor==sorg, the curve will be linear in [1 - swl - sorg, 1 - swl] (from krgend to krgmax). If not anchored to sorg, there is no linear part near sg=1-swl.

If krgendanchor is set to sorg (default), then the normalized gas saturation sgn (which is what is raised to the power of ng) is 1 at sg = 1 - swl - sorg. If not, it is 1 at sg = 1 - swl.

krgmax is only relevant if krgendanchor is ‘sorg’

This function is used by add_corey/LET_gas(), and perhaps by other utility functions. It should not be necessary for end-users.

Parameters
• krgend (float) – krg at sg = 1 - swl - sorg.

• krgmax (float) – krg at Sg = 1 - swl. Default 1.

set_endpoints_linearpart_krog(kroend, kromax=None)[source]

Set linear parts of krog outside endpoints.

Zero for sg above 1 - sorg - swl.

This function is used by add_corey/LET_oil(), and perhaps by other utility functions. It should not be necessary for end-users.

Parameters

kroend (float) – krog at sg=0

slgof_df()[source]

Slice out an SLGOF table.

This is a used by the SLGOF() function, it is extracted as a single function to facilitate testing.

## pyscal.gaswater module¶

Object to represent GasWater, implemented as a Container object for one WaterOil and one GasOil object

class pyscal.gaswater.GasWater(swirr=0, swl=0.0, swcr=0.0, sgrw=0.0, sgcr=0, h=0.01, tag='', fast=False)[source]

Bases: object

A representation of two-phase properties for gas-water

Internally, this class handles gas-water by using one WaterOil object and one GasOil object, with dummy parameters for oil.

Parameters
• swirr (float) – Irreducible water saturation for capillary pressure

• swl (float) – First water saturation point in outputted tables.

• swcr (float) – Critical water saturation, water is immobile below this

• sgrw (float) – Residual gas saturation after water flooding.

• sgcr (float) – Critical gas saturation, gas is immobile below this

• h (float) – Saturation intervals in generated tables.

• tag (str) – Optional text that will be included as comments.

• fast (bool) – Set to True if you prefer speed over robustness. Not recommended, pyscal will not guarantee valid output in this mode.

SGFN(header=True, dataincommentrow=True)[source]

Produce SGFN input for Eclipse reservoir simulator.

The columns sg and krg are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SGFN string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SGFN yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

SWFN(header=True, dataincommentrow=True)[source]

Produce SWFN input to Eclipse

The columns sw, krw and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SWFN string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SWFN yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

add_LET_gas(l=2, e=2, t=2, krgend=1)[source]

Add krg data through the LET parametrization

A column named ‘krg’ will be added. If it exists, it will be replaced.

Parameters
• l (float) – LET parameter

• e (float) – LET parameter

• t (float) – LET parameter

• krgend (float) – value of krg at swl

add_LET_water(l=2, e=2, t=2, krwend=1, krwmax=None)[source]

Add krw data through LET parametrization

The LET model applies for sw < 1 - sgrw. For higher water saturations, krw is linear between krwend and krwmax.

krwmax will be ignored if sorw is close to zero.

Parameters
• l (float) – LET parameter

• e (float) – LET parameter

• t (float) – LET parameter

• krwend (float) – value of krw at 1 - sorw

• krwmax (float) – maximal value at Sw=1. Default 1

add_corey_gas(ng=2, krgend=1)[source]

Add krg data through the Corey parametrization

A column named ‘krg’ will be added. If it exists, it will be replaced.

Parameters
• ng (float) – Corey parameter for gas

• krgend (float) – value of krg at swl.

add_corey_water(nw=2, krwend=1, krwmax=None)[source]

Add krw data through the Corey parametrization

A column named ‘krw’ will be added. If it exists, it will be replaced.

The Corey model applies for sw < 1 - sgrw. For higher water saturations, krw is linear between krwend and krwmax.

krwmax will be ignored if sgrw is close to zero

Parameters
• nw (float) – Corey parameter for water.

• krwend (float) – value of krw at 1 - sorw.

• krwmax (float) – maximal value at Sw=1. Default 1

add_simple_J(a=5, b=- 1.5, poro_ref=0.25, perm_ref=100, drho=300, g=9.81)[source]

Add capillary pressure function from a simplified J-function

This is the RMS version of the coefficients a and b, the formula used is

$J = a S_w^b$

J is not dimensionless in this equation. The capillary pressure be in bars.

This is identical to the also seen formula

$J = 10^{b \log(S_w) + \log(a)}$

$$S_w$$ in this formula is normalized with respect to the swirr variable of the WaterOil object.

Parameters
• a (float) – a coefficient

• b (float) – b coefficient

• poro_ref (float) – Reference porosity for scaling to Pc, between 0 and 1

• perm_ref (float) – Reference permeability for scaling to Pc, in milliDarcy

• drho (float) – Density difference between water and oil, in SI units kg/m³. Default value is 300

• g (float) – Gravitational acceleration, in SI units m/s², default value is 9.81

Returns

None. Modifies pc column in self.table, using bar as pressure unit.

add_simple_J_petro(a, b, poro_ref=0.25, perm_ref=100, drho=300, g=9.81)[source]

Add capillary pressure function from a simplified J-function

This is the petrophysical version of the coefficients a and b, the formula used is

$J = \left(\frac{S_w}{a}\right)^{\frac{1}{b}}$

which is identical to

$J = 10^\frac{\log(S_w) - \log(a)}{b}$

J is not dimensionless in this equation.

$$S_w$$ in this formula is normalized with respect to the swirr variable of the WaterOil object.

Parameters
• a (float) – a coefficient, petrophysical version

• b (float) – b coefficient, petrophysical version

• poro_ref (float) – Reference porosity for scaling to Pc, between 0 and 1

• perm_ref (float) – Reference permeability for scaling to Pc, in milliDarcy

• drho (float) – Density difference between water and oil, in SI units kg/m³. Default value is 300

• g (float) – Gravitational acceleration, in SI units m/s², default value is 9.81

Returns

None. Modifies pc column in self.table, using bar as pressure unit.

crosspoint()[source]

Calculate the sw value where krg == krw.

Accuracy of this crosspoint depends on the resolution chosen when initializing the saturation range (it uses linear interpolation to solve for the zero)

Returns

the gas saturation where krw == krg, for relperm

linearly interpolated in water saturation.

Return type

float

property krgcomment
property krwcomment
plotkrwkrg(mpl_ax=None, color='blue', alpha=1, linewidth=1, linestyle='-', marker=None, label='', logyscale=False)[source]

Plot krw and krg

If the argument ‘mpl_ax’ is not supplied, a new plot window will be made. If supplied, it will draw on the specified axis.

selfcheck()[source]

Run selfcheck on the data.

Performs tests if necessary data is ready in the object for printing Eclipse include files, and checks some numerical properties (direction and monotonocity)

Returns

bool

property sgcomment
property swcomment
property swcr
property swirr
property swl
property tag
pyscal.gaswater.is_documented_by(original)[source]

Decorator to avoid duplicating function docstrings

## pyscal.pyscalcli module¶

Command line tool for pyscal

pyscal.pyscalcli.get_parser()[source]

Construct the argparse parser for the command line script.

Returns

argparse.Parser

pyscal.pyscalcli.main()[source]

Endpoint for pyscals command line utility.

Translates from argparse API to Pyscal’s Python API

pyscal.pyscalcli.pyscal_main(parametertable, verbose=False, debug=False, output='relperm.inc', delta_s=None, int_param_wo=None, int_param_go=None, sheet_name=None, slgof=False, family2=False)[source]

A “main()” method not relying on argparse. This can be used for testing, and also by an ERT forward model, e.g. in semeio (github.com/equinor/semeio)

Parameters
• parametertable (string) – Filename (CSV or XLSX) to load

• verbose (bool) – verbose or not

• debug (bool) – debug mode or not

• output (string) – Output filename

• delta_s (float) – Saturation step-length

• int_param_wo (list) – Interpolation params for wateroil

• int_param_go (list) – Interpolation params for gasoil

• sheet_name (string) – Which sheet in XLSX file

• slgof (bool) – Use SLGOF

• family2 (bool) – Dump family 2 keywords

## pyscal.pyscallist module¶

Container class for list of Pyscal objects

class pyscal.pyscallist.PyscalList(pyscal_list=None)[source]

Bases: object

Container class for a list of WaterOilGas objects.

Essentially this is a list of objects of equal type, and all being pyscal objects WaterOil, GasOil, WaterOilGas or SCALrecommendation

It is possible to ask this list class for SWOF++ printouts, and it will call SWOF on each element succesively.

Parameters

pyscal_list (list) – List of objects if already ready. Can be empty or None.

SGFN(write_to_filename=None, gaswater=False)[source]

Make SGFN string and optionally print to file

SGOF(write_to_filename=None)[source]

Make SGOF string and optionally print to file

SLGOF(write_to_filename=None)[source]

Make SLGOF string and optionally print to file

SOF3(write_to_filename=None)[source]

Make SOF3 string and optionally print to file

SWFN(write_to_filename=None, gaswater=False)[source]

Make SWFN string and optionally print to file

SWOF(write_to_filename=None)[source]

Make SWOF string and optionally print to file

append(pyscal_obj)[source]

Append a pyscal object to the list

Parameters

pyscal_obj (WaterOil, GasOil, WaterOilGas or SCALrecommendation) –

Raises

ValueError if the type of the incoming object does not – match existing objects in the list

df()[source]

Dump dataframes of generated relperm data

Column names are compatible with ecl2df.satfunc. Always uppercase and capillary pressure is PCOW or PCOG (wateroil vs gasoil)

If the PyscalList contains SCALrecommendations, the CASE column will contain the strings ‘pess’, ‘base’ and ‘opt’ (independent of any alias name potentially used in an input xlsx/csv)

Returns

pd.DataFrame

dump_family_1(filename=None, slgof=False)[source]

Dumps family 1 Eclipse saturation tables to one filename. This means SWOF + SGOF (SGOF only if relevant)

Parameters
• filename (str) – Filename for the output to be given to Eclips 100

• slgof (bool) – Set to true of SLGOF is wanted instead of SGOF

dump_family_2(filename=None)[source]

Dumps family 2 Eclipse saturation tables to one filename. This means SWFN + SGFN + SOF3 (SOF3 only for WaterOilGas)

Relevant for WaterOilGas and GasWater.

Parameters

filename (str) – Filename for the output to be given to Eclipse 100

interpolate(int_params_wo, int_params_go=None, h=None)[source]

This function will interpolate each SCALrecommendation object to the chosen parameters

This only works on lists of SCALrecommendation objects

Parameters
• int_params_wo (float or list of float) – Interpolation parameters for wateroil, or for both. If list, separate parameter for each SATNUM. All numbers between -1 and 1.

• int_params_go (float or list of float) – If specified, will be used for GasOil interpolation.

• h (float) – Saturation step-length

Returns

PyscalList of type WaterOilGas, with the same length.

make_ecl_output(keyword, write_to_filename=None, gaswater=False)[source]

Internal helper function for constructing strings and writing to disk

## pyscal.scalrecommendation module¶

SCALrecommendation, container for low, base and high WaterOilGas objects

class pyscal.scalrecommendation.SCALrecommendation(low, base, high, tag=None, h=0.01)[source]

Bases: object

A SCAL recommendation consists of three OilWaterGas objects, tagged low, base and high.

This container exists in order to to interpolation from -1 (low), through 0 (base) and to 1 (high).

Parameters
• low (WaterOilGas) – An object representing the low case

• base (WaterOilGas) – An object representing the base case

• high (WaterOilGas) – An object representing the high case

• tag (str) – A string that describes the recommendation. Optional.

add_simple_J(a=5, b=- 1.5, poro_ref=0.25, perm_ref=100, drho=300, g=9.81)[source]

Add (identical) simplified J-function to all water-oil curves in the SCAL recommendation set

static defaultshandling(key, value, dicts)[source]

Helper function for __init__ to fill out missing values in dicts with relperm parameter

This function IS DEPRECATED and will be removed when __init__ no longer supports dicts as arguments.

interpolate(parameter, parameter2=None, h=0.02)[source]

Interpolate between low, base and high

Endpoints are located for input curves, and interpolated individually. Interpolation for the nonlinear part is done on a normalized interval between the endpoints

Interpolation is linear in relperm-direction, and will thus not be linear in log-relperm-direction

This method returns an WaterOilGas object which can be realized into printed tables. No attempt is made to parametrize the interpolant in L,E,T parameter space, or Corey-space.

Parameters
• parameter (float) – Between -1 and 1, inclusive. -1 reproduces low/ pessimistic curve, 0 gives base, 1 gives high/optimistic.

• parameter2 (float) – If not None, used for the gas-oil interpolation, enables having interpolation uncorrelated for WaterOil and GasOil. Ignored for GasWater (no warning).

• h (float) – Saturation step length in generated tables. Does not need to be the same as the tables interpolation is done from.

## pyscal.utils module¶

Utility function for pyscal

pyscal.utils.comment_formatter(multiline, prefix='-- ')[source]

Prepends comment characters to every line in input

Parameters
• multiline (str) – String that can contain newlines

• prefix (str) – Comment characters to prepend every line with Default is the Eclipse comment syntax ‘– ‘

Returns

string, with newlines preserved, and where each line

starts with the given prefix. Always ends with a newline.

pyscal.utils.crosspoint(dframe, satcol, kr1col, kr2col)[source]

Locate the crosspoint where kr1col == kr2col

Parameters
• dframe (pd.DataFrame) – Dataframe with at least three columns

• satcol (str) – Column name for the saturation column

• kr1col (str) – Column name for first relperm column

• kr2col (str) – Columnn ame for second column

Returns

float, the saturation value (interpolated) where

kr1col == kr2col, when krXcol is linearly interpolated as a function of the saturation values.

pyscal.utils.df2str(dframe, digits=7, roundlevel=9, header=False, monotone_column=None, monotone_direction=None)[source]

Make a string representation of a dataframe with proper rounding.

This is used to print the tables in the SWOF/SGOF include files, explicit rounding is necessary to avoid monotonicity errors from truncation. Examples in test code.

Capillary pressure must be strictly monotone if nonzero, and if a column name is provided, the string representation of that column is ensured to be strictly monotone decreasing

Parameters
• dframe (pd.DataFrame) – A dataframe to print, all columns are included

• digits (int) – Number of digits used in floating point format f.ex “.7f” It is not recommended to deviate from the default 7 uncritically for pyscal output, other code have to be tuned to ensure numerical robustness to the deviation.

• roundlevel (int) – To how many digits should we round prior to print. Recommended to be > digits + 1, see test code.

• header (bool) – If the dataframe column header should be included

• monotone_column – column name for which strict monotonicity must be preserved in output. Only one column can be fixed.

• monotone_direction – Direction of monotonicity, increasing or decreasing, allowed values are ‘-1’, ‘1’, ‘inc’ or ‘dec’

pyscal.utils.estimate_diffjumppoint(table, xcol=None, ycol=None, side='right')[source]

Estimate the point where the y-data jumps from being linear in x to being nonlinear, or where it shift from one linear domain to another (for a piecewise linear function)

If xcol is sw, and ycol is krw, and side is ‘right’, this will typically estimate sorw for you. If side is ‘left’ it will give you swcr.

Parameters
• table (pd.DataFrame) – A Dataframe with x and y data

• xcol (string) – The name of the column in table containing x-data. If None (default) the first column in table will be used.

• ycol (string) – The name of the column in table containing y-data. If None (default) the second column in the table will be used.

• side (string) – Must be ‘left’ or ‘right’. Decides whether to look from the right side of the x-interval or from the left side for the linear domain.

Returns

The x value where the start-linear domain ends.

Return type

float

pyscal.utils.interpolate_go(go_low, go_high, parameter, h=0.01, tag=None)[source]

Interpolates between two gas-oil curves.

The saturation endpoints for the curves must be known by the objects. They can be estimated by estimate_sorg() etc. or can be set manually for finer control.

The interpolation algorithm is different left and right for saturation endpoints, and saturation endpoints are interpolated individually.

Parameters
• go_low (GasOil) – a “low” case

• go_high (GasOil) – a “high” case

• parameter (float) – Between 0 and 1. 0 will return the low case, 1 will return the high case. Any number in between will return an interpolated curve

• h (float) – Saturation step-size in interpolant. If defaulted, a value smaller than in the input curves are used, to preserve information.

• tag (string) – Tag to associate to the constructed object. If None it will be automatically filled. Set to empty string to ensure no tag.

Returns

A new gas-oil curve

pyscal.utils.interpolate_wo(wo_low, wo_high, parameter, h=0.01, tag=None)[source]

Interpolates between two water-oil curves.

The saturation endpoints for the curves must be known by the objects. They can be estimated by estimate_sorw() etc. or can be set manually for finer control.

The interpolation algorithm is different left and right for saturation endpoints, and saturation endpoints are interpolated individually.

Parameters
• wo_low (WaterOil) – a “low” case

• wo_high (WaterOil) – a “high” case

• parameter (float) – Between 0 and 1. 0 will return the low case, 1 will return the high case. Any number in between will return an interpolated curve

• h (float) – Saturation step-size in interpolant. If defaulted, a value smaller than in the input curves are used, to preserve information.

• tag (string) – Tag to associate to the constructed object. If None it will be automatically filled. Set to empty string to ensure no tag.

Returns

A new oil-water curve

pyscal.utils.interpolator(tableobject, wo_low, wo_high, parameter, sat='sw', kr1='krw', kr2='krow', pc='pc')[source]

Interpolates between two curves.

DEPRECATED FUNCTION!

The interpolation parameter is 0 through 1, irrespective of phases or low-base/base-high/low-high.

Parameters
• tabjeobject (WaterOil or GasOil) – A partially setup object where relperm and pc columns are to be filled with numbers.

• wo_low (WaterOil or GasOil) – “Low” case of interpolation (relates to interpolation parameter 0). Must be copies, as they will be modified.

• wo_high – Ditto, relates to interpolation parameter 1

• parameter (float) – Between 0 and 1, what you want to interpolate to.

• sat (str) – Name of the saturation column, typically ‘sw’ or ‘sg’

• kr1 (str) – Name of the first relperm column (‘krw’ or ‘krg’)

• kr2 (str) – Name of the second relperm column (‘krow’ or ‘krog’)

• pc (str) – Name of the capillary pressure column (‘pc’)

Returns

None, but modifies the first argument.

pyscal.utils.normalize_nonlinpart_go(curve)[source]

Make krg and krog functions that evaluates only on the (potentially) nonlinear part of the relperm curves, and with a normalized argument (0,1) on that interval.

For a GasOil krg curve, the nonlinear part is from sgcr to sorg. sgcr is mapped to sg=zero, and sg=1 - sorg - swl is mapped to 1. Then there is an assumed linear part from sorg to 1 which we ignore here.

For a GasOil krow curve, the nonlinear part is from 1 - sorg (mapped to zero) to sg=0 (mapped to 1).

These endpoints must be known the the GasOil object coming in (the object can determine them using functions ‘estimate_sorg()’ and ‘estimate_sgcr()’

If the entire curve is linear, it will not matter for this function, because this function only deals with the presumably known endpoints.

Parameters

curve (GasOil) – incoming gasoil curve set (krg and krog)

Returns

tuple of functions. The first will evaluate krg on

the normalized Sg interval [0,1], the second will evaluate krog on the normalized So interval [0,1].

pyscal.utils.normalize_nonlinpart_wo(curve)[source]

Make krw and krow functions that evaluate only on the (potentially) nonlinear part of the relperm curves, and with a normalized argument (0,1) on that interval.

For a WaterOil krw curve, the nonlinear part is from swcr to sorw. swcr is mapped to zero, and 1 - sorw is mapped to 1. Then there is an assumed linear part from sorw to 1 which we ignore here.

For a WaterOil krow curve, the nonlinear part is from 1 - sorw (mapped to zero) to swl (mapped to 1).

These endpoints must be known the the WaterOil object coming in (the object can determine them using functions ‘estimate_sorw()’ and ‘estimate_swcr()’

If the entire curve is linear, it will not matter for this function, because this function only deals with the presumably known endpoints.

Parameters

curve (WaterOil) – incoming oilwater curve set (krw and krow)

Returns

tuple of lambda functions. The first will evaluate krw on

the normalized Sw interval [0,1], the second will evaluate krow on the normalized So interval [0,1].

pyscal.utils.normalize_pc(curve)[source]

Normalize the capillary pressure curve.

This is only normalized with respect to the smallest and largest saturation present in the table, not to the could-be-uncertain swirr that the object could contain, because we then have to make assumptions on the equations used to generate the data in the table.

Parameters

curve (WaterOil or GasOil) – An object with a table with a pc column

Returns

a lambda function that will evaluate pc on the normalized interval [0,1]

## pyscal.wateroil module¶

Wateroil module

class pyscal.wateroil.WaterOil(swirr=0.0, swl=0.0, swcr=0.0, sorw=0.0, h=0.01, tag='', fast=False, _sgcr=None)[source]

Bases: object

A representation of two-phase properties for oil-water.

Can hold relative permeability data, and capillary pressure.

Parametrizations for relative permeability:
• Corey

• LET

For capillary pressure:
• Simplified J-function

For object initialization, only saturation endpoints must be inputted, and saturation resolution. An optional string can be added as a ‘tag’ that can be used when outputting.

Relative permeability and/or capillary pressure can be added through parametrizations, or from a dataframe (will incur interpolation).

Can be dumped as include files for Eclipse/OPM and Nexus simulators.

Parameters
• swirr (float) – Absolute minimal water saturation at infinite capillary pressure.

• swl (float) – First water saturation point in generated table. Used for normalized saturations.

• swcr (float) – Critical water saturation. Water will not be mobile before the water saturation is above this value.

• sorw (float) – Residual oil saturation after water flooding. At this oil saturation, the oil has zero relative permeability.

• h (float) – Saturation step-length in the outputted table.

• tag (str) – Optional string identifier, only used in comments.

• fast (bool) – Set to True if in order to skip some integrity checks and nice-to-have features. Not needed to set for normal pyscal runs, as speed is seldom crucial. Default False

SWFN(header=True, dataincommentrow=True, swcomment=None, crosspointcomment=None)[source]

Return a SWFN keyword with data to Eclipse

The columns sw, krw and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header – boolean for whether the SWFN string should be emitted. If you have multiple satnums, you should have True only for the first (or False for all, and emit the SWFN yourself). Defaults to True.

• dataincommentrow – boolean for wheter metadata should be printed, defaults to True.

• swcomment (str) – String to be used for swcomment, overrides what this object can provide. Used by GasWater

• crosspointcomment (str) – String to be used for crosspoint comment string, overrides what this object can provide. Used by GasWater. If None, it will be computed, use empty string to avoid.

SWOF(header=True, dataincommentrow=True)[source]

Produce SWOF input for Eclipse reservoir simulator.

The columns sw, krw, krow and pc are outputted and formatted accordingly.

Meta-information for the tabulated data are printed as Eclipse comments.

Parameters
• header (bool) – Indicate whether the SWOF string should be emitted. If you have multiple SATNUMs, you should set this to True only for the first (or False for all, and emit the SWOF yourself). Default True

• dataincommentrow (bool) – Wheter metadata should be printed. Defualt True

WOTABLE(header=True, dataincommentrow=True)[source]

Return a string for a Nexus WOTABLE

add_LET_oil(l=2, e=2, t=2, kroend=1, kromax=None)[source]

Add kro data through LET parametrization

Parameters
• l (float) – LET parameter

• e (float) – LET parameter

• t (float) – LET parameter

• kroend (float) – value of kro at swl

Returns

None (modifies object)

add_LET_pc_imb(Ls, Es, Ts, Lf, Ef, Tf, Pcmax, Pcmin, Pct)[source]

Add an imbition LET capillary pressure curve.

add_LET_pc_pd(Lp, Ep, Tp, Lt, Et, Tt, Pcmax, Pct)[source]

Add a primary drainage LET capillary pressure curve.

Note that Pc where Sw > 1 - sorw will appear linear because there are no saturation points in that interval.

add_LET_water(l=2, e=2, t=2, krwend=1, krwmax=None)[source]

Add krw data through LET parametrization

The LET model applies for sw < 1 - sgrw. For higher water saturations, krw is linear between krwend and krwmax.

krwmax will be ignored if sorw is close to zero.

Parameters
• l (float) – LET parameter

• e (float) – LET parameter

• t (float) – LET parameter

• krwend (float) – value of krw at 1 - sorw

• krwmax (float) – maximal value at Sw=1. Default 1

add_corey_oil(now=2, kroend=1, kromax=None)[source]

Add kro data through the Corey parametrization

Corey applies to the interval between swcr and 1 - sorw

Curve is linear between swl and swcr, zero above 1 - sorw.

Parameters
• now (float) – Corey exponent

• kroend (float) – kro value at swcr

Returns

None (modifies object)

add_corey_water(nw=2, krwend=1, krwmax=None)[source]

Add krw data through the Corey parametrization

A column named ‘krw’ will be added. If it exists, it will be replaced.

The Corey model applies for sw < 1 - sorw. For higher water saturations, krw is linear between krwend and krwmax.

krwmax will be ignored if sorw is close to zero

Parameters
• nw (float) – Corey parameter for water.

• krwend (float) – value of krw at 1 - sorw.

• krwmax (float) – maximal value at Sw=1. Default 1

add_fromtable(dframe, swcolname='Sw', krwcolname='krw', krowcolname='krow', pccolname='pcow', krwcomment='', krowcomment='', pccomment='', sorw=None)[source]

Interpolate relpermdata from a dataframe.

The saturation range with endpoints must be set up beforehand, and must be compatible with the tabular input. The tabular input will be interpolated to the initialized Sw-table

If you have krw and krow in different dataframes, call this function twice

Calling function is responsible for checking if any data was actually added to the table.

The relpermdata will be interpolated using a monotone cubic interpolator below 1-sorw, and linearly above 1-sorw. Capillary pressure data will be interpolated monotone cubicly over the entire saturation interval

The python package ecl2df has a tool for converting Eclipse input files to dataframes.

Parameters
• dframe (pd.DataFrame) – containing data

• swcolname (string) – column name with the saturation data in the dataframe df

• krwcolname (string) – name of column in df with krw

• krowcolname (string) – name of column in df with krow

• pccolname (string) – name of column in df with capillary pressure data

• krwcomment (string) – Inserted into comment

• krowcomment (string) – Inserted into comment

• pccomment (str) – Inserted into comment

• sorw (float) – Explicit sorw. If None, it will be estimated from the numbers in krw (or krow)

add_normalized_J(a, b, poro, perm, sigma_costau)[source]

Add capillary pressure in bar through a normalized J-function.

$p_c = \frac{\left(\frac{S_w}{a}\right)^{\frac{1}{b}} \sigma \cos \tau}{\sqrt{\frac{k}{\phi}}}$

The $$S_w$$ saturation used in the formula is normalized with respect to the swirr parameter.

Parameters
• a (float) – a parameter

• b (float) – b exponent (typically negative)

• poro (float) – Porosity value, fraction between 0 and 1

• perm (float) – Permeability value in mD

• sigma_costau (float) – Interfacial tension in mN/m (typical value 30 mN/m)

Returns

None. Modifies pc column in self.table, using bar as pressure unit.

add_oilwater_fromtable(*args, **kwargs)[source]

Deprecated, use add_fromtable()

add_simple_J(a=5, b=- 1.5, poro_ref=0.25, perm_ref=100, drho=300, g=9.81)[source]

Add capillary pressure function from a simplified J-function

This is the RMS version of the coefficients a and b, the formula used is

$J = a S_w^b$

J is not dimensionless in this equation. The capillary pressure be in bars.

This is identical to the also seen formula

$J = 10^{b \log(S_w) + \log(a)}$

$$S_w$$ in this formula is normalized with respect to the swirr variable of the WaterOil object.

Parameters
• a (float) – a coefficient

• b (float) – b coefficient

• poro_ref (float) – Reference porosity for scaling to Pc, between 0 and 1

• perm_ref (float) – Reference permeability for scaling to Pc, in milliDarcy

• drho (float) – Density difference between water and oil, in SI units kg/m³. Default value is 300

• g (float) – Gravitational acceleration, in SI units m/s², default value is 9.81

Returns

None. Modifies pc column in self.table, using bar as pressure unit.

add_simple_J_petro(a, b, poro_ref=0.25, perm_ref=100, drho=300, g=9.81)[source]

Add capillary pressure function from a simplified J-function

This is the petrophysical version of the coefficients a and b, the formula used is

$J = \left(\frac{S_w}{a}\right)^{\frac{1}{b}}$

which is identical to

$J = 10^\frac{\log(S_w) - \log(a)}{b}$

J is not dimensionless in this equation.

$$S_w$$ in this formula is normalized with respect to the swirr variable of the WaterOil object.

Parameters
• a (float) – a coefficient, petrophysical version

• b (float) – b coefficient, petrophysical version

• poro_ref (float) – Reference porosity for scaling to Pc, between 0 and 1

• perm_ref (float) – Reference permeability for scaling to Pc, in milliDarcy

• drho (float) – Density difference between water and oil, in SI units kg/m³. Default value is 300

• g (float) – Gravitational acceleration, in SI units m/s², default value is 9.81

Returns

None. Modifies pc column in self.table, using bar as pressure unit.

add_skjaeveland_pc(cw, co, aw, ao, swr=None, sor=None)[source]

Add capillary pressure from the Skjæveland correlation,

The implementation is unit independent, units are contained in the input constants.

If swr and sor are not provided, it will be taken from the swirr and sorw. Only use different values here if you know what you are doing.

Modifies or adds self.table[“pc”] if succesful. Returns false if error occured.

crosspoint()[source]

Locate and return the saturation point where krw = krow

Accuracy of this crosspoint depends on the resolution chosen when initializing the saturation range

Returns

the water saturation where krw == krow, for relperm

linearly interpolated in water saturation.

Return type

float

estimate_sorw(curve='krw')[source]

Estimate sorw of the current krw data.

This is mostly relevant when add_fromtable() has been used. sorw is estimated by searching for a linear part in krw downwards from sw=1. In practice it is impossible to infer sorw = 0, since we are limited by h, and the last segment from sw=1-h to sw=1 can always be assumed linear. Expect sorw = h if the real sorw = 0, but do not depend that it might not return zero in the future (one could argue that sorw = h should be specially treated to mean sorw = 0)

If the curve is linear everywhere, sorw will be returned as swl + h

krow is not used, and should probably not be, as it can be very close to zero before approaching sorw.

Parameters

curve (str) – Colum name of column to use, default is krw. If this is all linear, but krow is not, you might be better off with krow

Returns

The estimated sorw.

Return type

float

estimate_swcr(curve='krw')[source]

Estimate swcr of the current krw data.

swcr is estimated by searching for a linear part in krw upwards from sw=swl. In practice it is impossible to infer swcr = 0, since we are limited by h, and the first segment is assumed linear anyways.

If the curve is linear everywhere, swcr can end up at the right end of your saturation interval.

Parameters

curve (str) – Colum name of column to use, default is krow. If this is all linear, but krw is not, you might be better off with krw

Returns

The estimated sgcr.

Return type

float

plotkrwkrow(mpl_ax=None, color='blue', alpha=1, linewidth=1, linestyle='-', marker=None, label='', logyscale=False)[source]

Plot krw and krow

If the argument ‘mpl_ax’ is not supplied, a new plot window will be made. If supplied, it will draw on the specified axis.

plotpc(mpl_ax=None, color='blue', alpha=1, linewidth=1, linestyle='-', label='', logyscale=False)[source]

Plot capillary pressure (pc)

If mpl_ax is supplied, the curve will be drawn on that, if not, a new axis (plot) will be made

selfcheck(mode='SWOF')[source]

Check validities of the data in the table.

An unfinished object will return False.

If you call SWOF, this function must not return False

This function should not throw an exception, but capture the error and give an error.

Parameters

mode (str) – “SWOF” or “SWFN”. If SWFN, krow is not required.

set_endpoints_linearpart_krow(kroend, kromax=None)[source]

Set linear parts of krow outside endpoints

Curve will be zero in [1 - sorw, 1].

This function is used by add_corey_water(), and perhaps by other utility functions. It should not be necessary for end-users.

Parameters

kroend (float) – value of kro at swcr

set_endpoints_linearpart_krw(krwend, krwmax=None)[source]

Set linear parts of krw outside endpoints.

Curve will be linear from [1 - sorw, 1] (from krwmax to krwend) and zero in [swl, swcr]

This function is used by add_corey_water(), and perhaps by other utility functions. It should not be necessary for end-users.

Parameters
• krwend (float) – krw at 1 - sorwr

• krwmax (float) – krw at Sw=1. Default 1.

## pyscal.wateroilgas module¶

Container object for one WaterOil and one GasOil object

class pyscal.wateroilgas.WaterOilGas(swirr=0, swl=0.0, swcr=0.0, sorw=0.0, sorg=0, sgcr=0, h=0.01, tag='', fast=False)[source]

Bases: object

A representation of three-phase properties for oil-water-gas

Use one object for each satnum.

One WaterOil and one GasOil object will be created, with compatible saturation ranges. Access the class members ‘wateroil’ and ‘gasoil’ directly to add curves.

All arguments to the initializer can be defaulted, and all are zero except h.

Either the gasoil or the wateroil member is allowed to be None in case of only two phases present.

Parameters
• swirr (float) – Irreducible water saturation for capillary pressure

• swl (float) – First water saturation point in outputted tables.

• swcr (float) – Critical water saturation, water is immobile below this

• sorw (float) – Residual oil saturation

• sgcr (float) – Critical gas saturation, gas is immobile below this

• h (float) – Saturation intervals in generated tables.

• tag (str) – Optional text that will be included as comments.

• fast (bool) – Set to True if you prefer speed over robustness. Not recommended, pyscal will not guarantee valid output in this mode.

SGFN(header=True, dataincommentrow=True)[source]

Return a SGFN string. Delegated to the gasoil object.

SGOF(header=True, dataincommentrow=True)[source]

Return a SGOF string. Delegated to the gasoil object.

SLGOF(header=True, dataincommentrow=True)[source]

Return a SLGOF string. Delegated to the gasoil object.

SOF3(header=True, dataincommentrow=True)[source]

Return a SOF3 string, combining data from the wateroil and gasoil objects.

So - the oil saturation ranges from 0 to 1-swl. The saturation points from the WaterOil object is used to generate these

SWFN(header=True, dataincommentrow=True)[source]

Return a SWFN string. Delegated to the wateroil object.

SWOF(header=True, dataincommentrow=True)[source]

Return a SWOF string. Delegated to the wateroil object

run_eclipse_test()[source]

Start the Eclipse simulator on a minimal deck in order to test the properties of the current WaterOilGas deck

selfcheck()[source]

Run selfcheck on both wateroil and gasoil.

Returns true only if both passes if both are present.

If only wateroil or gasoil is present (the other being None, only the relevant is checked.

Returns

bool

property sorg
property sorw
property swirr
property swl
property tag
threephaseconsistency()[source]

Perform consistency checks on produced curves, similar to what Eclipse does at startup.

If any (likely) errors are found, these are printed as warnings and this function returns False.

“Errors” from this function should be treated as warnings, as false positives from this function should not have breaking consequences.

Parameters
• None

• self. (examines) –

Returns

bool - True if this function approves the data

pyscal