From d2ef39f1c05c59e5e482774335ef21d6dbf0f6c9 Mon Sep 17 00:00:00 2001 From: Asgeir Nyvoll Date: Tue, 30 Jan 2024 14:21:30 +0100 Subject: [PATCH] replace ecl2df with res2df --- .github/workflows/fmu-ensemble.yml | 2 +- docs/advancedusage.rst | 22 +++++----- src/fmu/ensemble/realization.py | 20 ++++----- tests/test_ensemble.py | 1 + tests/test_realization.py | 1 + tests/{test_ecl2df.py => test_res2df.py} | 52 ++++++++++++------------ tests/test_util.py | 1 + tests/test_virtualrealization.py | 1 + 8 files changed, 53 insertions(+), 47 deletions(-) rename tests/{test_ecl2df.py => test_res2df.py} (62%) diff --git a/.github/workflows/fmu-ensemble.yml b/.github/workflows/fmu-ensemble.yml index 98b0ca0f..a0e65ed0 100644 --- a/.github/workflows/fmu-ensemble.yml +++ b/.github/workflows/fmu-ensemble.yml @@ -42,7 +42,7 @@ jobs: - name: 📦 Install test dependencies run: | - pip install ecl2df + pip install res2df pip install .[tests,docs] - name: 🧾 List all installed packages diff --git a/docs/advancedusage.rst b/docs/advancedusage.rst index 6dff3f93..3437a4c9 100644 --- a/docs/advancedusage.rst +++ b/docs/advancedusage.rst @@ -253,15 +253,15 @@ in the realization object to use, potentially only the directory). :header-rows: 1 where PORV and VOLUME are sums over each zone, Z is the minimum (thus apex pr. -zone) and PERMX is an arithmetic mean. In the language of `ecl2df -`_ this could be done with a code like this: +zone) and PERMX is an arithmetic mean. In the language of `res2df +`_ this could be done with a code like this: .. code-block:: python - from ecl2df import grid, EclFiles + from res2df import grid, ResdataFiles - eclfiles = EclFiles('MYDATADECK.DATA') # There is a file zones.lyr alongside this. - grid_df = grid.df(eclfiles) # Produce a dataframe with one row pr. cell + resdatafiles = ResdataFiles('MYDATADECK.DATA') # There is a file zones.lyr alongside this. + grid_df = grid.df(resdatafiles) # Produce a dataframe with one row pr. cell my_aggregators = {'PORV': 'sum', 'VOLUME': 'sum', 'Z': 'min', 'PERMX': 'mean'} stats_df = grid_df.groupby("ZONE").agg(my_aggregators) print(stats_df) @@ -269,10 +269,10 @@ zone) and PERMX is an arithmetic mean. In the language of `ecl2df ``ScratchRealization`` objects contain the methods ``runpath()`` which will give the full path to the directory the realization resides in, this can be used -freely by your function. For easier coupling with ecl2df, the function -``get_eclfiles()`` is provided. +freely by your function. For easier coupling with res2df, the function +``get_resdatafiles()`` is provided. -To be able to inject the ecl2df lines above into the API of fmu.ensemble and the +To be able to inject the res2df lines above into the API of fmu.ensemble and the :py:meth:`apply() ` function, we need to to put it into a wrapper function. This wrapper function will always receive a Realization object as a named argument, and it must return a @@ -280,7 +280,7 @@ dataframe. The wrapper function can look like this: .. code-block:: python - from ecl2df import grid, EclFiles + from res2df import grid, ResdataFiles def my_realization_stats(args): """A custom function for performing a particular calculation @@ -290,8 +290,8 @@ dataframe. The wrapper function can look like this: args (dict): A dictionary with parameters to my custom function. The keys 'realization' and 'localpath' are reserved for fmu.ensemble.""" realization = args["realization"] # Provided by fmu.ensemble apply() - eclfiles = realization.get_eclfiles() - grid_df = grid.df(eclfiles) + resdatafiles = realization.get_resdatafiles() + grid_df = grid.df(resdatafiles) my_aggregators = {'PORV': 'sum', 'VOLUME': 'sum', 'Z': 'min', 'PERMX': 'mean'} stats_df = grid_df.groupby("ZONE").agg(my_aggregators) return stats_df.reset_index() # Zone names are in the index, lost if not reset. diff --git a/src/fmu/ensemble/realization.py b/src/fmu/ensemble/realization.py index 95c1f21c..a7a5064b 100644 --- a/src/fmu/ensemble/realization.py +++ b/src/fmu/ensemble/realization.py @@ -31,13 +31,13 @@ from .util.rates import compute_volumetric_rates from .virtualrealization import VirtualRealization -HAVE_ECL2DF = False +HAVE_RES2DF = False try: - import ecl2df + import res2df - HAVE_ECL2DF = True + HAVE_RES2DF = True except ImportError: - HAVE_ECL2DF = False + HAVE_RES2DF = False logger = logging.getLogger(__name__) @@ -844,9 +844,9 @@ def parameters(self): """ return self.data["parameters.txt"] - def get_eclfiles(self): + def get_resdatafiles(self): """ - Return an ecl2df.EclFiles object to connect to the ecl2df package + Return an res2df.ResdataFiles object to connect to the res2df package If autodiscovery, it will search for a DATA file in the standard location eclipse/model/...DATA. @@ -858,10 +858,10 @@ def get_eclfiles(self): >>> real.find_files("eclipse/model/MYMODELPREDICTION.DATA") Returns: - ecl2df.EclFiles. None if nothing found + res2df.ResdataFiles. None if nothing found """ - if not HAVE_ECL2DF: - logger.warning("ecl2df not installed. Skipping") + if not HAVE_RES2DF: + logger.warning("res2df not installed. Skipping") return None data_file_row = self.files[self.files["FILETYPE"] == "DATA"] data_filename = None @@ -887,7 +887,7 @@ def get_eclfiles(self): return None if not os.path.exists(data_filename): return None - return ecl2df.EclFiles(data_filename) + return res2df.ResdataFiles(data_filename) def get_eclsum(self, cache=True, include_restart=True): """ diff --git a/tests/test_ensemble.py b/tests/test_ensemble.py index 381d15c7..e52da755 100644 --- a/tests/test_ensemble.py +++ b/tests/test_ensemble.py @@ -1,4 +1,5 @@ """Testing fmu-ensemble.""" + # pylint: disable=protected-access import logging diff --git a/tests/test_realization.py b/tests/test_realization.py index 690f013a..07417767 100644 --- a/tests/test_realization.py +++ b/tests/test_realization.py @@ -1,4 +1,5 @@ """Testing fmu-ensemble.""" + # pylint: disable=protected-access import datetime diff --git a/tests/test_ecl2df.py b/tests/test_res2df.py similarity index 62% rename from tests/test_ecl2df.py rename to tests/test_res2df.py index 227c77eb..151930c1 100644 --- a/tests/test_ecl2df.py +++ b/tests/test_res2df.py @@ -1,4 +1,4 @@ -"""Testing incorporation of ecl2df in fmu-ensemble.""" +"""Testing incorporation of res2df in fmu-ensemble.""" import logging import os @@ -6,19 +6,19 @@ import pytest from fmu.ensemble import ScratchEnsemble, ScratchRealization -HAVE_ECL2DF = True +HAVE_RES2DF = True try: - import ecl2df + import res2df except ImportError: - HAVE_ECL2DF = False + HAVE_RES2DF = False logger = logging.getLogger(__name__) -def test_ecl2df_real(): - """Check that we can utilize ecl2df on single realizations""" +def test_res2df_real(): + """Check that we can utilize res2df on single realizations""" - if not HAVE_ECL2DF: + if not HAVE_RES2DF: pytest.skip() if "__file__" in globals(): @@ -29,15 +29,15 @@ def test_ecl2df_real(): realdir = os.path.join(testdir, "data/testensemble-reek001", "realization-0/iter-0") real = ScratchRealization(realdir) - eclfiles = real.get_eclfiles() - assert isinstance(eclfiles, ecl2df.EclFiles) - compdat_df = ecl2df.compdat.df(eclfiles) + resdatafiles = real.get_resdatafiles() + assert isinstance(resdatafiles, res2df.ResdataFiles) + compdat_df = res2df.compdat.df(resdatafiles) assert not compdat_df.empty assert "KH" in compdat_df def test_reek(): - """Import the reek ensemble and apply ecl2df functions on + """Import the reek ensemble and apply res2df functions on the realizations""" if "__file__" in globals(): @@ -48,19 +48,19 @@ def test_reek(): reekens = ScratchEnsemble( "reektest", testdir + "/data/testensemble-reek001/" + "realization-*/iter-0" ) - if not HAVE_ECL2DF: + if not HAVE_RES2DF: pytest.skip() def extract_compdat(kwargs): - """Callback fnction to extract compdata data using ecl2df + """Callback fnction to extract compdata data using res2df on a ScratchRealization""" - eclfiles = kwargs["realization"].get_eclfiles() - if not eclfiles: + resdatafiles = kwargs["realization"].get_resdatafiles() + if not resdatafiles: print( - "Could not obtain EclFiles object for realization " + "Could not obtain ResdataFiles object for realization " + str(kwargs["realization"].index) ) - return ecl2df.compdat.deck2dfs(eclfiles.get_ecldeck())["COMPDAT"] + return res2df.compdat.deck2dfs(resdatafiles.get_deck())["COMPDAT"] allcompdats = reekens.apply(extract_compdat) assert not allcompdats.empty @@ -69,16 +69,18 @@ def extract_compdat(kwargs): # Pr. now, only realization-0 has eclipse/include in git -def test_smry_via_ecl2df(): - """Test that we could use ecl2df for smry extraction instead +def test_smry_via_res2df(): + """Test that we could use res2df for smry extraction instead of the native code inside fmu-ensemble""" def get_smry(kwargs): - """Callback function to extract smry data using ecl2df on a + """Callback function to extract smry data using res2df on a ScratchRealization""" - eclfiles = kwargs["realization"].get_eclfiles() - return ecl2df.summary.df( - eclfiles, time_index=kwargs["time_index"], column_keys=kwargs["column_keys"] + resdatafiles = kwargs["realization"].get_resdatafiles() + return res2df.summary.df( + resdatafiles, + time_index=kwargs["time_index"], + column_keys=kwargs["column_keys"], ) if "__file__" in globals(): @@ -89,7 +91,7 @@ def get_smry(kwargs): reekens = ScratchEnsemble( "reektest", testdir + "/data/testensemble-reek001/" + "realization-*/iter-0" ) - if not HAVE_ECL2DF: + if not HAVE_RES2DF: pytest.skip() callback_smry = reekens.apply(get_smry, column_keys="FOPT", time_index="yearly") @@ -97,4 +99,4 @@ def get_smry(kwargs): assert callback_smry["FOPT"].sum() == direct_smry["FOPT"].sum() assert callback_smry["REAL"].sum() == direct_smry["REAL"].sum() - # BUG in ecl2df, dates are missing!! + # BUG in res2df, dates are missing!! diff --git a/tests/test_util.py b/tests/test_util.py index c0e9e72d..e45a45d2 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,4 +1,5 @@ """Test general utility functions in use by fmu.ensemble""" + import datetime import logging diff --git a/tests/test_virtualrealization.py b/tests/test_virtualrealization.py index 1acf6d66..41a9c5b2 100644 --- a/tests/test_virtualrealization.py +++ b/tests/test_virtualrealization.py @@ -1,4 +1,5 @@ """Testing fmu-ensemble, virtual realizations""" + # pylint: disable=protected-access,duplicate-code import datetime