From d609e86654e60a831de3f70ea1b7623b0f49af7f Mon Sep 17 00:00:00 2001 From: Asgeir Nyvoll Date: Tue, 8 Feb 2022 10:39:29 +0100 Subject: [PATCH] Add Eclipse relperm family 2 to df output --- pyscal/pyscallist.py | 131 +++++++++++++++++++++++------------ pyscal/scalrecommendation.py | 2 +- pyscal/wateroilgas.py | 77 +++++++++++--------- 3 files changed, 133 insertions(+), 77 deletions(-) diff --git a/pyscal/pyscallist.py b/pyscal/pyscallist.py index 91920e5f..886914ec 100644 --- a/pyscal/pyscallist.py +++ b/pyscal/pyscallist.py @@ -89,16 +89,19 @@ def df(self) -> pd.DataFrame: will contain the strings 'pess', 'base' and 'opt' (independent of any alias name potentially used in an input xlsx/csv) """ - # Names of dataframe columns in wateroil/gasoil.table: + # Names of dataframe columns in wateroil/gasoil.table, SOF3 and SLGOF: wateroil_pyscal_cols = {"SW", "KRW", "KROW", "PC"} gasoil_pyscal_cols = {"SG", "KRG", "KROG", "PC"} + sof3_cols = {"SO", "KROW", "KROG"} + slgof_cols = {"SL", "KRG", "KROG", "PC"} # Renamers applied to the returned dataframe: gasoil_col_renamer = {"SG": "SG", "KRG": "KRG", "KROG": "KROG", "PC": "PCOG"} wateroil_col_renamer = {"SW": "SW", "KRW": "KRW", "KROW": "KROW", "PC": "PCOW"} + slgof_col_renamer = {"SL": "SL", "KRG": "KRG", "KROG": "KROG", "PC": "PCOG"} # Sort order for rows in returned dataframe: - sort_candidates = ["SATNUM", "CASE", "KEYWORD", "SW", "SG", "SL"] + sort_candidates = ["SATNUM", "CASE", "KEYWORD", "SW", "SG", "SL", "SO"] df_list = [] if self.pyscaltype == WaterOilGas: @@ -122,55 +125,93 @@ def df(self) -> pd.DataFrame: .assign(SATNUM=satnum + 1) .rename(wateroil_col_renamer, axis="columns") ) + df_list.append( + wateroilgas.sof3_df()[sof3_cols].assign(SATNUM=satnum + 1) + ) + df_list.append( + wateroilgas.gasoil.slgof_df()[gasoil_cols] + .assign(SATNUM=satnum + 1) + .rename(gasoil_col_renamer, axis="columns") + ) elif self.pyscaltype == SCALrecommendation: for (satnum, scalrec) in enumerate(self.pyscal_list): assert isinstance(scalrec, SCALrecommendation) assert scalrec.low is not None assert scalrec.base is not None assert scalrec.high is not None - assert scalrec.low.wateroil is not None - assert scalrec.low.gasoil is not None - assert scalrec.base.wateroil is not None - assert scalrec.base.gasoil is not None - assert scalrec.high.wateroil is not None - assert scalrec.high.gasoil is not None - gasoil_cols = set(scalrec.base.gasoil.table.columns).intersection( - gasoil_pyscal_cols - ) - wateroil_cols = set(scalrec.base.wateroil.table.columns).intersection( - wateroil_pyscal_cols - ) - df_list.append( - scalrec.low.gasoil.table[gasoil_cols] - .assign(SATNUM=satnum + 1, CASE="pess") - .rename(gasoil_col_renamer, axis="columns") - ) - df_list.append( - scalrec.base.gasoil.table[gasoil_cols] - .assign(SATNUM=satnum + 1, CASE="base") - .rename(gasoil_col_renamer, axis="columns") - ) - df_list.append( - scalrec.high.gasoil.table[gasoil_cols] - .assign(SATNUM=satnum + 1, CASE="opt") - .rename(gasoil_col_renamer, axis="columns") - ) - - df_list.append( - scalrec.low.wateroil.table[wateroil_cols] - .assign(SATNUM=satnum + 1, CASE="pess") - .rename(wateroil_col_renamer, axis="columns") - ) - df_list.append( - scalrec.base.wateroil.table[wateroil_cols] - .assign(SATNUM=satnum + 1, CASE="base") - .rename(wateroil_col_renamer, axis="columns") - ) - df_list.append( - scalrec.high.wateroil.table[wateroil_cols] - .assign(SATNUM=satnum + 1, CASE="opt") - .rename(wateroil_col_renamer, axis="columns") - ) + if scalrec.type == WaterOilGas: + assert scalrec.low.wateroil is not None + assert scalrec.low.gasoil is not None + assert scalrec.base.wateroil is not None + assert scalrec.base.gasoil is not None + assert scalrec.high.wateroil is not None + assert scalrec.high.gasoil is not None + gasoil_cols = set(scalrec.base.gasoil.table.columns).intersection( + gasoil_pyscal_cols + ) + wateroil_cols = set( + scalrec.base.wateroil.table.columns + ).intersection(wateroil_pyscal_cols) + df_list.append( + scalrec.low.gasoil.table[gasoil_cols] + .assign(SATNUM=satnum + 1, CASE="pess") + .rename(gasoil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.base.gasoil.table[gasoil_cols] + .assign(SATNUM=satnum + 1, CASE="base") + .rename(gasoil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.high.gasoil.table[gasoil_cols] + .assign(SATNUM=satnum + 1, CASE="opt") + .rename(gasoil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.low.wateroil.table[wateroil_cols] + .assign(SATNUM=satnum + 1, CASE="pess") + .rename(wateroil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.base.wateroil.table[wateroil_cols] + .assign(SATNUM=satnum + 1, CASE="base") + .rename(wateroil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.high.wateroil.table[wateroil_cols] + .assign(SATNUM=satnum + 1, CASE="opt") + .rename(wateroil_col_renamer, axis="columns") + ) + df_list.append( + scalrec.low.sof3_df()[sof3_cols].assign( + SATNUM=satnum + 1, CASE="pess" + ) + ) + df_list.append( + scalrec.base.sof3_df()[sof3_cols].assign( + SATNUM=satnum + 1, CASE="base" + ) + ) + df_list.append( + scalrec.low.sof3_df()[sof3_cols].assign( + SATNUM=satnum + 1, CASE="opt" + ) + ) + df_list.append( + scalrec.low.gasoil.slgof_df()[slgof_cols] + .assign(SATNUM=satnum + 1, CASE="pess") + .rename(slgof_col_renamer, axis="columns") + ) + df_list.append( + scalrec.base.gasoil.slgof_df()[slgof_cols] + .assign(SATNUM=satnum + 1, CASE="base") + .rename(slgof_col_renamer, axis="columns") + ) + df_list.append( + scalrec.high.gasoil.slgof_df()[slgof_cols] + .assign(SATNUM=satnum + 1, CASE="opt") + .rename(slgof_col_renamer, axis="columns") + ) elif self.pyscaltype == WaterOil: for (satnum, wateroil) in enumerate(self.pyscal_list): assert isinstance(wateroil, WaterOil) diff --git a/pyscal/scalrecommendation.py b/pyscal/scalrecommendation.py index b3fcb755..16edcb3b 100644 --- a/pyscal/scalrecommendation.py +++ b/pyscal/scalrecommendation.py @@ -12,7 +12,7 @@ class SCALrecommendation(object): - """A SCAL recommendation consists of three OilWaterGas objects, + """A SCAL recommendation consists of three WaterOilGas objects, tagged low, base and high. This container exists in order to to interpolation from -1 (low), diff --git a/pyscal/wateroilgas.py b/pyscal/wateroilgas.py index 10f799b9..cda75c4e 100644 --- a/pyscal/wateroilgas.py +++ b/pyscal/wateroilgas.py @@ -144,37 +144,7 @@ def SOF3(self, header: bool = True, dataincommentrow: bool = True) -> str: ): logger.error("Both WaterOil and GasOil krow/krog is needed for SOF3") return "" - self.threephaseconsistency() - - # Copy of the wateroil data: - table = pd.DataFrame(self.wateroil.table[["SW", "KROW"]]) - table["SO"] = 1 - table["SW"] - - # Copy of the gasoil data: - gastable = pd.DataFrame(self.gasoil.table[["SG", "KROG"]]) - gastable["SO"] = 1 - gastable["SG"] - self.wateroil.swl - - # Merge WaterOil and GasOil on oil saturation, interpolate for - # missing data (potentially different sg- and sw-grids) - sof3table = ( - pd.concat([table, gastable], sort=True) - .set_index("SO") - .sort_index() - .interpolate(method="slinear") - .fillna(method="ffill") - .fillna(method="bfill") - .reset_index() - ) - sof3table["soint"] = list( - map(int, list(map(round, sof3table["SO"] * SWINTEGERS))) - ) - sof3table.drop_duplicates("soint", inplace=True) - - # The 'so' column has been calculated from floating point numbers - # and the zero value easily becomes a negative zero, circumvent this: - zerorow = np.isclose(sof3table["SO"], 0.0) - sof3table.loc[zerorow, "SO"] = abs(sof3table.loc[zerorow, "SO"]) - + sof3table = self.sof3_df() string = "" if header: string += "SOF3\n" @@ -298,3 +268,48 @@ def threephaseconsistency(self) -> bool: # swl=0.45, (1-swl) = 0.55 return wog_is_ok + + def sof3_df(self) -> pd.DataFrame: + """Return a SOF3 DataFrame, 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 + """ + if (self.wateroil is None or self.gasoil is None) or ( + "KROW" not in self.wateroil.table or "KROG" not in self.gasoil.table + ): + logger.error("Both WaterOil and GasOil krow/krog is needed for SOF3") + return pd.DataFrame() + self.threephaseconsistency() + + # Copy of the wateroil data: + table = pd.DataFrame(self.wateroil.table[["SW", "KROW"]]) + table["SO"] = 1 - table["SW"] + + # Copy of the gasoil data: + gastable = pd.DataFrame(self.gasoil.table[["SG", "KROG"]]) + gastable["SO"] = 1 - gastable["SG"] - self.wateroil.swl + + # Merge WaterOil and GasOil on oil saturation, interpolate for + # missing data (potentially different sg- and sw-grids) + sof3table = ( + pd.concat([table, gastable], sort=True) + .set_index("SO") + .sort_index() + .interpolate(method="slinear") + .fillna(method="ffill") + .fillna(method="bfill") + .reset_index() + ) + sof3table["soint"] = list( + map(int, list(map(round, sof3table["SO"] * SWINTEGERS))) + ) + sof3table.drop_duplicates("soint", inplace=True) + + # The 'so' column has been calculated from floating point numbers + # and the zero value easily becomes a negative zero, circumvent this: + zerorow = np.isclose(sof3table["SO"], 0.0) + sof3table.loc[zerorow, "SO"] = abs(sof3table.loc[zerorow, "SO"]) + + return sof3table