From 90878e0930a430818f7d2aa70fc496d4e8e31d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dieter=20Werthm=C3=BCller?= Date: Fri, 6 Dec 2024 16:07:46 +0100 Subject: [PATCH 1/2] resmda->dageo; ES-MDA->ESMDA --- .github/workflows/linux.yml | 4 ++-- .gitignore | 6 ++--- Makefile | 12 +++++----- README.rst | 20 +++++++++------- {resmda => dageo}/__init__.py | 13 ++++------ {resmda => dageo}/data_assimilation.py | 18 +++++++------- {resmda => dageo}/reservoir_simulator.py | 4 ++-- {resmda => dageo}/utils.py | 6 ++--- docs/Makefile | 2 +- docs/api/data_assimilation.rst | 2 +- docs/api/index.rst | 2 +- docs/api/reservoir_simulator.rst | 2 +- docs/api/utils.rst | 2 +- docs/conf.py | 14 +++++------ docs/index.rst | 16 ++++++------- docs/manual/about.rst | 18 +++++++------- docs/manual/installation.rst | 10 ++++---- docs/manual/license.rst | 4 ++-- examples/README.rst | 2 +- examples/basicESMDA.py | 28 +++++++++++----------- examples/basicreservoir.py | 30 ++++++++++++------------ examples/fluvialreservoir.py | 26 ++++++++++---------- examples/geothermal.py | 28 +++++++++++----------- examples/localization.py | 26 ++++++++++---------- pyproject.toml | 18 +++++++------- tests/test_data_assimilation.py | 14 +++++------ tests/test_reservoir_simulator.py | 8 +++---- tests/test_utils.py | 4 ++-- 28 files changed, 169 insertions(+), 170 deletions(-) rename {resmda => dageo}/__init__.py (72%) rename {resmda => dageo}/data_assimilation.py (93%) rename {resmda => dageo}/reservoir_simulator.py (99%) rename {resmda => dageo}/utils.py (97%) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6912402..9f5d4f1 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -80,13 +80,13 @@ jobs: - name: Flake8 shell: bash -l {0} - run: flake8 docs/conf.py resmda/ tests/ + run: flake8 docs/conf.py dageo/ tests/ - name: Test with pytest shell: bash -l {0} run: | python -m pip install . - pytest --cov=resmda + pytest --cov=dageo deploy: needs: test diff --git a/.gitignore b/.gitignore index b319386..9117471 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ __pycache__/ # Sphinx docs/_build/ -docs/api/resmda* +docs/api/dageo* docs/savefig/ docs/gallery/* docs/sg_execution_times.rst @@ -15,10 +15,10 @@ htmlcov .pytest_cache/ # setuptools_scm -resmda/version.py +dageo/version.py # Build related .eggs/ build/ dist/ -resmda.egg-info/ +dageo.egg-info/ diff --git a/Makefile b/Makefile index 44ad6f5..4c11058 100644 --- a/Makefile +++ b/Makefile @@ -22,11 +22,11 @@ dev-install: .ONESHELL: pytest: rm -rf .coverage htmlcov/ .pytest_cache/ - pytest --cov=resmda + pytest --cov=dageo coverage html flake8: - flake8 docs/conf.py resmda/ tests/ examples/ + flake8 docs/conf.py dageo/ tests/ examples/ html: cd docs && make html @@ -35,7 +35,7 @@ html-noplot: cd docs && make html-noplot html-clean: - cd docs && rm -rf api/resmda* gallery/* _build/ && make html + cd docs && rm -rf api/dageo* gallery/* _build/ && make html preview: xdg-open docs/_build/html/index.html @@ -44,9 +44,9 @@ linkcheck: cd docs && make linkcheck clean: - python -m pip uninstall resmda -y - rm -rf build/ dist/ .eggs/ resmda.egg-info/ resmda/version.py # build + python -m pip uninstall dageo -y + rm -rf build/ dist/ .eggs/ dageo.egg-info/ dageo/version.py # build rm -rf */__pycache__/ */*/__pycache__/ # python cache rm -rf .coverage htmlcov/ .pytest_cache/ # tests and coverage - rm -rf docs/gallery/* docs/gallery/*.zip docs/_build/ docs/api/resmda* # docs + rm -rf docs/gallery/* docs/gallery/*.zip docs/_build/ docs/api/dageo* # docs rm -rf docs/savefig diff --git a/README.rst b/README.rst index d01e19e..21f7b4c 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,17 @@ -``resmda`` - ES-MDA with a simple 2D reservoir modeller -======================================================= +``dageo`` - Data Assimilation in Geosciences +============================================ -A simple 2D reservoir simulator and a straight-forward implementation of the -basic *Ensemble smoother with multiple data assimilation* (ES-MDA) algorithm as -presented by Emerick and Reynolds, 2013. +Data Assimilation in Geosciences is, for now, a simple 2D reservoir simulator +and a straight-forward implementation of the basic *Ensemble smoother with +multiple data assimilation* (ESMDA) algorithm as presented by Emerick and +Reynolds, 2013. However, more DA methods and examples might be added in the +future. -- **Documentation:** https://tuda-geo.github.io/resmda -- **Source Code:** https://github.com/tuda-geo/resmda -- **Bug reports:** https://github.com/tuda-geo/resmda/issues +- **Documentation:** https://tuda-geo.github.io/dageo +- **Source Code:** https://github.com/tuda-geo/dageo +- **Bug reports:** https://github.com/tuda-geo/dageo/issues Available through pip and conda: -``pip install resmda`` / ``conda install -c conda-forge resmda``. +``pip install dageo`` / ``conda install -c conda-forge dageo``. diff --git a/resmda/__init__.py b/dageo/__init__.py similarity index 72% rename from resmda/__init__.py rename to dageo/__init__.py index 6da7c9d..03f61ea 100644 --- a/resmda/__init__.py +++ b/dageo/__init__.py @@ -1,6 +1,6 @@ # Copyright 2024 D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel # -# This file is part of resmda. +# This file is part of dageo. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy @@ -14,13 +14,10 @@ # License for the specific language governing permissions and limitations under # the License. -from resmda import utils -from resmda.utils import localization_matrix, Report -from resmda.data_assimilation import esmda -from resmda.reservoir_simulator import Simulator, RandomPermeability - -print("Warning: `resmda` will change its name to `dageo`.") -print(" Install `dageo` to get the newest version.") +from dageo import utils +from dageo.utils import localization_matrix, Report +from dageo.data_assimilation import esmda +from dageo.reservoir_simulator import Simulator, RandomPermeability # Initialize a random number generator. rng = utils.rng() diff --git a/resmda/data_assimilation.py b/dageo/data_assimilation.py similarity index 93% rename from resmda/data_assimilation.py rename to dageo/data_assimilation.py index 11e872c..1e9f834 100644 --- a/resmda/data_assimilation.py +++ b/dageo/data_assimilation.py @@ -1,6 +1,6 @@ # Copyright 2024 D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel # -# This file is part of resmda. +# This file is part of dageo. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy @@ -16,7 +16,7 @@ import numpy as np -from resmda import utils +from dageo import utils __all__ = ['esmda'] @@ -28,10 +28,10 @@ def __dir__(): def esmda(model_prior, forward, data_obs, sigma, alphas=4, data_prior=None, localization_matrix=None, callback_post=None, return_post_data=True, return_steps=False, random=None): - """ES-MDA algorithm ([EmRe13]_) with optional localization. + """ESMDA algorithm ([EmRe13]_) with optional localization. Consult the section :ref:`esmda` in the manual for the theory and more - information about ES-MDA. + information about ESMDA. Parameters ---------- @@ -48,20 +48,20 @@ def esmda(model_prior, forward, data_obs, sigma, alphas=4, data_prior=None, sigma : {float, ndarray} Standard deviation(s) of the observation noise. alphas : {int, array-like}, default: 4 - Inflation factors for ES-MDA. + Inflation factors for ESMDA. data_prior : ndarray, default: None Prior data ensemble, of shape ``(ne, nd)``. callback_post : function, default: None - Function to be executed after each ES-MDA iteration to the posterior + Function to be executed after each ESMDA iteration to the posterior model, ``callback_post(model_post)``. return_post_data : bool, default: True If true, returns also ``forward(model_post)``. return_steps : bool, default: False - If true, returns model and data of all ES-MDA steps. Setting + If true, returns model and data of all ESMDA steps. Setting ``return_steps`` to True enforces ``return_post_data=True``. random : {None, int, np.random.Generator}, default: None Seed or random generator for reproducibility; see - :func:`resmda.utils.rng`. + :func:`dageo.utils.rng`. localization_matrix : {ndarray, None}, default: None If provided, apply localization to the Kalman gain matrix, of shape ``(model-shape, nd)``. @@ -97,7 +97,7 @@ def esmda(model_prior, forward, data_obs, sigma, alphas=4, data_prior=None, # Loop over alphas for i, alpha in enumerate(alphas): - print(f"ES-MDA step {i+1: 3d}; α={alpha}") + print(f"ESMDA step {i+1: 3d}; α={alpha}") # == Step (a) of Emerick & Reynolds, 2013 == # Run the ensemble from time zero. diff --git a/resmda/reservoir_simulator.py b/dageo/reservoir_simulator.py similarity index 99% rename from resmda/reservoir_simulator.py rename to dageo/reservoir_simulator.py index 039cef9..6c65680 100644 --- a/resmda/reservoir_simulator.py +++ b/dageo/reservoir_simulator.py @@ -1,6 +1,6 @@ # Copyright 2024 D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel # -# This file is part of resmda. +# This file is part of dageo. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy @@ -17,7 +17,7 @@ import numpy as np import scipy as sp -from resmda import utils +from dageo import utils __all__ = ['Simulator', 'RandomPermeability'] diff --git a/resmda/utils.py b/dageo/utils.py similarity index 97% rename from resmda/utils.py rename to dageo/utils.py index c95b764..5e230d0 100644 --- a/resmda/utils.py +++ b/dageo/utils.py @@ -1,6 +1,6 @@ # Copyright 2024 D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel # -# This file is part of resmda. +# This file is part of dageo. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy @@ -21,7 +21,7 @@ from scooby import Report as ScoobyReport try: - from resmda.version import version as __version__ + from dageo.version import version as __version__ except ImportError: __version__ = 'unknown-'+datetime.today().strftime('%Y%m%d') @@ -189,6 +189,6 @@ class Report(ScoobyReport): def __init__(self, **kwargs): """Initiate a scooby.Report instance.""" kwargs = {'ncol': 3, **kwargs} - kwargs['core'] = ['resmda', 'numpy', 'scipy'] + kwargs['core'] = ['dageo', 'numpy', 'scipy'] kwargs['optional'] = ['matplotlib', 'IPython'] super().__init__(**kwargs) diff --git a/docs/Makefile b/docs/Makefile index 469256b..98eff76 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,7 +1,7 @@ # Command line options. SPHINXOPTS = SPHINXBUILD = sphinx-build -SPHINXPROJ = resmda +SPHINXPROJ = dageo SOURCEDIR = . BUILDDIR = _build diff --git a/docs/api/data_assimilation.rst b/docs/api/data_assimilation.rst index c1d7e64..b8422ec 100644 --- a/docs/api/data_assimilation.rst +++ b/docs/api/data_assimilation.rst @@ -1,6 +1,6 @@ Data Assimilation ----------------- -.. automodapi:: resmda.data_assimilation +.. automodapi:: dageo.data_assimilation :no-inheritance-diagram: :no-heading: diff --git a/docs/api/index.rst b/docs/api/index.rst index f91d3e5..75f4ec9 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -9,7 +9,7 @@ API reference ---- -.. module:: resmda +.. module:: dageo .. toctree:: diff --git a/docs/api/reservoir_simulator.rst b/docs/api/reservoir_simulator.rst index 1e3bdbc..8dba591 100644 --- a/docs/api/reservoir_simulator.rst +++ b/docs/api/reservoir_simulator.rst @@ -1,6 +1,6 @@ Reservoir Simulator ------------------- -.. automodapi:: resmda.reservoir_simulator +.. automodapi:: dageo.reservoir_simulator :no-inheritance-diagram: :no-heading: diff --git a/docs/api/utils.rst b/docs/api/utils.rst index fff5471..52212b5 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -1,6 +1,6 @@ Utilities --------- -.. automodapi:: resmda.utils +.. automodapi:: dageo.utils :no-inheritance-diagram: :no-heading: diff --git a/docs/conf.py b/docs/conf.py index 6cda408..dc499e8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,6 @@ import time import warnings -from resmda import __version__ +from dageo import __version__ # ==== 1. Extensions ==== @@ -64,7 +64,7 @@ } # ==== 2. General Settings ==== -description = "ES-MDA with a simple 2D reservoir modeller" +description = "Data Assimilation in Geosciences" # The templates path. # templates_path = ["_templates"] @@ -76,7 +76,7 @@ master_doc = "index" # General information about the project. -project = "resmda" +project = "dageo" author = "D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel" copyright = f"2024-{time.strftime('%Y')}, {author}" @@ -99,23 +99,23 @@ html_theme_options = { "logo": { - "text": "resmda", + "text": "dageo", }, "navigation_with_keys": True, - "github_url": "https://github.com/tuda-geo/resmda", + "github_url": "https://github.com/tuda-geo/dageo", # "use_edit_page_button": True, } html_context = { "github_user": "tuda-geo", - "github_repo": "resmda", + "github_repo": "dageo", "github_version": "main", "doc_path": "docs", } html_use_modindex = True html_file_suffix = ".html" -htmlhelp_basename = "resmda" +htmlhelp_basename = "dageo" html_css_files = [ "style.css", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/" + diff --git a/docs/index.rst b/docs/index.rst index 3c5277f..1e7b046 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,12 +1,12 @@ -.. _resmda-manual: +.. _dageo-manual: -#################### -resmda Documentation -#################### +################### +dageo Documentation +################### :Release: |version| :Date: |today| -:Source: `github.com/tuda-geo/resmda `_ +:Source: `github.com/tuda-geo/dageo `_ ---- @@ -47,13 +47,13 @@ resmda Documentation Gallery ^^^^^^^ - The gallery contains examples on the usage of resmda, and is generally + The gallery contains examples on the usage of dageo, and is generally the best way to get started. Download them and modify them to your needs! +++ - .. button-ref:: resmda_gallery + .. button-ref:: dageo_gallery :expand: :color: info :click-parent: @@ -67,7 +67,7 @@ resmda Documentation API reference ^^^^^^^^^^^^^ - The API reference of resmda includes almost every function and class. + The API reference of dageo includes almost every function and class. Some of the underlying theory is also described in the docstrings. +++ diff --git a/docs/manual/about.rst b/docs/manual/about.rst index 02d99ac..069f296 100644 --- a/docs/manual/about.rst +++ b/docs/manual/about.rst @@ -2,22 +2,22 @@ About ===== A simple 2D reservoir simulator and a straight-forward implementation of the -basic *Ensemble Smoother with Multiple Data Assimilation* (ES-MDA) algorithm. +basic *Ensemble Smoother with Multiple Data Assimilation* (ESMDA) algorithm. .. _esmda: -ES-MDA ------- +ESMDA +----- In the following an introduction to the Ensemble Smoother with Multiple Data -Assimilation (ES-MDA) algorithm following [EmRe13]_: +Assimilation (ESMDA) algorithm following [EmRe13]_: In history-matching problems, it is common to consider solely the parameter-estimation problem and thereby neglecting model uncertainties. Thus, unlike with the ensemble Kalman filter (EnKF), the parameters and states are always consistent (Thulin et al., 2007). This fact helps to explain the better -data matches obtained by ES-MDA compared to EnKF. The analyzed vector of model +data matches obtained by ESMDA compared to EnKF. The analyzed vector of model parameters :math:`m^a` is given in that case by .. math:: @@ -35,7 +35,7 @@ for ensembles :math:`j=1, 2, \dots, N_e`. Here, (:math:`N_d \times N_d`); - :math:`C_\text{D}`: covariance matrix of observed data measurement errors (:math:`N_d \times N_d`); -- :math:`\alpha`: ES-MDA coefficient; +- :math:`\alpha`: ESMDA coefficient; - :math:`d_\text{uc}` : vector of perturbed data, obtained from the vector of observed data, :math:`d_\text{obs}` (:math:`N_d`); - :math:`d^f`: vector of predicted data (:math:`N_d`). @@ -45,7 +45,7 @@ The prior vector of model parameters, :math:`m^f_j`, can in reality be geologist). In theoretical tests, these are usually created by perturbing the prior :math:`m^f` by, e.g., adding random Gaussian noise. -The ES-MDA algorithm follows [EmRe13]_: +The ESMDA algorithm follows [EmRe13]_: 1. Choose the number of data assimilations, :math:`N_a`, and the coefficients :math:`\alpha_i` for :math:`i = 1, \dots, N_a`. @@ -60,9 +60,9 @@ The ES-MDA algorithm follows [EmRe13]_: The difficulty is the inversion of the large (:math:`N_d \times N_d`) matrix :math:`C=C_\text{DD}^f + \alpha C_\text{D}`, which is often poorly conditioned and poorly scaled. How to compute this inverse is one of the main differences -between different ES-MDA implementations. +between different ESMDA implementations. -Also note that in the ES-MDA algorithm, every time we repeat the data +Also note that in the ESMDA algorithm, every time we repeat the data assimilation, we re-sample the vector of perturbed observations, i.e., we recompute :math:`d_\text{uc} \sim \mathcal{N}(d_\text{obs}, \alpha_i C_\text{D})`. This procedure tends to reduce sampling problems caused by diff --git a/docs/manual/installation.rst b/docs/manual/installation.rst index 78c5663..02f24f2 100644 --- a/docs/manual/installation.rst +++ b/docs/manual/installation.rst @@ -1,24 +1,24 @@ Installation ============ -You can install the latest release of resmda simply via ``pip`` +You can install the latest release of dageo simply via ``pip`` .. code-block:: console - pip install resmda + pip install dageo and ``conda`` .. code-block:: console - conda install -c conda-forge resmda + conda install -c conda-forge dageo or clone the repository and install it manually with .. code-block:: console - git clone git@github.com:tuda-geo/resmda - cd resmda + git clone git@github.com:tuda-geo/dageo + cd dageo make install to get the latest version. diff --git a/docs/manual/license.rst b/docs/manual/license.rst index ad29127..0d209e3 100644 --- a/docs/manual/license.rst +++ b/docs/manual/license.rst @@ -3,7 +3,7 @@ License ======= -Everything of resmda is open-source: The code is released under the Apache 2.0 +Everything of dageo is open-source: The code is released under the Apache 2.0 license, the text (e.g., the manual) is released under the CC-BY 4.0 license. @@ -18,7 +18,7 @@ This work is licensed under Attribution 4.0 International (CC-BY-4.0). License of Code --------------- -Copyright 2024 Dieter Werthmüller, Gabriel Serrao Seabra +Copyright 2024 D. Werthmüller, G. Serrao Seabra, F.C. Vossepoel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/examples/README.rst b/examples/README.rst index 434dae0..b84e895 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -1,4 +1,4 @@ -.. _resmda_gallery: +.. _dageo_gallery: ======= Gallery diff --git a/examples/basicESMDA.py b/examples/basicESMDA.py index 5562435..c1f7369 100644 --- a/examples/basicESMDA.py +++ b/examples/basicESMDA.py @@ -1,8 +1,8 @@ r""" -Linear and non-linear ES-MDA examples -===================================== +Linear and non-linear ESMDA examples +==================================== -A basic example of ES-MDA using a simple 1D equation. +A basic example of ESMDA using a simple 1D equation. Geir Evensen gave a talk on *Properties of Iterative Ensemble Smoothers and Strategies for Conditioning on Production Data* at the IPAM in May 2017. @@ -14,7 +14,7 @@ - Video can be found here: https://www.ipam.ucla.edu/programs/workshops/workshop-iii-data-assimilation-uncertainty-reduction-and-optimization-for-subsurface-flow/?tab=schedule -Geir gives the ES-MDA equations as +Geir gives the ESMDA equations as .. math:: x_{j,i+1} &= x_{j,i} + (C^e_{xy})_i \left((C^e_{yy})_i + @@ -33,7 +33,7 @@ import numpy as np import matplotlib.pyplot as plt -import resmda +import dageo # sphinx_gallery_thumbnail_number = 3 @@ -83,7 +83,7 @@ def plot_result(mpost, dpost, dobs, title, ylim): # Plot Likelihood ax2.plot( - *pseudopdf(resmda.rng.normal(dobs, size=(ne, dobs.size))), + *pseudopdf(dageo.rng.normal(dobs, size=(ne, dobs.size))), 'C2', lw=2, label='Datum' ) @@ -115,8 +115,8 @@ def plot_result(mpost, dpost, dobs, title, ylim): # Linear case # ----------- # -# Prior model parameters and ES-MDA parameters -# '''''''''''''''''''''''''''''''''''''''''''' +# Prior model parameters and ESMDA parameters +# ''''''''''''''''''''''''''''''''''''''''''' # # In reality, the prior would be :math:`j` models provided by, e.g., the # geologists. Here we create $j$ realizations using a normal distribution of a @@ -132,12 +132,12 @@ def plot_result(mpost, dpost, dobs, title, ylim): obs_std = 1.0 # Prior: Let's start with ones as our prior guess -mprior = resmda.rng.normal(loc=1.0, scale=obs_std, size=(ne, 1)) +mprior = dageo.rng.normal(loc=1.0, scale=obs_std, size=(ne, 1)) ############################################################################### -# Run ES-MDA and plot -# ''''''''''''''''''' +# Run ESMDA and plot +# '''''''''''''''''' def lin_fwd(x): """Linear forward model.""" @@ -147,7 +147,7 @@ def lin_fwd(x): # Sample an "observation". l_dobs = lin_fwd(xlocation) -lm_post, ld_post = resmda.esmda( +lm_post, ld_post = dageo.esmda( model_prior=mprior, forward=lin_fwd, data_obs=l_dobs, @@ -180,7 +180,7 @@ def nonlin_fwd(x): # Sample a nonlinear observation; the rest of the parameters remains the same. n_dobs = nonlin_fwd(xlocation) -nm_post, nd_post = resmda.esmda( +nm_post, nd_post = dageo.esmda( model_prior=mprior, forward=nonlin_fwd, data_obs=n_dobs, @@ -203,4 +203,4 @@ def nonlin_fwd(x): ############################################################################### -resmda.Report() +dageo.Report() diff --git a/examples/basicreservoir.py b/examples/basicreservoir.py index e03bab6..b942db0 100644 --- a/examples/basicreservoir.py +++ b/examples/basicreservoir.py @@ -1,14 +1,14 @@ r""" -2D Reservoir ES-MDA example -=========================== +2D Reservoir ESMDA example +========================== -Ensemble Smoother Multiple Data Assimilation (ES-MDA) in Reservoir Simulation. +Ensemble Smoother Multiple Data Assimilation (ESMDA) in Reservoir Simulation. """ import numpy as np import matplotlib.pyplot as plt -import resmda +import dageo # For reproducibility, we instantiate a random number generator with a fixed # seed. For production, remove the seed! @@ -30,7 +30,7 @@ perm_min = 0.5 perm_max = 5.0 -# ES-MDA parameters +# ESMDA parameters ne = 100 # Number of ensembles dt = np.zeros(10)+0.0001 # Time steps (could be irregular, e.g., increasing!) time = np.r_[0, np.cumsum(dt)] @@ -47,15 +47,15 @@ ############################################################################### -# Create permeability maps for ES-MDA -# ----------------------------------- +# Create permeability maps for ESMDA +# ---------------------------------- # # We will create a set of permeability maps that will serve as our initial # guess (prior). These maps are generated using a Gaussian random field and are # constrained by certain statistical properties. # Get the model and ne prior models -RP = resmda.RandomPermeability(nx, ny, perm_mean, perm_min, perm_max) +RP = dageo.RandomPermeability(nx, ny, perm_mean, perm_min, perm_max) perm_true = RP(1, random=rng) perm_prior = RP(ne, random=rng) @@ -84,7 +84,7 @@ # ------------------------------------------- # Instantiate reservoir simulator -RS = resmda.Simulator(nx, ny, wells=wells) +RS = dageo.Simulator(nx, ny, wells=wells) def sim(x): @@ -109,8 +109,8 @@ def sim(x): ############################################################################### -# ES-MDA -# ------ +# ESMDA +# ----- def restrict_permeability(x): @@ -118,7 +118,7 @@ def restrict_permeability(x): np.clip(x, perm_min, perm_max, out=x) -perm_post, data_post = resmda.esmda( +perm_post, data_post = dageo.esmda( model_prior=perm_prior, forward=sim, data_obs=data_obs, @@ -134,7 +134,7 @@ def restrict_permeability(x): # Posterior Analysis # ------------------ # -# After running ES-MDA, it's crucial to analyze the posterior ensemble of +# After running ESMDA, it's crucial to analyze the posterior ensemble of # models. Here, we visualize the first three realizations from both the prior # and posterior ensembles to see how the models have been updated. @@ -153,7 +153,7 @@ def restrict_permeability(x): # Observing the monitored pressure at cell (1,1) for all realizations and the # reference case, we can see that the ensemble of models after the assimilation # steps (in blue) is closer to the reference case (in red) than the prior -# ensemble (in gray). This indicates that the ES-MDA method is effectively +# ensemble (in gray). This indicates that the ESMDA method is effectively # updating the models to better represent the observed data. @@ -170,4 +170,4 @@ def restrict_permeability(x): ############################################################################### -resmda.Report() +dageo.Report() diff --git a/examples/fluvialreservoir.py b/examples/fluvialreservoir.py index cc06894..a380f2f 100644 --- a/examples/fluvialreservoir.py +++ b/examples/fluvialreservoir.py @@ -1,12 +1,12 @@ r""" -2D Fluvial Reservoir ES-MDA example -=================================== +2D Fluvial Reservoir ESMDA example +================================== This example uses fluvial models containing different facies. This in contrast to the basic reservoir example :ref:`sphx_glr_gallery_basicreservoir.py`, where a single facies was used. The -example also compares the use of ES-MDA with and without localization, as +example also compares the use of ESMDA with and without localization, as explained in the example :ref:`sphx_glr_gallery_localization.py`. The fluvial models were generated with ``FLUVSIM`` through ``geomodpy``, for @@ -34,7 +34,7 @@ import numpy as np import matplotlib.pyplot as plt -import resmda +import dageo # For reproducibility, we instantiate a random number generator with a fixed # seed. For production, remove the seed! @@ -82,7 +82,7 @@ perm_max = 10.0 # Instantiate a random permeability instance -RP = resmda.RandomPermeability( +RP = dageo.RandomPermeability( nx, ny, perm_mean=None, perm_min=perm_min, perm_max=perm_max ) @@ -105,7 +105,7 @@ # Model parameters # ---------------- -# We take the first model as "true/reference", and the other for ES-MDA. +# We take the first model as "true/reference", and the other for ESMDA. perm_true = permeabilities[0, ...][None, ...] perm_prior = permeabilities[1:, ...] @@ -137,7 +137,7 @@ # ------------------------------------------- # Instantiate reservoir simulator -RS = resmda.Simulator(nx, ny, wells=wells) +RS = dageo.Simulator(nx, ny, wells=wells) def sim(x): @@ -160,12 +160,12 @@ def sim(x): nd_positions = np.tile(np.array([ox, oy]), time.size).T # Create matrix -loc_mat = resmda.localization_matrix(RP.cov, nd_positions, (nx, ny)) +loc_mat = dageo.localization_matrix(RP.cov, nd_positions, (nx, ny)) ############################################################################### -# ES-MDA -# ------ +# ESMDA +# ----- def restrict_permeability(x): @@ -189,14 +189,14 @@ def restrict_permeability(x): # Without localization # '''''''''''''''''''' -nl_perm_post, nl_data_post = resmda.esmda(**inp) +nl_perm_post, nl_data_post = dageo.esmda(**inp) ############################################################################### # With localization # ''''''''''''''''' -wl_perm_post, wl_data_post = resmda.esmda(**inp, localization_matrix=loc_mat) +wl_perm_post, wl_data_post = dageo.esmda(**inp, localization_matrix=loc_mat) ############################################################################### @@ -388,4 +388,4 @@ def restrict_permeability(x): print(json.dumps(json.load(f), indent=2)) ############################################################################### -resmda.Report() +dageo.Report() diff --git a/examples/geothermal.py b/examples/geothermal.py index 3f7f60b..cb67e0d 100644 --- a/examples/geothermal.py +++ b/examples/geothermal.py @@ -2,29 +2,29 @@ Geothermal Case Study ===================== -ES-MDA example predicting temperature at a production well as a function of +ESMDA example predicting temperature at a production well as a function of permeability. This example demonstrates the application of the Ensemble Smoother with -Multiple Data Assimilation (ES-MDA) using the ``resmda`` library to predict +Multiple Data Assimilation (ESMDA) using the ``dageo`` library to predict temperature at a production well in a geothermal reservoir. The notebook integrates the `Delft Advanced Research Terra Simulator (DARTS) `_ to model the impact of permeability variations on temperature over a 30-year period. The example uses a channelized -permeability field, which provides an interesting case study of ES-MDA's -behavior with non-Gaussian geological features. Since ES-MDA operates under +permeability field, which provides an interesting case study of ESMDA's +behavior with non-Gaussian geological features. Since ESMDA operates under Gaussian assumptions, it tends to create smooth updates to the permeability field rather than maintaining sharp channel boundaries. This limitation becomes particularly visible when the algorithm identifies the need for connectivity between wells - instead of creating or modifying channels, it increases permeability in a more diffuse manner. This behavior highlights both the power -of ES-MDA in matching production data and its limitations in preserving complex +of ESMDA in matching production data and its limitations in preserving complex geological features. .. tip:: - This example can serve as an example how one can use ``resmda`` with any + This example can serve as an example how one can use ``dageo`` with any external modelling code, here with the *Delft Advanced Research Terra Simulator* (DARTS). @@ -79,7 +79,7 @@ import numpy as np import matplotlib.pyplot as plt -import resmda +import dageo compute_darts = False if compute_darts: @@ -166,7 +166,7 @@ # # The true permeability model is the one facies realization we use to create # observations by adding noise to the modelled data. These observations are -# what we try to match with ES-MDA. To look at this permeability field is +# what we try to match with ESMDA. To look at this permeability field is # important to later interpret the result. In particular, we see that there is # a channel of high permeability connecting the injection with the production # well. @@ -346,7 +346,7 @@ def set_boundary_conditions(self): # DARTS simulation function # ''''''''''''''''''''''''' # -# In order to use an external code with ``resmda``, you have to write a wrapper +# In order to use an external code with ``dageo``, you have to write a wrapper # function, which # # - takes an ndarray of the shape of the prior models ``(ne, ...)``, and @@ -432,8 +432,8 @@ def temperature_at_production_well(permeabilities, years=years): ############################################################################### -# Perform Data Assimilation (ES-MDA) -# ---------------------------------- +# Perform Data Assimilation (ESMDA) +# --------------------------------- # Define a function to restrict the permeability values def restrict_permeability(x): @@ -441,9 +441,9 @@ def restrict_permeability(x): np.clip(x, perm_min, perm_max, out=x) -# Run ES-MDA +# Run ESMDA if compute_darts: - perm_post, data_post = resmda.esmda( + perm_post, data_post = dageo.esmda( model_prior=perm_prior, forward=temperature_at_production_well, data_obs=data_obs, @@ -596,4 +596,4 @@ def restrict_permeability(x): ############################################################################### -resmda.Report() +dageo.Report() diff --git a/examples/localization.py b/examples/localization.py index 35b597c..b60ea5c 100644 --- a/examples/localization.py +++ b/examples/localization.py @@ -2,7 +2,7 @@ Localization ========================== -Example using several well doublets and compares ES-MDA with and without +Example using several well doublets and compares ESMDA with and without localization. The example follows contextually :ref:`sphx_glr_gallery_basicreservoir.py`. @@ -11,7 +11,7 @@ import numpy as np import matplotlib.pyplot as plt -import resmda +import dageo # For reproducibility, we instantiate a random number generator with a fixed # seed. For production, remove the seed! @@ -33,7 +33,7 @@ perm_min = 0.5 perm_max = 5.0 -# ES-MDA parameters +# ESMDA parameters ne = 100 # Number of ensembles dt = np.zeros(10)+0.0001 # Time steps (could be irregular, e.g., increasing!) time = np.r_[0, np.cumsum(dt)] @@ -57,15 +57,15 @@ ############################################################################### -# Create permeability maps for ES-MDA -# ----------------------------------- +# Create permeability maps for ESMDA +# ---------------------------------- # # We will create a set of permeability maps that will serve as our initial # guess (prior). These maps are generated using a Gaussian random field and are # constrained by certain statistical properties. # Get the model and ne prior models -RP = resmda.RandomPermeability(nx, ny, perm_mean, perm_min, perm_max) +RP = dageo.RandomPermeability(nx, ny, perm_mean, perm_min, perm_max) perm_true = RP(1, random=rng) perm_prior = RP(ne, random=rng) @@ -75,7 +75,7 @@ # ------------------------------------------- # Instantiate reservoir simulator -RS = resmda.Simulator(nx, ny, wells=wells) +RS = dageo.Simulator(nx, ny, wells=wells) def sim(x): @@ -98,7 +98,7 @@ def sim(x): nd_positions = np.tile(np.array([ox, oy]), time.size).T # Create matrix -loc_mat = resmda.localization_matrix(RP.cov, nd_positions, (nx, ny)) +loc_mat = dageo.localization_matrix(RP.cov, nd_positions, (nx, ny)) # QC localization matrix fig, ax = plt.subplots(1, 1, constrained_layout=True) @@ -112,8 +112,8 @@ def sim(x): ############################################################################### -# ES-MDA -# ------ +# ESMDA +# ----- def restrict_permeability(x): @@ -137,14 +137,14 @@ def restrict_permeability(x): # Without localization # '''''''''''''''''''' -nl_perm_post, nl_data_post = resmda.esmda(**inp) +nl_perm_post, nl_data_post = dageo.esmda(**inp) ############################################################################### # With localization # ''''''''''''''''' -wl_perm_post, wl_data_post = resmda.esmda(**inp, localization_matrix=loc_mat) +wl_perm_post, wl_data_post = dageo.esmda(**inp, localization_matrix=loc_mat) ############################################################################### @@ -206,4 +206,4 @@ def restrict_permeability(x): ############################################################################### -resmda.Report() +dageo.Report() diff --git a/pyproject.toml b/pyproject.toml index 011cbef..9f9921f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,8 +3,8 @@ requires = ["setuptools>=64", "setuptools_scm>=8"] build-backend = "setuptools.build_meta" [project] -name = "resmda" -description = "ES-MDA with a simple 2D reservoir modeller" +name = "dageo" +description = "Data Assimilation in Geosciences" readme = "README.rst" requires-python = ">=3.10" authors = [ @@ -28,9 +28,9 @@ dynamic = ["version"] file = "LICENSE" [project.urls] -Homepage = "https://tuda-geo.github.io/resmda" -Documentation = "https://tuda-geo.github.io/resmda" -Repository = "https://github.com/tuda-geo/resmda" +Homepage = "https://tuda-geo.github.io/dageo" +Documentation = "https://tuda-geo.github.io/dageo" +Repository = "https://github.com/tuda-geo/dageo" [project.optional-dependencies] docs = [ @@ -56,8 +56,8 @@ tests = [ "flake8-pyproject", ] all = [ - "resmda[docs]", - "resmda[tests]", + "dageo[docs]", + "dageo[tests]", ] build = [ "setuptools_scm>=8", @@ -65,10 +65,10 @@ build = [ ] [tool.setuptools.packages.find] -include = ["resmda*"] +include = ["dageo*"] [tool.setuptools_scm] -version_file = "resmda/version.py" +version_file = "dageo/version.py" [tool.flake8] per-file-ignores = [ diff --git a/tests/test_data_assimilation.py b/tests/test_data_assimilation.py index f136047..227bc15 100644 --- a/tests/test_data_assimilation.py +++ b/tests/test_data_assimilation.py @@ -1,8 +1,8 @@ import numpy as np from numpy.testing import assert_allclose -import resmda -from resmda import data_assimilation +import dageo +from dageo import data_assimilation def pseudopdf(data, bins=200, density=True, **kwargs): @@ -22,11 +22,11 @@ def forward(x, beta): def test_esmda_linear(): - # Use the simple linear ES-MDA example from the gallery as simple test. + # Use the simple linear ESMDA example from the gallery as simple test. xlocation = -1.0 ne = int(1e7) obs_std = 1.0 - rng = resmda.utils.rng(1234) # fixed seed for testing + rng = dageo.utils.rng(1234) # fixed seed for testing mprior = rng.normal(loc=1.0, scale=obs_std, size=(ne, 1)) def lin_fwd(x): @@ -36,7 +36,7 @@ def lin_fwd(x): l_dobs = lin_fwd(xlocation) # Only return final model and data - lm_post, ld_post = resmda.esmda( + lm_post, ld_post = dageo.esmda( model_prior=mprior, forward=lin_fwd, data_obs=l_dobs, @@ -52,7 +52,7 @@ def lin_fwd(x): assert_allclose(0.012, x[np.argmax(p)], atol=0.001) # Also return steps - lm_post2, ld_post2 = resmda.esmda( + lm_post2, ld_post2 = dageo.esmda( model_prior=mprior, forward=lin_fwd, data_obs=l_dobs, @@ -71,7 +71,7 @@ def cbp(x): x[:] /= 100 # Gets the model much narrowed around 0. # alpha-array, localization_matrix, callback_post, return only model - lm_post3 = resmda.esmda( + lm_post3 = dageo.esmda( model_prior=mprior, forward=lin_fwd, data_obs=l_dobs, diff --git a/tests/test_reservoir_simulator.py b/tests/test_reservoir_simulator.py index efaa7cf..06250fc 100644 --- a/tests/test_reservoir_simulator.py +++ b/tests/test_reservoir_simulator.py @@ -2,8 +2,8 @@ import scipy as sp from numpy.testing import assert_allclose -import resmda -from resmda import reservoir_simulator +import dageo +from dageo import reservoir_simulator class TestSimulator: @@ -127,7 +127,7 @@ def test_cov_lcho(self): RP = reservoir_simulator.RandomPermeability(3, 2, 0.5, 0.2, 0.8) assert_allclose( RP.cov, - resmda.utils.gaussian_covariance( + dageo.utils.gaussian_covariance( 3, 2, RP.length, RP.theta, RP.variance ), ) @@ -138,7 +138,7 @@ def test_call(self): RP = reservoir_simulator.RandomPermeability(3, 2, 0.5, 0.0, 1.0) assert_allclose(RP(1, 0.5, 0.5, 0.5), 0.5) - rng = resmda.utils.rng(4) + rng = dageo.utils.rng(4) result = np.array([[ [0.00000000, 0.29639514], [0.00000000, 0.00000000], diff --git a/tests/test_utils.py b/tests/test_utils.py index ace1dc8..7ae785d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,7 +2,7 @@ import numpy as np from numpy.testing import assert_allclose -from resmda import utils +from dageo import utils def test_gaussian_covariance(): @@ -78,7 +78,7 @@ def test_Report(capsys): # We just ensure the shown packages do not change (core and optional). out1 = utils.Report() out2 = scooby.Report( - core=['resmda', 'numpy', 'scipy'], + core=['dageo', 'numpy', 'scipy'], optional=['matplotlib', 'IPython'], ncol=3, ) From 4f2a1524c8ed94860cddb8ff70128b18a3e69f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dieter=20Werthm=C3=BCller?= Date: Fri, 6 Dec 2024 16:11:21 +0100 Subject: [PATCH 2/2] m->z --- docs/manual/about.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/manual/about.rst b/docs/manual/about.rst index 069f296..db1cbaf 100644 --- a/docs/manual/about.rst +++ b/docs/manual/about.rst @@ -18,18 +18,18 @@ parameter-estimation problem and thereby neglecting model uncertainties. Thus, unlike with the ensemble Kalman filter (EnKF), the parameters and states are always consistent (Thulin et al., 2007). This fact helps to explain the better data matches obtained by ESMDA compared to EnKF. The analyzed vector of model -parameters :math:`m^a` is given in that case by +parameters :math:`z^a` is given in that case by .. math:: - m_j^a = m_j^f + C_\text{MD}^f \left(C_\text{DD}^f + \alpha C_\text{D} + z_j^a = z_j^f + C_\text{MD}^f \left(C_\text{DD}^f + \alpha C_\text{D} \right)^{-1}\left(d_{\text{uc},j} - d_j^f \right) \qquad \text{(1)} for ensembles :math:`j=1, 2, \dots, N_e`. Here, - :math:`^a`: analysis; - :math:`^f`: forecast; -- :math:`m^f`: prior vector of model parameters (:math:`N_m`); -- :math:`C_\text{MD}^f`: cross-covariance matrix between :math:`m^f` and +- :math:`z^f`: prior vector of model parameters (:math:`N_m`); +- :math:`C_\text{MD}^f`: cross-covariance matrix between :math:`z^f` and :math:`d^f` (:math:`N_m \times N_d`); - :math:`C_\text{DD}^f`: auto-covariance matrix of predicted data (:math:`N_d \times N_d`); @@ -40,10 +40,10 @@ for ensembles :math:`j=1, 2, \dots, N_e`. Here, vector of observed data, :math:`d_\text{obs}` (:math:`N_d`); - :math:`d^f`: vector of predicted data (:math:`N_d`). -The prior vector of model parameters, :math:`m^f_j`, can in reality be -:math:`j` possible models :math:`m^f` given from an analyst (e.g., the +The prior vector of model parameters, :math:`z^f_j`, can in reality be +:math:`j` possible models :math:`z^f` given from an analyst (e.g., the geologist). In theoretical tests, these are usually created by perturbing the -prior :math:`m^f` by, e.g., adding random Gaussian noise. +prior :math:`z^f` by, e.g., adding random Gaussian noise. The ESMDA algorithm follows [EmRe13]_: