Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[interp_relperm] Add support for family 2 output #382

Merged
merged 2 commits into from
May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 41 additions & 36 deletions src/subscript/interp_relperm/interp_relperm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import argparse
from pathlib import Path
from typing import List, Dict, Any

import yaml
import pandas as pd
Expand Down Expand Up @@ -61,36 +62,38 @@
- swof_pes.inc
- /project/snakeoil/user/best/r001/ert/input/relperm/sgof_low.inc

result_file : outfilen.inc # Required: Name of output file with interpolated tables
result_file: outfilen.inc # Required: Name of output file with interpolated tables

delta_s : 0.02 # Optional: resolution of Sw/Sg, defaulted to 0.01
family: 1 # Eclipse keyword family. 1 is optional, 2 is the alternative

delta_s: 0.02 # Optional: resolution of Sw/Sg, defaulted to 0.01

# Required: applied in order of appearance so that
# a default value for all tables can set and overrided
# for individual satnums later.
interpolations:
- tables : []
- tables: []
# Required: list of satnums to be interpolated
# empty list interpreted as all entries
# for individual satnums later.
param_w : -0.23
param_g : 0.44
param_w: -0.23
param_g: 0.44

# Required: list of satnums to be interpolated
# empty list interpreted as all entries

- tables : [1]
- tables: [1]
# will only apply to satnum nr. 1, for SWOF and SGOF
param_w : -0.23
param_g : 0.24
param_w: -0.23
param_g: 0.24

- tables : [2,5,75]
- tables: [2,5,75]
# applies to satnum 2, 5, and 75, for SWOF
# (not SGOF since param_g not declared) SGOF
# will be interpolated using 0.44, from above.
# If a parameter not set, no interpolation will
# be applied ie base table is returned
param_w : 0.5
param_w: 0.5

"""

Expand Down Expand Up @@ -171,6 +174,11 @@ def _is_valid_table_entries(schema: dict):
return valid


@configsuite.validator_msg("Valid Eclipse keyword family")
def _is_valid_eclipse_keyword_family(schema: dict):
return schema["family"] in [1, 2]


def get_cfg_schema() -> dict:
"""
Defines the yml config schema
Expand Down Expand Up @@ -206,6 +214,7 @@ def get_cfg_schema() -> dict:
},
},
"result_file": {MK.Type: types.String},
"family": {MK.Type: types.Number, MK.Default: 1},
"delta_s": {MK.Type: types.Number, MK.Default: 0.01},
"interpolations": {
MK.Type: types.List,
Expand All @@ -231,45 +240,45 @@ def get_cfg_schema() -> dict:
return schema


def tables_to_dataframe(filenames: list) -> pd.DataFrame:
def tables_to_dataframe(filenames: List[str]) -> pd.DataFrame:
"""
Routine to gather scal tables (SWOF and SGOF) from ecl include files.

Parameters:
filenames (list): List with filenames (str) to be parsed.
Assumed to contain ecl SCAL tables
filenames : List with filenames to be parsed. Assumed to contain Eclipse
saturation function keywords.

Returns:
dataframe with the tables
"""

return pd.concat(
[satfunc.df(open(filename).read()) for filename in filenames], sort=False
[satfunc.df(Path(filename).read_text()) for filename in filenames], sort=False
)


def make_interpolant(
base_df: pd.DataFrame,
low_df: pd.DataFrame,
high_df: pd.DataFrame,
interp_param: dict,
interp_param: Dict[str, float],
satnum: int,
delta_s: float,
) -> pyscal.WaterOilGas:
"""
Routine to define a pyscal.interpolant instance and perform interpolation.

Parameters:
base_df (pd.DataFrame): containing the base tables
low_df (pd.DataFrame): containing the low tables
high_df (pd.DataFrame): containing the high tables
interp_param (dict): With keys ('param_w', 'param_g'),
base_df: containing the base tables
low_df: containing the low tables
high_df: containing the high tables
interp_param: With keys ('param_w', 'param_g'),
the interp parameter values
satnum (int): the satuation number index
delta_s (float): the saturation spacing to be used in out tables
satnum: the satuation number index
delta_s: the saturation spacing to be used in out tables

Returns:
pyscal.WaterOilGas: Object holding tables for one satnum
Object holding tables for one satnum
"""

# Define base tables
Expand Down Expand Up @@ -451,7 +460,7 @@ def get_parser() -> argparse.ArgumentParser:
return parser


def main():
def main() -> None:
"""
Main function; this is what is executed
"""
Expand All @@ -472,13 +481,13 @@ def main():
process_config(cfg, args.root_path)


def process_config(cfg: dict, root_path: str = "") -> None:
def process_config(cfg: Dict[str, Any], root_path: str = "") -> None:
"""
Process a configuration and dumps produced Eclipse include file to disk.

Args:
cfg (dict): Configuration for files to parse and interpolate in
root_path (str): Preprended to the file paths. Defaults to empty string
cfg: Configuration for files to parse and interpolate in
root_path: Prepended to the file paths. Defaults to empty string
"""
# add root-path to all include files
if "base" in cfg.keys():
Expand Down Expand Up @@ -542,11 +551,11 @@ def process_config(cfg: dict, root_path: str = "") -> None:
high_df.sort_index(inplace=True)

# Loop over satnum and interpolate according to default and cfg values
interpolants = []
interpolants = pyscal.PyscalList()
satnums = range(1, base_df.reset_index("SATNUM")["SATNUM"].unique().max() + 1)

for satnum in satnums:
interp_values = {"param_w": 0, "param_g": 0}
interp_values = {"param_w": 0.0, "param_g": 0.0}
for interp in cfg_suite.snapshot.interpolations:
if not interp.tables or satnum in interp.tables:
if interp.param_w:
Expand All @@ -560,14 +569,10 @@ def process_config(cfg: dict, root_path: str = "") -> None:
)
)

# Dump to Eclipse include file:
with open(cfg_suite.snapshot.result_file, "w") as fileh:
fileh.write("SWOF\n")
for interpolant in interpolants:
fileh.write(interpolant.wateroil.SWOF(header=False))
fileh.write("\nSGOF\n")
for interpolant in interpolants:
fileh.write(interpolant.gasoil.SGOF(header=False))
if cfg_suite.snapshot.family == 1:
interpolants.dump_family_1(cfg_suite.snapshot.result_file)
else:
interpolants.dump_family_2(cfg_suite.snapshot.result_file)

logger.info(
"Done; interpolated relperm curves written to file: %s",
Expand Down
50 changes: 37 additions & 13 deletions tests/test_interp_relperm.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,17 +249,10 @@ def test_args(tmpdir, mocker):

interp_relperm.main()

assert Path("outfilen.inc").exists()
assert Path("outfile.inc").exists()


def test_mock(tmpdir):
"""Mocked pyscal-generated input files.

Note that this is using pyscal both for dumping to disk and
parsing from disk, and is thus not representative for how flexible
the code is for reading from include files not originating in pyscal.
"""
tmpdir.chdir()
def mock_family_1():
columns = [
"SATNUM",
"Nw",
Expand Down Expand Up @@ -289,6 +282,17 @@ def test_mock(tmpdir):
PyscalFactory.create_pyscal_list(dframe_base).dump_family_1("base.inc")
PyscalFactory.create_pyscal_list(dframe_opt).dump_family_1("opt.inc")


def test_mock(tmpdir):
"""Mocked pyscal-generated input files.

Note that this is using pyscal both for dumping to disk and
parsing from disk, and is thus not representative for how flexible
the code is for reading from include files not originating in pyscal.
"""
tmpdir.chdir()
mock_family_1()

config = {
"base": ["base.inc"],
"low": ["pess.inc"],
Expand All @@ -298,7 +302,6 @@ def test_mock(tmpdir):
"delta_s": 0.1,
}

interp_relperm.process_config(config)
interp_relperm.process_config(config)

outfile_df = satfunc.df(open("outfile.inc").read(), ntsfun=1)
Expand All @@ -312,6 +315,27 @@ def test_mock(tmpdir):
assert outfile_df["PCOW"].sum() > 0


def test_family_2_output(tmpdir):
tmpdir.chdir()
mock_family_1()

config = {
"base": ["base.inc"],
"low": ["pess.inc"],
"high": ["opt.inc"],
"result_file": "outfile.inc",
"interpolations": [{"param_w": -0.5, "param_g": 0.5}],
"family": 2,
"delta_s": 0.1,
}
interp_relperm.process_config(config)
output = Path("outfile.inc").read_text()

assert "SWFN" in output
assert "SGFN" in output
assert "SOF3" in output


def test_mock_two_satnums(tmpdir):
"""Mocked pyscal-generated input files.

Expand Down Expand Up @@ -451,7 +475,7 @@ def test_main(tmpdir, mocker):
mocker.patch("sys.argv", [__file__, "-c", str(test_cfg), "-r", str(TESTDATA)])
interp_relperm.main()

assert Path("outfilen.inc").exists()
assert Path("outfile.inc").exists()


if __name__ == "__main__":
Expand All @@ -461,5 +485,5 @@ def test_main(tmpdir, mocker):
test_schema_errors()
test_tables_to_dataframe()
test_make_interpolant()
test_args()
test_main()
test_args() # type: ignore
test_main() # type: ignore
40 changes: 18 additions & 22 deletions tests/testdata_interp_relperm/cfg.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@

base: # a unified file with SWOF and SGOF or two separate files. Both tables are required
base:
# Unified file with SWOF and SGOF or two separate files. Both tables are required
- swof_base.inc
- sgof_base.inc
high: # a unified file with SWOF and SGOF or two separate files. Nothing required
high:
# Not required.
- swof_opt.inc
- sgof_opt.inc
low: # a unified file with SWOF and SGOF or two separate files. Nothing required
low:
# Not required
- swof_pes.inc
- sgof_pes.inc

result_file : outfilen.inc
result_file: outfile.inc

delta_s : 0.001 # optional: defaulted to 0.01 this does not work as expected!
delta_s: 0.001 # optional, defaulted to 0.01

interpolations:
- param_w : -0.9975
param_g : -0.44

- tables : [] # all
param_w : -0.9975
param_g : -0.44
- tables : [1] # 1,3,6 #count from 1 NOT from 0
param_w : 0.3975
- tables : [2] # 1,3,6 #count from 1 NOT from 0
param_w : 0.1975







- param_w: -0.9975
param_g: -0.44

- tables: [] # all
param_w: -0.9975
param_g: -0.44
- tables: [1] # 1,3,6 # count from 1 NOT from 0
param_w: 0.3975
- tables: [2] # 1,3,6 # count from 1 NOT from 0
param_w: 0.1975