From 467edd6aae23e80a39ad67c9217542bdc5bc833f Mon Sep 17 00:00:00 2001 From: Dan Sava Date: Wed, 15 Nov 2023 15:35:57 +0200 Subject: [PATCH] Replace ecl with resdata (#234) * Replace ecl with resdata * Fix doc yaml block * Lock setuptools_scm version * Fix doc building (cherry picked from commit 459ddb083dc43adee30a81e5544060134a04c432) --- .github/workflows/fmu-ensemble.yml | 3 ++- docs/advancedusage.rst | 16 ++++++++-------- setup.py | 14 ++------------ src/fmu/ensemble/ensemble.py | 22 +++++++++++----------- src/fmu/ensemble/ensembleset.py | 14 +++++++------- src/fmu/ensemble/realization.py | 22 +++++++++------------- tests/test_realization.py | 4 ++-- 7 files changed, 41 insertions(+), 54 deletions(-) diff --git a/.github/workflows/fmu-ensemble.yml b/.github/workflows/fmu-ensemble.yml index 4325f6e5..831d5de1 100644 --- a/.github/workflows/fmu-ensemble.yml +++ b/.github/workflows/fmu-ensemble.yml @@ -66,7 +66,8 @@ jobs: - name: Build docs run: | sphinx-apidoc -H "API for fmu.ensemble" -o ./docs ./src/fmu - python setup.py build_sphinx + mkdir tmp + sphinx-build -W -b html -d tmp/doctrees docs build/sphinx/html touch build/sphinx/html/.nojekyll - name: 🚢 Build and deploy Python package diff --git a/docs/advancedusage.rst b/docs/advancedusage.rst index f35954e9..a9a78e45 100644 --- a/docs/advancedusage.rst +++ b/docs/advancedusage.rst @@ -175,13 +175,13 @@ matching), use the YAML syntax: # Mandatory elements per entry: key and observations - key: WBP4:OP_1 # This is a global comment regarding this set of observations - comment: "Shut-in pressures converted from well head conditions" - observations: - # Mandatory elements per entry in ecl_vector observations: value, error, date - - {value: 251, error: 4, date: 2001-01-01} - - {value: 251, error: 10, date: 2002-01-01} - - {value: 251, error: 10, date: 2003-01-01, - comment: First measurement after sensor drift correction} + comment: "Shut-in pressures converted from well head conditions" + observations: + # Mandatory elements per entry in ecl_vector observations: value, error, date + - {value: 251, error: 4, date: 2001-01-01} + - {value: 251, error: 10, date: 2002-01-01} + - {value: 251, error: 10, date: 2003-01-01, + comment: First measurement after sensor drift correction} Representative realizations @@ -324,7 +324,7 @@ VirtualRealization object from an Ensemble object. If we want only the aggregated table for our particular custom function, we can aggregate the ensemble only for that particular datatype: -.. code-block:: ipython +.. code-block:: In [1]: mean_realization = ensemble.agg("mean", keylist="zonestats.csv") In [2]: mean_realization.get_df("zonestats.csv") diff --git a/setup.py b/setup.py index 7a379f6e..7bf58075 100644 --- a/setup.py +++ b/setup.py @@ -3,15 +3,6 @@ """The setup script.""" from setuptools import setup, find_packages -try: - from sphinx.setup_command import BuildDoc - - cmdclass = {"build_sphinx": BuildDoc} -except ImportError: - # sphinx not installed - do not provide build_sphinx cmd - cmdclass = {} - - with open("README.rst") as readme_file: readme = readme_file.read() @@ -20,13 +11,13 @@ history = history_file.read().decode("UTF-8") REQUIREMENTS = [ - "ecl>=2.9", + "resdata>=4.0.0", "numpy", "pandas", "pyyaml>=5.1", ] -SETUP_REQUIREMENTS = ["setuptools>=28", "setuptools_scm"] +SETUP_REQUIREMENTS = ["setuptools>=28", "setuptools_scm < 6.1"] with open("test_requirements.txt") as f: test_requirements = f.read().splitlines() @@ -42,7 +33,6 @@ setup( name="fmu-ensemble", use_scm_version={"write_to": "src/fmu/ensemble/version.py"}, - cmdclass=cmdclass, description="Python API to ensembles produced by ERT", long_description=readme + "\n\n" + history, author="Håvard Berland", diff --git a/src/fmu/ensemble/ensemble.py b/src/fmu/ensemble/ensemble.py index 04fa5f68..fab01286 100644 --- a/src/fmu/ensemble/ensemble.py +++ b/src/fmu/ensemble/ensemble.py @@ -10,8 +10,8 @@ import pandas as pd import numpy as np import yaml -from ecl import EclDataType -from ecl.eclfile import EclKW +from resdata import ResDataType +from resdata.resfile import ResdataKW from .etc import Interaction # noqa from .realization import ScratchRealization @@ -723,7 +723,7 @@ def load_smry( you have retrieved it through get_smry() Wraps around Realization.load_smry() which wraps around - ecl.summary.EclSum.pandas_frame() + resdata.summary.Summary.pandas_frame() Beware that the default time_index for ensembles is 'monthly', differing from realizations which use raw dates by default. @@ -1386,7 +1386,7 @@ def get_smry( Aggregates summary data from all realizations. Wraps around Realization.get_smry() which wraps around - ecl.summary.EclSum.pandas_frame() + resdata.summary.Summary.pandas_frame() Args: time_index: list of DateTime if interpolation is wanted @@ -1499,7 +1499,7 @@ def get_eclgrid(self, props, report=0, agg="mean", active_only=False): @property def global_active(self): """ - :returns: An EclKw with, for each cell, + :returns: An ResdataKW with, for each cell, the number of realizations where the cell is active. """ warnings.warn( @@ -1510,8 +1510,8 @@ def global_active(self): FutureWarning, ) if not self._global_active: - self._global_active = EclKW( - "eactive", self.global_size, EclDataType.ECL_INT + self._global_active = ResdataKW( + "eactive", self.global_size, ResDataType.RD_INT ) for realization in self.realizations.values(): if realization.get_grid() is not None: @@ -1674,13 +1674,13 @@ def _keyword_mean(self, prop, global_active, report=None): """ :returns: Mean values of keywords. :param prop: Name of resulting Keyword. - :param global_active: A EclKW with, for each cell, The number of + :param global_active: A ResdataKW with, for each cell, The number of realizations where the cell is active. :param report: Report step for unrst keywords """ # ensemble._keyword_mean() is deprecated and # will be removed in fmu-ensemble v2.0.0 - mean = EclKW(prop, len(global_active), EclDataType.ECL_FLOAT) + mean = ResdataKW(prop, len(global_active), ResDataType.RD_FLOAT) if report: for _, realization in self.realizations.items(): if realization.get_unrst() is not None: @@ -1698,13 +1698,13 @@ def _keyword_std_dev(self, prop, global_active, mean, report=0): :returns: Standard deviation of keywords. :param name: Name of resulting Keyword. :param keywords: List of pairs of keywords and list of active cell - :param global_active: A EclKW with, for each cell, The number of + :param global_active: A ResdataKW with, for each cell, The number of realizations where the cell is active. :param mean: Mean of keywords. """ # ensemble._keyword_std_dev() is deprecated and # will be removed in fmu-ensemble v2.0.0 - std_dev = EclKW(prop, len(global_active), EclDataType.ECL_FLOAT) + std_dev = ResdataKW(prop, len(global_active), ResDataType.RD_FLOAT) if report: for _, realization in self.realizations.items(): real_prop = realization.get_global_unrst_keyword(prop, report) diff --git a/src/fmu/ensemble/ensembleset.py b/src/fmu/ensemble/ensembleset.py index a17d6e3c..64eeadf5 100644 --- a/src/fmu/ensemble/ensembleset.py +++ b/src/fmu/ensemble/ensembleset.py @@ -580,7 +580,7 @@ def load_smry( Fetch summary data from all ensembles Wraps around Ensemble.load_smry() which wraps - Realization.load_smry(), which wraps ecl.summary.EclSum.pandas_frame() + Realization.load_smry(), which wraps resdata.summary.Summary.pandas_frame() The time index is determined at realization level. If you ask for 'monthly', you will from each realization get its @@ -596,8 +596,8 @@ def load_smry( If a string is supplied, that string is attempted used via get_smry_dates() in order to obtain a time index. column_keys: list of column key wildcards - cache_eclsum: Boolean for whether we should cache the EclSum - objects. Set to False if you cannot keep all EclSum files in + cache_eclsum: Boolean for whether we should cache the Summary + objects. Set to False if you cannot keep all Summary files in memory simultaneously start_date: str or date with first date to include. Dates prior to this date will be dropped, supplied @@ -648,7 +648,7 @@ def get_smry( Wraps around Ensemble.get_smry(), which wraps around Realization.get_smry() which wraps around - ecl.summary.EclSum.pandas_frame() + resdata.summary.Summary.pandas_frame() Args: time_index: list of DateTime if interpolation is wanted @@ -656,7 +656,7 @@ def get_smry( If a string is supplied, that string is attempted used via get_smry_dates() in order to obtain a time index. column_keys: list of column key wildcards - cache_eclsum: boolean for whether to cache the EclSum + cache_eclsum: boolean for whether to cache the Summary objects. Defaults to False. Set to True if there is enough memory to keep all realizations summary files in memory at once. This will speed up subsequent @@ -709,8 +709,8 @@ def get_smry_dates( yield the sorted union of all valid timesteps for all realizations. Other valid options are 'daily', 'monthly' and 'yearly'. - cache_eclsum: Boolean for whether we should cache the EclSum - objects. Set to False if you cannot keep all EclSum files in + cache_eclsum: Boolean for whether we should cache the Summary + objects. Set to False if you cannot keep all Summary files in memory simultaneously start_date: str or date with first date to include. Dates prior to this date will be dropped, supplied diff --git a/src/fmu/ensemble/realization.py b/src/fmu/ensemble/realization.py index 9b31d35a..511be011 100644 --- a/src/fmu/ensemble/realization.py +++ b/src/fmu/ensemble/realization.py @@ -21,10 +21,10 @@ import numpy as np import pandas as pd -import ecl.summary -from ecl.eclfile import EclFile -from ecl.grid import EclGrid -from ecl import EclFileFlagEnum +from resdata.summary import Summary +from resdata.resfile import ResdataFile +from resdata.rd_util import FileMode +from resdata.grid import Grid from .virtualrealization import VirtualRealization from .realizationcombination import RealizationCombination @@ -947,7 +947,7 @@ def get_eclsum(self, cache=True, include_restart=True): if not os.path.exists(unsmry_filename): return None try: - eclsum = ecl.summary.EclSum( + eclsum = Summary( unsmry_filename, lazy_load=False, include_restart=include_restart ) except IOError: @@ -986,7 +986,7 @@ def load_smry( on the chosen time_index. If a custom time_index (list of datetime) was supplied, will be called 'custom'. - Wraps ecl.summary.EclSum.pandas_frame() + Wraps resdata.summary.Summary.pandas_frame() See also get_smry() @@ -1480,9 +1480,7 @@ def get_init(self): return None if not self._eclinit: - self._eclinit = EclFile( - init_filename, flags=EclFileFlagEnum.ECL_FILE_CLOSE_STREAM - ) + self._eclinit = ResdataFile(init_filename, flags=FileMode.CLOSE_STREAM) return self._eclinit def get_unrst(self): @@ -1509,9 +1507,7 @@ def get_unrst(self): if not os.path.exists(unrst_filename): return None if not self._eclunrst: - self._eclunrst = EclFile( - unrst_filename, flags=EclFileFlagEnum.ECL_FILE_CLOSE_STREAM - ) + self._eclunrst = ResdataFile(unrst_filename, flags=FileMode.CLOSE_STREAM) return self._eclunrst def get_grid_index(self, active_only): @@ -1614,7 +1610,7 @@ def get_grid(self): if not os.path.exists(grid_filename): return None if not self._eclgrid: - self._eclgrid = EclGrid(grid_filename) + self._eclgrid = Grid(grid_filename) return self._eclgrid @property diff --git a/tests/test_realization.py b/tests/test_realization.py index 70e1e216..f9a6a9c9 100644 --- a/tests/test_realization.py +++ b/tests/test_realization.py @@ -10,7 +10,7 @@ from dateutil.relativedelta import relativedelta import pytest -import ecl.summary +from resdata.summary import Summary import numpy as np @@ -475,7 +475,7 @@ def test_singlereal_ecl(tmp="TMP"): real = ensemble.ScratchRealization(realdir) # Eclipse summary files: - assert isinstance(real.get_eclsum(), ecl.summary.EclSum) + assert isinstance(real.get_eclsum(), Summary) if not os.path.exists(tmp): os.mkdir(tmp) real.load_smry().to_csv(os.path.join(tmp, "real0smry.csv"), index=False)