diff --git a/.gitignore b/.gitignore index a719593..02b8876 100644 --- a/.gitignore +++ b/.gitignore @@ -163,8 +163,8 @@ cython_debug/ .DS_Store # Tests -tests/configs/ert/ -tests/generic_deck +tests/configs/ert +tests/decks/coarser tests/configs/ert tests/configs/jobs tests/configs/logs diff --git a/README.md b/README.md index c21449f..48dd72b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![DOI](https://zenodo.org/badge/815649176.svg)](https://zenodo.org/doi/10.5281/zenodo.12740838) - + # pycopm: An open-source coarsening framework for OPM Flow geological models @@ -52,6 +52,11 @@ Run `pycopm --help` to see all possible command line argument options. ## Getting started See the [_examples_](https://cssr-tools.github.io/pycopm/examples.html) in the [_documentation_](https://cssr-tools.github.io/pycopm/introduction.html). +## Publications +The following is a list of manuscripts in which _pycopm_ is used: + +1. Sandve, T.H., Lorentzen, R.J., Landa-Marbán, D., Fossum, K., 2024. Closed-loop reservoir management using fast data-calibrated coarse models. European Association of Geoscientists & Engineers, ECMOR 2024, Volume 202, ISSN 2214-4609. https://doi.org/10.3997/2214-4609.202437071. + ## About pycopm The _pycopm_ package is being funded by the [_Center for Sustainable Subsurface Resources (CSSR)_](https://cssr.no) [project no. 331841]. diff --git a/docs/_images/hello_world_1.png b/docs/_images/hello_world_1.png new file mode 100644 index 0000000..dad7676 Binary files /dev/null and b/docs/_images/hello_world_1.png differ diff --git a/docs/_images/hello_world_2.png b/docs/_images/hello_world_2.png new file mode 100644 index 0000000..59f6e0e Binary files /dev/null and b/docs/_images/hello_world_2.png differ diff --git a/docs/_images/norne_vec.png b/docs/_images/norne_vec.png new file mode 100644 index 0000000..96b88bc Binary files /dev/null and b/docs/_images/norne_vec.png differ diff --git a/docs/_images/output_generic.png b/docs/_images/output_generic.png index 37d880a..9f553cb 100644 Binary files a/docs/_images/output_generic.png and b/docs/_images/output_generic.png differ diff --git a/docs/_images/smeia.png b/docs/_images/smeia.png index cd4845d..5c75516 100644 Binary files a/docs/_images/smeia.png and b/docs/_images/smeia.png differ diff --git a/docs/_sources/configuration_file.rst.txt b/docs/_sources/configuration_file.rst.txt index 55316a4..8ddcef1 100644 --- a/docs/_sources/configuration_file.rst.txt +++ b/docs/_sources/configuration_file.rst.txt @@ -6,7 +6,7 @@ Configuration file only for the drogon and norne model. To use **pycopm** in any given OPM Flow geological model to generate the coarser files, this can be achieve without a configuration file, but setting the parameters via command lines (see the :ref:`overview` or run `pycopm -h` for the definition - of the argument options, and the :doc:`examples <./examples>`.) + of the argument options, as well as the examples in :ref:`generic`.) Here we use as an example one of the configuration files used in the tests diff --git a/docs/_sources/examples.rst.txt b/docs/_sources/examples.rst.txt index bf1edd5..c3b8f87 100644 --- a/docs/_sources/examples.rst.txt +++ b/docs/_sources/examples.rst.txt @@ -6,11 +6,8 @@ Examples Via configuration files ======================= -Drogon ------- - The `examples `_ folder contains configuration files -to perform HM studies in drogon and norne. For example, by executing inside the `example folder for drogon `_: +to perform HM studies in drogon and norne using `ERT `_. For example, by executing inside the `example folder for drogon `_: .. code-block:: bash @@ -20,17 +17,50 @@ The following are the drogon model from `opm-tests ` was generated using the generated coarse model. + +.. _generic: ================== Via OPM Flow decks ================== +The current development of **pycopm** focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck. + +Hello world +----------- +For the `HELLO_WORLD.DATA `_ deck, by executing: + +.. code-block:: bash + + pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all + +This would generated the following: + +.. figure:: figs/hello_world_1.png + + Dry run from the input cloned deck (left) and (right) coarsed model. Adding the flag -p 1 adds the remove pore volume to the neighbouring cells. + +To make active the coarse cell where there is only one active cell, this can be achieve by: + +.. code-block:: bash + + pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all -a max + +.. figure:: figs/hello_world_2.png + + Dry run from the input cloned deck (left) and (right) coarsed model. The region numbers by default are given by the mode, e.g., use the flag -n max to keep the maximum integer. + SPE10 ----- -See/run the `test_generic_deck.py `_ -for an example where **pycopm** is used to coarse the -`SPE10_MODEL2 model `_ by downloading the OPM files and running: +By downloading the `SPE10_MODEL2 model `_, then: .. code-block:: bash @@ -48,26 +78,20 @@ then: .. code-block:: bash - pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a mode - -will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the mode is -used to decide if a coarser cell should be active or inactive. + pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a min -m all -We can execute a dry run of OPM Flow to generate the grid and static variables of the coarser model: - -.. code-block:: bash - - flow STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM.DATA --enable-dry-run=true +will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the coarse cell is +made inactive if at least one cell is inactive (-a min). We use our `plopm `_ friend to generate PNG figures: .. code-block:: bash - plopm -i STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM -s ,,0 + plopm -i ' STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PREP_PYCOPM_DRYRUN STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM' -s ,,0 -v poro -subfigs 1,2 -save smeaheia -t 'Smeaheia Coarsed smeaheia' -xunits km -xformat .0f -yunits km -yformat .0f -d 5,5.2 -suptitle 0 -c cet_rainbow_bgyrm_35_85_c69 -cbsfax 0.30,0.01,0.4,0.02 -cformat .2f .. figure:: figs/smeia.png - Porosity values for the (left) original and (right) coarsed model. + Top view of porosity values for the (left) original and (right) coarsed model (note that we also coarse on the z direction). .. tip:: You can install plopm by executing in the terminal: pip install git+https://github.com/cssr-tools/plopm.git. @@ -77,16 +101,16 @@ We use our `plopm `_ friend to generate PNG (e.g., FAULTS, WELLSPECS) are assumed to be define in the main .DATA deck. Then, in order to use **pycopm** for simulation models where these properties are define via include files, replace those includes in the .DATA deck with the actual content of the include files. -Generic Drogon --------------- +Drogon +------ Following the note above, then by downloading the `DROGON model `_, replacing the lines in `DROGON_HIST.DATA `_ for the FAULTS (L127-128) and SCHEDULE (L242-243) with the actual content of those include files, then by executing: .. code-block:: bash - pycopm -i DROGON_HIST.DATA -o . -c 1,1,3 -a min -n max -p 1 - pycopm -i DROGON_HIST_PYCOPM.DATA -o . -c 1,3,1 -a mode -n mode -p 1 -j 1.9 + pycopm -i DROGON_HIST.DATA -c 1,1,3 -p 1 + pycopm -i DROGON_HIST_PYCOPM.DATA -c 1,3,1 -p 1 -j 2.5 this would generate the following coarse model: @@ -95,8 +119,23 @@ this would generate the following coarse model: Note that the total pore volume is conserved for the coarse model. Here, we first coarse in the z direction, which reduces the number of cells from 31 to 11, and after we coarse in the y direction. -After trial and error, the jump (-j) is set to 1.9 to avoid generated connections across the faults. +After trial and error, the jump (-j) is set to 2.5 to avoid generated connections across the faults. For geological models with a lot of +inactive cells and faults, this divide and conquer apporach is recommended, i.e., coarsening first in the z directon and after coarsening +in the x and y directions. .. note:: - After genereting the first coarser deck (DROGON_HIST_PYCOPM.DATA), change the path '../include/props/drogon.swatinit' to 'SWATINIT.INC', - which contains the right number of values for the coarse model. \ No newline at end of file + Add to the generated coarse deck the missing include files in the grid section related to the region operations (e.g., + ../include/grid/drogon.multregt for this case). + +Norne +----- +By downloading the `Norne model `_ (and replacing the needed include files as described in the previous +example), then here we create a coarser model by removing certain pilars in order to keep the main features of the geological model: + +.. code-block:: bash + + pycopm -i NORNE_ATW2013.DATA -x 0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,2,0,2,2,2,2,0 -y 0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,2,2,2,2,2,2,2,2,0 -z 0,0,2,0,0,2,2,2,2,2,02,2,2,2,2,0,0,2,0,2,2,0,0,0,0,0,0,0,0,0,0 -a min -p 1 + +this would generate the following coarse model: + +.. figure:: figs/norne_vec.png diff --git a/docs/_sources/introduction.rst.txt b/docs/_sources/introduction.rst.txt index b68ab76..3388bdb 100644 --- a/docs/_sources/introduction.rst.txt +++ b/docs/_sources/introduction.rst.txt @@ -12,8 +12,8 @@ Simplified and flexible framework to create coarser OPM Flow geological models. Roadmap ------- -In the initial development of the framework, the focus was two available models in `opm-tests `_: `norne `_ -and `drogon `_, where the coarser models are used to perform history matching studies using +In the initial development of the framework, the focus were two available models in `opm-tests `_: `norne `_ +and `drogon `_, where the coarser models were used to perform history matching studies using the Ensemble based reservoir tool `ERT `_, via a :doc:`configuration file <./configuration_file>`. The current development of **pycopm** focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files @@ -32,16 +32,20 @@ The current implementation supports the following executable with the argument o where --i The base name of the :doc:`configuration file <./configuration_file>` or the name of the deck, e.g., `DROGON.DATA`, (`input.txt` by default). --o The base name of the :doc:`output folder <./output_folder>` ('.'' by default, i.e., the folder where pycopm is executed). --f OPM Flow full path to executable or just `flow` (`flow` by default). --c Level of coarsening in the x, y, and z dir (`2,2,2` by default). --a Use `min`, `max`, or `mode` to scale the actnum, e.g., min makes the new coarser cell inactive it at least one cell is inactive, while max makes it active it at least one cell is active (`max` by default). --j Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults ('' by default, i.e., nothing corrected; if need it, try with values of the order of 1). --x Vector of x-coarsening, e.g., if the grid has 6 cells in the x direction, then `0,2,0,2,0,2,0` would generate a coarser model with 3 cells, while `0,2,2,2,2,2,0` would generate a coarser model with 1 cell, i.e., 0 keeps the pilars while 2 removes them ('' by default), --y Vector of y-coarsening, see the description for -x ('' by default). --z Vector of z-coarsening, see the description for -x ('' by default). --e Use `utf8` or `ISO-8859-1` encoding to read the deck (`ISO-8859-1` by default). --p Add the removed pore volume to the closest coarser cells (`0` by default, `1` to enable). --n Use `min`, `max`, or `mode` to scale satnum, fipnum, pvtnum, eqlnum, imbnum, and multnum (`mode` by default). --s Use `min`, `max`, or `mean` to scale permx, permy, permz, and poro ('' by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the porosity). \ No newline at end of file +-i The base name of the :doc:`configuration file <./configuration_file>` or the name of the deck, e.g., `DROGON.DATA`, (`input.txt` by default). +-o The base name of the :doc:`output folder <./output_folder>` ('.'' by default, i.e., the folder where pycopm is executed). +-f OPM Flow full path to executable or just `flow` (`flow` by default). +-c Level of coarsening in the x, y, and z dir (`2,2,2` by default; either use this flag or the -x, -y, and -z ones). +-x Vector of x-coarsening, e.g., if the grid has 6 cells in the x direction, then `0,2,0,2,0,2,0` would generate a coarser model with 3 cells, while `0,2,2,2,2,2,0` would generate a coarser model with 1 cell, i.e., 0 keeps the pilars while 2 removes them ('' by default), +-y Vector of y-coarsening, see the description for -x ('' by default). +-z Vector of z-coarsening, see the description for -x ('' by default). +-a Use `min`, `max`, or `mode` to scale the actnum, e.g., min makes the new coarser cell inactive if at least one cell is inactive, while max makes it active it at least one cell is active (`mode` by default). +-n Use `min`, `max`, or `mode` to scale endnum, eqlnum, fipnum, fluxnum, imbnum, miscnum, multnum, pvtnum, rocknum, and satnum (`mode` by default). +-s Use `min`, `max`, or `mean` to scale permx, permy, permz, poro, swatinit, and all mult(-)xyz ('' by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the rest). +-p Add the removed pore volume to the closest coarser cells (`0` by default, `1` to enable). +-j Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults ('' by default, i.e., nothing corrected; if need it, try with values of the order of 1). +-m Execute a dry run on the input deck to generate the static properties ('prep'), generate only the coarse files ('deck'), only exectute a dry run on the generated coarse model ('dry'), 'prep_deck', 'deck_dry', or do all ('all') (`prep_deck` by default). +-w Name of the generated deck ('' by default, i.e., the name of the input deck plus _PYCOPM.DATA). +-l Added text before each generated .INC (`PYCOPM_` by default, i.e., the coarse porv is saved in PYCOPM_PORV.INC; set to '' to generate PORV.INC, PERMX.INC, etc). +-e Use `utf8` or `ISO-8859-1` encoding to read the deck (`ISO-8859-1` by default). +-ijk Given i,j,k indices in the input model, return the coarse i,j,k corresponding positions ('' by default; if not empty, e.g., 1,2,3 then the -m is set to deck and there will not be generation of coarse files, only the i,j,k coarse indices in the terminal). \ No newline at end of file diff --git a/docs/_sources/output_folder.rst.txt b/docs/_sources/output_folder.rst.txt index 5e04a73..da7515f 100644 --- a/docs/_sources/output_folder.rst.txt +++ b/docs/_sources/output_folder.rst.txt @@ -21,7 +21,7 @@ are generated in the postprocessing folder. The OPM simulation results can be vi Via an OPM Flow input deck -------------------------- -The current development of **pycopm** focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files. +The current development of **pycopm** focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck. The following screenshot shows the input deck and generated files in the selected output folder (coarser for this example) after executing **pycopm** on the SPE10 model (see the `test_generic_deck.py `_) file. @@ -29,4 +29,10 @@ The following screenshot shows the input deck and generated files in the selecte .. figure:: figs/output_generic.png Then, after running **pycopm**, one could adapt the generated files with the coarser geological model in your -favourite history matching/optimization tool (e.g., `ERT `_, `PET `_, `everest `_). \ No newline at end of file +favourite history matching/optimization tool (e.g., `ERT `_, `PET `_, `everest `_). + +.. Note:: + For input decks that include other files without giving the full path (e.g., './include/summary...'), then we recommend + to use the default output folder (-o .), i.e., the generated deck and coarse files would be generated in the same location as + the input deck and no errors would appear for not finding the include files; otherwise, you might need to copy all needed folders + with the include files to the output folder or setting the correct path to the include files in the generated coarse deck. \ No newline at end of file diff --git a/docs/configuration_file.html b/docs/configuration_file.html index d383e64..675c7ce 100644 --- a/docs/configuration_file.html +++ b/docs/configuration_file.html @@ -89,7 +89,7 @@

Configuration fileOverview or run pycopm -h for the definition -of the argument options, and the examples.)

+of the argument options, as well as the examples in Via OPM Flow decks.)

Here we use as an example one of the configuration files used in the tests (see ert.txt). diff --git a/docs/examples.html b/docs/examples.html index b98f74a..a281f99 100644 --- a/docs/examples.html +++ b/docs/examples.html @@ -51,14 +51,13 @@

  • Installation
  • Configuration file
  • Examples @@ -97,10 +96,8 @@

    Examples

    Via configuration files

    -
    -

    Drogon

    The examples folder contains configuration files -to perform HM studies in drogon and norne. For example, by executing inside the example folder for drogon:

    +to perform HM studies in drogon and norne using ERT. For example, by executing inside the example folder for drogon:

    pycopm -i coarser.txt -o drogon_coarser
     
    @@ -108,22 +105,49 @@

    Drogon<
    _images/drogon_coarser.png
    -

    +

    For norne:

    +
    pycopm -i input.txt -o norne_coarser
    +
    +
    +

    The norne GIF in the introduction was generated using the generated coarse model.

    -

    Via OPM Flow decks

    +

    Via OPM Flow decks

    +

    The current development of pycopm focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck.

    +
    +

    Hello world

    +

    For the HELLO_WORLD.DATA deck, by executing:

    +
    pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all
    +
    +
    +

    This would generated the following:

    +
    +_images/hello_world_1.png +
    +

    Dry run from the input cloned deck (left) and (right) coarsed model. Adding the flag -p 1 adds the remove pore volume to the neighbouring cells.

    +
    +
    +

    To make active the coarse cell where there is only one active cell, this can be achieve by:

    +
    pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all -a max
    +
    +
    +
    +_images/hello_world_2.png +
    +

    Dry run from the input cloned deck (left) and (right) coarsed model. The region numbers by default are given by the mode, e.g., use the flag -n max to keep the maximum integer.

    +
    +
    +

    SPE10

    -

    See/run the test_generic_deck.py -for an example where pycopm is used to coarse the -SPE10_MODEL2 model by downloading the OPM files and running:

    +

    By downloading the SPE10_MODEL2 model, then:

    pycopm -i SPE10_MODEL2.DATA -o coarser -c 4,8,2
     
    -
    +
    _images/spe10_model2_coarser.png
    -

    Porosity values for the (left) original and (right) coarsed SPE10 model.

    +

    Porosity values for the (left) original and (right) coarsed SPE10 model.

    @@ -131,23 +155,19 @@

    SPE10Smeaheia

    By downloading the Smeaheia simulation model, then:

    -
    pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a mode
    -
    -
    -

    will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the mode is -used to decide if a coarser cell should be active or inactive.

    -

    We can execute a dry run of OPM Flow to generate the grid and static variables of the coarser model:

    -
    flow STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM.DATA --enable-dry-run=true
    +
    pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a min -m all
     
    +

    will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the coarse cell is +made inactive if at least one cell is inactive (-a min).

    We use our plopm friend to generate PNG figures:

    -
    plopm -i STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM -s ,,0
    +
    plopm -i ' STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PREP_PYCOPM_DRYRUN STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM' -s ,,0 -v poro -subfigs 1,2 -save smeaheia -t 'Smeaheia  Coarsed smeaheia' -xunits km -xformat .0f -yunits km -yformat .0f -d 5,5.2 -suptitle 0 -c cet_rainbow_bgyrm_35_85_c69 -cbsfax 0.30,0.01,0.4,0.02 -cformat .2f
     
    -
    +
    _images/smeia.png
    -

    Porosity values for the (left) original and (right) coarsed model.

    +

    Top view of porosity values for the (left) original and (right) coarsed model (note that we also coarse on the z direction).

    -
    -

    Generic Drogon

    +
    +

    Drogon

    Following the note above, then by downloading the DROGON model, replacing the lines in DROGON_HIST.DATA for the FAULTS (L127-128) and SCHEDULE (L242-243) with the actual content of those include files, then by executing:

    -
    pycopm -i DROGON_HIST.DATA -o . -c 1,1,3 -a min -n max -p 1
    -pycopm -i DROGON_HIST_PYCOPM.DATA -o . -c 1,3,1 -a mode -n mode -p 1 -j 1.9
    +
    pycopm -i DROGON_HIST.DATA -c 1,1,3 -p 1
    +pycopm -i DROGON_HIST_PYCOPM.DATA -c 1,3,1 -p 1 -j 2.5
     

    this would generate the following coarse model:

    -
    +
    _images/drogon_generic.png
    -

    Note that the total pore volume is conserved for the coarse model.

    +

    Note that the total pore volume is conserved for the coarse model.

    Here, we first coarse in the z direction, which reduces the number of cells from 31 to 11, and after we coarse in the y direction. -After trial and error, the jump (-j) is set to 1.9 to avoid generated connections across the faults.

    +After trial and error, the jump (-j) is set to 2.5 to avoid generated connections across the faults. For geological models with a lot of +inactive cells and faults, this divide and conquer apporach is recommended, i.e., coarsening first in the z directon and after coarsening +in the x and y directions.

    Note

    -

    After genereting the first coarser deck (DROGON_HIST_PYCOPM.DATA), change the path ‘../include/props/drogon.swatinit’ to ‘SWATINIT.INC’, -which contains the right number of values for the coarse model.

    +

    Add to the generated coarse deck the missing include files in the grid section related to the region operations (e.g., +../include/grid/drogon.multregt for this case).

    +
    +

    Norne

    +

    By downloading the Norne model (and replacing the needed include files as described in the previous +example), then here we create a coarser model by removing certain pilars in order to keep the main features of the geological model:

    +
    pycopm -i NORNE_ATW2013.DATA -x 0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,2,0,2,2,2,2,0 -y 0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,2,2,2,2,2,2,2,2,0 -z 0,0,2,0,0,2,2,2,2,2,02,2,2,2,2,0,0,2,0,2,2,0,0,0,0,0,0,0,0,0,0 -a min -p 1
    +
    +
    +

    this would generate the following coarse model:

    +
    +_images/norne_vec.png +
    +
    diff --git a/docs/genindex.html b/docs/genindex.html index ca1cca7..7e96213 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -180,13 +180,17 @@

    H

  • handle_fault() (in module pycopm.utils.generate_coarser_files)
  • - - +
    • handle_grid_props() (in module pycopm.utils.generate_coarser_files)
    • handle_mapaxes() (in module pycopm.utils.generate_coarser_files) +
    • +
    • handle_oper() (in module pycopm.utils.generate_coarser_files) +
    • +
    • handle_props() (in module pycopm.utils.generate_coarser_files)
    • handle_pv() (in module pycopm.utils.generate_coarser_files)
    • diff --git a/docs/index.html b/docs/index.html index a4b0abc..d2e2a42 100644 --- a/docs/index.html +++ b/docs/index.html @@ -101,14 +101,13 @@

      Welcome to pycopm’s documentation!Configuration file
    • Examples diff --git a/docs/introduction.html b/docs/introduction.html index 9e5e5ed..b3059f3 100644 --- a/docs/introduction.html +++ b/docs/introduction.html @@ -96,8 +96,8 @@

      Concept

      Roadmap

      -

      In the initial development of the framework, the focus was two available models in opm-tests: norne -and drogon, where the coarser models are used to perform history matching studies using +

      In the initial development of the framework, the focus were two available models in opm-tests: norne +and drogon, where the coarser models were used to perform history matching studies using the Ensemble based reservoir tool ERT, via a configuration file.

      The current development of pycopm focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files (i.e., avoiding the manual work to create templates as it was done for drogon and norne). This allows for flexibility to adapt the generated coarser decks in your @@ -121,13 +121,7 @@

      Roadmap

      OPM Flow full path to executable or just flow (flow by default).

      -c
      -

      Level of coarsening in the x, y, and z dir (2,2,2 by default).

      -
      -
      -a
      -

      Use min, max, or mode to scale the actnum, e.g., min makes the new coarser cell inactive it at least one cell is inactive, while max makes it active it at least one cell is active (max by default).

      -
      -
      -j
      -

      Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults (’’ by default, i.e., nothing corrected; if need it, try with values of the order of 1).

      +

      Level of coarsening in the x, y, and z dir (2,2,2 by default; either use this flag or the -x, -y, and -z ones).

      -x

      Vector of x-coarsening, e.g., if the grid has 6 cells in the x direction, then 0,2,0,2,0,2,0 would generate a coarser model with 3 cells, while 0,2,2,2,2,2,0 would generate a coarser model with 1 cell, i.e., 0 keeps the pilars while 2 removes them (’’ by default),

      @@ -138,17 +132,35 @@

      Roadmap
      -z

      Vector of z-coarsening, see the description for -x (’’ by default).

      -
      -e
      -

      Use utf8 or ISO-8859-1 encoding to read the deck (ISO-8859-1 by default).

      +
      -a
      +

      Use min, max, or mode to scale the actnum, e.g., min makes the new coarser cell inactive if at least one cell is inactive, while max makes it active it at least one cell is active (mode by default).

      +
      +
      -n
      +

      Use min, max, or mode to scale endnum, eqlnum, fipnum, fluxnum, imbnum, miscnum, multnum, pvtnum, rocknum, and satnum (mode by default).

      +
      +
      -s
      +

      Use min, max, or mean to scale permx, permy, permz, poro, swatinit, and all mult(-)xyz (’’ by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the rest).

      -p

      Add the removed pore volume to the closest coarser cells (0 by default, 1 to enable).

      -
      -n
      -

      Use min, max, or mode to scale satnum, fipnum, pvtnum, eqlnum, imbnum, and multnum (mode by default).

      +
      -j
      +

      Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults (’’ by default, i.e., nothing corrected; if need it, try with values of the order of 1).

      -
      -s
      -

      Use min, max, or mean to scale permx, permy, permz, and poro (’’ by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the porosity).

      +
      -m
      +

      Execute a dry run on the input deck to generate the static properties (‘prep’), generate only the coarse files (‘deck’), only exectute a dry run on the generated coarse model (‘dry’), ‘prep_deck’, ‘deck_dry’, or do all (‘all’) (prep_deck by default).

      +
      +
      -w
      +

      Name of the generated deck (’’ by default, i.e., the name of the input deck plus _PYCOPM.DATA).

      +
      +
      -l
      +

      Added text before each generated .INC (PYCOPM_ by default, i.e., the coarse porv is saved in PYCOPM_PORV.INC; set to ‘’ to generate PORV.INC, PERMX.INC, etc).

      +
      +
      -e
      +

      Use utf8 or ISO-8859-1 encoding to read the deck (ISO-8859-1 by default).

      +
      +
      -ijk
      +

      Given i,j,k indices in the input model, return the coarse i,j,k corresponding positions (’’ by default; if not empty, e.g., 1,2,3 then the -m is set to deck and there will not be generation of coarse files, only the i,j,k coarse indices in the terminal).

      diff --git a/docs/objects.inv b/docs/objects.inv index 012d960..aab696b 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/output_folder.html b/docs/output_folder.html index 81b7066..17af0bd 100644 --- a/docs/output_folder.html +++ b/docs/output_folder.html @@ -106,7 +106,7 @@

      Via configuration files

      Via an OPM Flow input deck

      -

      The current development of pycopm focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files.

      +

      The current development of pycopm focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck.

      The following screenshot shows the input deck and generated files in the selected output folder (coarser for this example) after executing pycopm on the SPE10 model (see the test_generic_deck.py) file.

      @@ -114,6 +114,13 @@

      Via an OPM Flow input deckERT, PET, everest).

      +
      +

      Note

      +

      For input decks that include other files without giving the full path (e.g., ‘./include/summary…’), then we recommend +to use the default output folder (-o .), i.e., the generated deck and coarse files would be generated in the same location as +the input deck and no errors would appear for not finding the include files; otherwise, you might need to copy all needed folders +with the include files to the output folder or setting the correct path to the include files in the generated coarse deck.

      +

      diff --git a/docs/pycopm.html b/docs/pycopm.html index 3162b03..d8dfb73 100644 --- a/docs/pycopm.html +++ b/docs/pycopm.html @@ -120,6 +120,8 @@

      Subpackageshandle_fault()

    • handle_grid_props()
    • handle_mapaxes()
    • +
    • handle_oper()
    • +
    • handle_props()
    • handle_pv()
    • handle_regions()
    • handle_segmented_wells()
    • diff --git a/docs/pycopm.utils.generate_coarser_files.html b/docs/pycopm.utils.generate_coarser_files.html index c94ed30..1497549 100644 --- a/docs/pycopm.utils.generate_coarser_files.html +++ b/docs/pycopm.utils.generate_coarser_files.html @@ -192,6 +192,32 @@ +
      +
      +pycopm.utils.generate_coarser_files.handle_oper(dic, nrwo)
      +

      We also support operations

      +
      +
      Args:

      dic (dict): Global dictionary

      +

      nrwo (list): Splited row from the input deck

      +
      +
      Returns:

      dic (dict): Modified global dictionary

      +
      +
      +
      + +
      +
      +pycopm.utils.generate_coarser_files.handle_props(dic, nrwo)
      +

      Handle the props sections

      +
      +
      Args:

      dic (dict): Global dictionary

      +

      nrwo (list): Splited row from the input deck

      +
      +
      Returns:

      dic (dict): Modified global dictionary

      +
      +
      +
      +
      pycopm.utils.generate_coarser_files.handle_pv(dic, clusmin, clusmax, rmv)
      diff --git a/docs/pycopm.utils.html b/docs/pycopm.utils.html index 190b915..f32e2dc 100644 --- a/docs/pycopm.utils.html +++ b/docs/pycopm.utils.html @@ -106,6 +106,8 @@

      Submoduleshandle_fault()
    • handle_grid_props()
    • handle_mapaxes()
    • +
    • handle_oper()
    • +
    • handle_props()
    • handle_pv()
    • handle_regions()
    • handle_segmented_wells()
    • diff --git a/docs/searchindex.js b/docs/searchindex.js index 25b7be0..029a9fe 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["about", "api", "configuration_file", "examples", "index", "installation", "introduction", "modules", "output_folder", "pycopm", "pycopm.core", "pycopm.core.pycopm", "pycopm.utils", "pycopm.utils.files_writer", "pycopm.utils.generate_coarser_files", "pycopm.utils.grid_builder", "pycopm.utils.input_values", "pycopm.utils.properties_builder", "pycopm.utils.runs_executer", "related"], "filenames": ["about.rst", "api.rst", "configuration_file.rst", "examples.rst", "index.rst", "installation.rst", "introduction.rst", "modules.rst", "output_folder.rst", "pycopm.rst", "pycopm.core.rst", "pycopm.core.pycopm.rst", "pycopm.utils.rst", "pycopm.utils.files_writer.rst", "pycopm.utils.generate_coarser_files.rst", "pycopm.utils.grid_builder.rst", "pycopm.utils.input_values.rst", "pycopm.utils.properties_builder.rst", "pycopm.utils.runs_executer.rst", "related.rst"], "titles": ["About pycopm", "pycopm Python API", "Configuration file", "Examples", "Welcome to pycopm\u2019s documentation!", "Installation", "Introduction", "pycopm", "Output folder", "pycopm package", "pycopm.core package", "pycopm.core.pycopm module", "pycopm.utils package", "pycopm.utils.files_writer module", "pycopm.utils.generate_coarser_files module", "pycopm.utils.grid_builder module", "pycopm.utils.input_values module", "pycopm.utils.properties_builder module", "pycopm.utils.runs_executer module", "Related"], "terms": {"tool": [0, 3, 5, 6, 8, 19], "coarsen": [0, 1, 2, 6], "opm": [0, 1, 2, 4, 6, 13, 16, 18, 19], "flow": [0, 1, 2, 4, 6, 13, 18, 19], "geolog": [0, 2, 6, 8], "model": [0, 2, 3, 6, 8, 19], "i": [0, 1, 2, 3, 6, 8, 14, 15], "being": 0, "fund": 0, "center": [0, 14], "sustain": 0, "subsurfac": 0, "resourc": [0, 19], "cssr": [0, 3, 5, 6], "project": [0, 5, 19], "331841": 0, "thi": [0, 2, 3, 5, 6, 8], "work": [0, 6], "progress": 0, "contribut": [0, 5], "ar": [0, 1, 2, 3, 5, 6, 8, 19], "more": 0, "than": 0, "welcom": 0, "us": [0, 1, 2, 3, 5, 6, 8, 17, 19], "fork": 0, "pull": 0, "request": 0, "approach": [0, 2], "The": [1, 2, 3, 6, 8], "main": [1, 2, 3, 9, 10, 11, 14], "script": [1, 5, 11], "execut": [1, 2, 3, 5, 6, 8, 11, 18], "locat": 1, "core": [1, 5, 7, 9], "folder": [1, 3, 4, 5, 6], "differ": [1, 2], "job": 1, "call": [1, 2, 8, 14], "ert": [1, 2, 6, 8, 13, 16, 18], "reference_simul": 1, "contain": [1, 3], "gener": [1, 2, 4, 6, 8, 14, 15, 17, 18, 19], "file": [1, 4, 5, 6, 13, 14, 16, 18], "after": [1, 2, 3, 5, 8], "run": [1, 2, 3, 5, 6, 8, 13, 18], "norn": [1, 2, 3, 6, 8], "drogon": [1, 2, 4, 6, 8], "case": 1, "test": [1, 2, 3, 5, 6], "template_script": 1, "mako": [1, 13], "base": [1, 6, 19], "from": [1, 2, 3, 5, 14, 15, 16, 19], "origin": [1, 3], "deck": [1, 2, 4, 6, 13, 14, 17], "final": [1, 2], "util": [1, 7, 9], "function": [1, 2, 11, 13, 15, 16, 17, 18], "framework": [1, 6, 19], "pyocpm": 1, "packag": [1, 4, 7], "subpackag": [1, 4, 7], "submodul": [1, 7, 9], "modul": [1, 4, 5, 7, 19], "content": [1, 3, 4, 7], "allow": [2, 6], "set": [2, 3, 16], "integr": 2, "studi": [2, 3, 6, 8, 18, 19], "histori": [2, 6, 8], "match": [2, 6, 8], "onli": [2, 5, 6, 8, 14], "To": [2, 5], "pycopm": [2, 3, 5, 6, 8], "ani": 2, "given": 2, "coarser": [2, 3, 6, 8, 14, 17], "can": [2, 3, 5, 8], "achiev": [2, 5], "without": 2, "paramet": [2, 6, 16, 17], "via": [2, 4, 6], "command": [2, 5], "line": [2, 3, 5, 16], "see": [2, 3, 5, 6, 8], "overview": [2, 4], "h": 2, "definit": [2, 3], "argument": [2, 6, 11, 14], "option": [2, 6, 11], "exampl": [2, 4, 8], "here": [2, 3], "we": [2, 3, 14], "an": [2, 3, 4, 5, 19], "one": [2, 6, 8, 14], "txt": [2, 3, 5, 6], "first": [2, 3, 16], "input": [2, 4, 6, 14, 16, 17], "full": [2, 6], "path": [2, 3, 6], "If": [2, 5], "your": [2, 6, 8], "write": [2, 13, 14, 17], "e": [2, 3, 5, 6, 8], "g": [2, 3, 5, 6, 8], "user": [2, 5], "dmar": 2, "github": [2, 3, 5, 6], "build": [2, 4], "simul": [2, 3, 5, 8, 9, 12, 16, 18, 19], "bin": [2, 5], "follow": [2, 3, 5, 6, 8], "delet": 2, "suffix": 2, "save": 2, "storag": [2, 19], "egrid": 2, "dbg": 2, "grdecl": 2, "unrst": 2, "unsmri": 2, "prt": 2, "inc": [2, 3, 16], "infostep": 2, "smspec": 2, "init": 2, "you": [2, 3, 5], "type": [2, 19], "each": 2, "realiz": 2, "complet": 2, "order": [2, 3, 6], "memori": 2, "number": [2, 3, 16], "jump": [2, 3, 14], "2": [2, 3, 6], "4": [2, 3], "sinc": 2, "implement": [2, 3, 6], "white": 2, "space": 2, "between": [2, 6], "block": [2, 17], "need": [2, 5, 6, 8], "next": 2, "entri": 2, "defin": [2, 3, 17], "singl": 2, "0": [2, 3, 5, 6], "1": [2, 3, 5, 6], "vector": [2, 6], "x": [2, 3, 6], "coers": 2, "y": [2, 3, 6], "z": [2, 3, 6, 14, 17], "ensembl": [2, 6], "maximum": 2, "parallel": 2, "mpi": [2, 5], "process": [2, 14, 16], "600": 2, "runtim": 2, "second": 2, "A": [2, 19], "valu": [2, 3, 6, 16], "mean": [2, 6], "unlimit": 2, "minimum": 2, "must": 2, "have": [2, 14], "succeed": 2, "regard": 2, "success": 2, "7": 2, "specif": 2, "seed": 2, "reproduc": 2, "observations_train": 2, "name": [2, 6, 16], "observ": 2, "hm": [2, 3], "observations_test": 2, "observations_complet": 2, "select": [2, 8, 18], "which": [2, 3, 5], "default": [2, 6], "let": [2, 13], "sat": 2, "For": [2, 3, 5], "satnum": [2, 6], "comput": 2, "sandv": 2, "et": 2, "al": 2, "2022": 2, "cell": [2, 3, 6, 14, 15, 16, 17], "correct": [2, 6, 17], "lost": [2, 17], "pv": 2, "boundari": [2, 17], "account": 2, "poros": [2, 3, 6], "all": [2, 6, 8, 14, 17], "initi": [2, 6, 16, 17], "equil": 2, "fine": 2, "scale": [2, 6], "error": [2, 3], "wwpr": 2, "wopr": 2, "wgpr": 2, "100": 2, "100000": 2, "2005": 2, "03": 2, "01": 2, "last": [2, 16], "date": 2, "do": [2, 5], "remov": [2, 6, 14, 17], "current": [2, 3, 5, 6, 8, 14, 18], "read": [2, 6, 16], "result": [2, 8], "inform": 2, "shown": 2, "termin": [2, 3, 5], "instead": 2, "same": [2, 14, 17], "discuss": 2, "later": 2, "three": 2, "pillar": [2, 14], "direct": [2, 3, 6, 17], "respect": 2, "j": [2, 3, 6, 14, 15], "k": [2, 3, 14, 15], "index": [2, 4, 14, 15, 17], "standard": 2, "data": [2, 3, 6], "pilar": [2, 6, 17], "keep": [2, 6, 14], "honor": 2, "shape": 2, "Then": [2, 3, 8], "provid": 2, "chang": [2, 3], "": [2, 3, 6, 14], "add": [2, 6, 14], "back": 2, "remain": 2, "mpirun": 2, "avail": [2, 5, 6], "stop": 2, "time": [2, 3, 18], "random": 2, "satur": [2, 13, 16], "consid": 2, "region": [2, 14], "ntg": 2, "poro": [2, 6], "properti": [2, 3, 13, 14, 17], "modifi": [2, 5, 13, 14, 15, 16, 17, 18], "activ": [2, 3, 5, 6, 14, 17], "gui": 2, "test_run": 2, "ensemble_experi": 2, "ensemble_smooth": 2, "iterative_ensemble_smooth": 2, "es_mda": 2, "weight": 2, "flag": [2, 14, 16], "support": [2, 5, 6, 14], "confer": 2, "document": [2, 6], "descript": [2, 6], "enabl": [2, 3, 6], "rst": 2, "true": [2, 3], "newton": 2, "min": [2, 3, 6], "iter": 2, "dist": 2, "distpara": 2, "lw": 2, "3": [2, 3, 5, 6], "uniform": 2, "5": [2, 3], "ew": 2, "tw": 2, "lo": 2, "eo": 2, "lg": 2, "eg": 2, "tg": 2, "log": 2, "eog": 2, "tog": 2, "lmlto": 2, "emlto": 2, "9": [2, 3, 5], "tmlto": 2, "lmltg": 2, "emltg": 2, "tmltg": 2, "permeabl": 2, "rock": 2, "coars": [2, 3, 14, 15, 17], "max": [2, 3, 6], "permx": [2, 6], "permi": [2, 6], "permz": [2, 6], "distribut": [2, 14, 17], "interv": 2, "perm_min": 2, "perm_max": 2, "correspond": [2, 14], "perform": [3, 6], "insid": [3, 5], "o": [3, 6, 14], "drogon_coars": 3, "test_generic_deck": [3, 8], "py": [3, 8, 18], "where": [3, 6], "spe10_model2": 3, "download": 3, "c": [3, 6], "8": 3, "left": [3, 8], "right": [3, 8, 14], "By": 3, "statoil_feasibility_sim_model_with_depletion_kross_inj_sector_20": 3, "mode": [3, 6], "1000": [], "decid": 3, "should": [3, 5], "inact": [3, 6], "higher": [], "avoid": [3, 6], "grid": [3, 5, 6, 13, 14, 15, 17], "connect": [3, 6], "tun": [], "neighbour": [6, 14], "dry": 3, "static": 3, "variabl": [3, 13, 16], "statoil_feasibility_sim_model_with_depletion_kross_inj_sector_20_pycopm": 3, "our": 3, "plopm": [3, 4], "friend": 3, "png": [3, 19], "figur": [3, 8], "instal": [3, 4], "pip": [3, 5], "git": [3, 5], "http": [3, 5, 6], "com": [3, 5, 6], "In": [3, 5, 6], "handl": [3, 14], "requir": [3, 5, 14, 16, 17], "indic": [3, 14], "fault": [3, 6, 14, 15], "wellspec": 3, "assum": 3, "includ": [3, 5], "replac": 3, "those": 3, "actual": 3, "introduct": [4, 8], "concept": 4, "roadmap": 4, "python": [4, 19], "sourc": [4, 19], "linux": 4, "window": 4, "maco": 4, "configur": [4, 6], "spe10": [4, 8], "smeaheia": 4, "api": 4, "output": [4, 6, 16], "relat": [4, 13], "pyopmspe11": 4, "pyopmnearwel": 4, "exprecc": 4, "ad": 4, "micp": 4, "pymm": 4, "about": 4, "search": [4, 14], "page": 4, "exist": 5, "environ": 5, "interest": [5, 19], "code": 5, "clone": 5, "repositori": 5, "virtual": 5, "repo": 5, "get": 5, "cd": 5, "creat": [5, 6, 8, 14], "python3": 5, "m": 5, "venv": 5, "vpycopm": 5, "upgrad": 5, "setuptool": 5, "wheel": 5, "lint": 5, "dev": 5, "r": 5, "also": [5, 14], "org": 5, "releas": 5, "2024": 5, "04": 5, "master": 5, "branch": 5, "ci": 5, "yml": 5, "binari": 5, "subsystem": 5, "could": [5, 8], "try": [5, 6], "prerequisit": 5, "turn": 5, "current_directori": 5, "pwd": 5, "common": 5, "done": [5, 6], "mkdir": 5, "cmake": 5, "duse_mpi": 5, "dwith_ndebug": 5, "dcmake_build_typ": 5, "dcmake_prefix_path": 5, "make": [5, 6, 14], "j5": 5, "sh": 5, "build_opm_mpi": 5, "copi": 5, "previou": 5, "so": [5, 14], "built": 5, "addit": 5, "dune": 5, "librari": 5, "macport": 5, "brew": 5, "geometri": 5, "istl": 5, "gitlab": 5, "v2": 5, "dunecontrol": 5, "dcmake_disable_find_package_mpi": 5, "dpython_execut": 5, "dopm_enable_python": 5, "ON": 5, "least": [5, 6, 14], "version": 5, "10": 5, "due": 5, "resdata": 5, "describ": [6, 8], "host": 6, "simplifi": 6, "flexibl": 6, "develop": [6, 8], "focu": [6, 8], "wa": [6, 8], "two": 6, "reservoir": 6, "focus": 6, "give": [6, 8], "manual": 6, "templat": [6, 13], "adapt": [6, 8], "favourit": [6, 8], "optim": [6, 8], "pet": [6, 8], "everest": [6, 8], "name_of_input_fil": 6, "f": 6, "just": 6, "level": 6, "dir": [6, 15], "actnum": [6, 14], "new": [6, 14], "while": 6, "tune": 6, "creation": 6, "discontinu": 6, "along": 6, "around": 6, "noth": 6, "ha": 6, "6": 6, "would": [3, 6], "them": [6, 19], "utf8": 6, "iso": 6, "8859": 6, "encod": 6, "p": [3, 6], "pore": [3, 6, 14, 17], "volum": [3, 6, 14, 17], "closest": 6, "n": [3, 6, 14], "fipnum": [6, 17], "pvtnum": 6, "eqlnum": [6, 17], "imbnum": 6, "multnum": 6, "arithmet": 6, "averag": 6, "harmon": 6, "As": 8, "earli": 8, "screenshot": 8, "show": 8, "some": [8, 19], "postprocess": 8, "directli": 8, "further": 8, "plot": [8, 9, 12, 18], "visual": 8, "resinsight": 8, "focuc": 8, "load_pars": [9, 10, 11], "files_writ": [9, 12], "coarser_fil": [9, 12, 13], "ert_fil": [9, 12, 13], "grid_featur": [9, 12, 13], "opm_properti": [9, 12, 13], "write_let_t": [9, 12, 13], "generate_coarser_fil": [9, 12], "create_deck": [9, 12, 14], "find_neighbor": [9, 12, 14], "get_ijk": [9, 12, 14], "handle_clust": [9, 12, 14], "handle_cp_grid": [9, 12, 14], "handle_fault": [9, 12, 14, 15], "handle_grid_prop": [9, 12, 14], "handle_mapax": [9, 12, 14], "handle_pv": [9, 12, 14], "handle_region": [9, 12, 14], "handle_segmented_wel": [9, 12, 14], "handle_wel": [9, 12, 14], "handle_zcorn": [9, 12, 14], "map_ijk": [9, 12, 14], "map_properti": [9, 12, 14], "process_the_deck": [9, 12, 14], "write_grid": [9, 12, 14], "write_prop": [9, 12, 14], "grid_build": [9, 12], "coarser_grid": [9, 12, 15], "handle_face_dir_im": [9, 12, 15], "handle_face_dir_ip": [9, 12, 15], "handle_face_dir_jm": [9, 12, 15], "handle_face_dir_jp": [9, 12, 15], "input_valu": [9, 12], "assign_hm_paramet": [9, 12, 16], "assign_standard_valu": [9, 12, 16], "get_number_of_lin": [9, 12, 16], "initialize_valu": [9, 12, 16], "process_input": [9, 12, 16], "read_refer": [9, 12, 16], "read_the_first_part": [9, 12, 16], "properties_build": [9, 12], "add_lost_pv_to_all_cel": [9, 12, 17], "add_lost_pv_to_all_eq_cel": [9, 12, 17], "add_lost_pv_to_all_fip_cel": [9, 12, 17], "add_lost_pv_to_boundary_cel": [9, 12, 17], "coarser_properti": [9, 12, 17], "identify_removed_pilar": [9, 12, 17], "identify_removed_pilars_zdir": [9, 12, 17], "initialize_properti": [9, 12, 17], "runs_execut": [9, 12], "utilii": [13, 14, 15, 16, 17, 18], "necessari": [13, 14], "dic": [13, 14, 15, 16, 17, 18], "method": [13, 14, 15, 17], "arg": [13, 14, 15, 16, 17, 18], "dict": [13, 14, 15, 16, 17, 18], "global": [13, 14, 15, 16, 17, 18], "dictionari": [13, 14, 15, 16, 17, 18], "return": [13, 14, 15, 16, 17, 18], "none": [13, 14, 18], "tabl": 13, "scrip": 14, "diffeent": 14, "ind": [14, 16], "i_d": 14, "find": 14, "list": [14, 16], "int": [14, 15, 16, 17], "its": 14, "increas": 14, "shift": 14, "cluster": 14, "zcord": 14, "nrwo": 14, "splite": 14, "row": 14, "prop": [3, 14], "section": 14, "map": [14, 15], "view": 14, "clusmin": 14, "clusmax": 14, "rmv": 14, "sure": 14, "nor": 14, "destroi": 14, "panda": 14, "datafram": 14, "mask": 14, "segment": 14, "well": [14, 19], "keyword": 14, "ir": 14, "zcorn": 14, "coordin": 14, "corner": [14, 15], "d_z": 14, "z_t": 14, "z_b": 14, "z_b_t": 14, "arrai": [14, 17], "integ": 14, "float": [14, 18], "dz": 14, "top": 14, "posit": [14, 15], "bottom": 14, "identifi": [14, 17], "point": [14, 15], "cell_index": 15, "face": 15, "refer": [15, 17], "requiri": 16, "lol": 16, "num_lin": 16, "befor": 16, "inject": 16, "obtain": 16, "dic1": 16, "local": 16, "in_fil": 16, "str": 16, "text": 16, "quantiti": 16, "uncoars": 16, "29": 16, "inx": 17, "num": 17, "below": 19, "might": 19, "check": 19, "out": 19, "csp": 19, "spe11": 19, "benchmark": 19, "dynam": 19, "quick": 19, "gif": 19, "vtk": 19, "expans": 19, "co2": 19, "horda": 19, "platform": 19, "leakag": 19, "remedi": 19, "microbi": 19, "induc": 19, "calcit": 19, "precipit": 19, "open": 19, "imag": 19, "cfd": 19, "microsystem": 19, "trial": 3, "note": 3, "abov": 3, "drogon_hist": 3, "l127": 3, "128": 3, "schedul": 3, "l242": 3, "243": 3, "total": 3, "conserv": 3, "drogon_hist_pycopm": 3, "reduc": 3, "31": 3, "11": 3, "across": 3, "generet": 3, "swatinit": 3}, "objects": {"": [[9, 0, 0, "-", "pycopm"]], "pycopm": [[10, 0, 0, "-", "core"], [12, 0, 0, "-", "utils"]], "pycopm.core": [[11, 0, 0, "-", "pycopm"]], "pycopm.core.pycopm": [[11, 1, 1, "", "load_parser"], [11, 1, 1, "", "main"], [11, 1, 1, "", "pycopm"]], "pycopm.utils": [[13, 0, 0, "-", "files_writer"], [14, 0, 0, "-", "generate_coarser_files"], [15, 0, 0, "-", "grid_builder"], [16, 0, 0, "-", "input_values"], [17, 0, 0, "-", "properties_builder"], [18, 0, 0, "-", "runs_executer"]], "pycopm.utils.files_writer": [[13, 1, 1, "", "coarser_files"], [13, 1, 1, "", "ert_files"], [13, 1, 1, "", "grid_features"], [13, 1, 1, "", "opm_properties"], [13, 1, 1, "", "write_let_tables"]], "pycopm.utils.generate_coarser_files": [[14, 1, 1, "", "create_deck"], [14, 1, 1, "", "find_neighbors"], [14, 1, 1, "", "get_ijk"], [14, 1, 1, "", "handle_clusters"], [14, 1, 1, "", "handle_cp_grid"], [14, 1, 1, "", "handle_fault"], [14, 1, 1, "", "handle_grid_props"], [14, 1, 1, "", "handle_mapaxes"], [14, 1, 1, "", "handle_pv"], [14, 1, 1, "", "handle_regions"], [14, 1, 1, "", "handle_segmented_wells"], [14, 1, 1, "", "handle_wells"], [14, 1, 1, "", "handle_zcorn"], [14, 1, 1, "", "map_ijk"], [14, 1, 1, "", "map_properties"], [14, 1, 1, "", "process_the_deck"], [14, 1, 1, "", "write_grid"], [14, 1, 1, "", "write_props"]], "pycopm.utils.grid_builder": [[15, 1, 1, "", "coarser_grid"], [15, 1, 1, "", "handle_face_dir_im"], [15, 1, 1, "", "handle_face_dir_ip"], [15, 1, 1, "", "handle_face_dir_jm"], [15, 1, 1, "", "handle_face_dir_jp"], [15, 1, 1, "", "handle_faults"]], "pycopm.utils.input_values": [[16, 1, 1, "", "assign_hm_parameters"], [16, 1, 1, "", "assign_standard_values"], [16, 1, 1, "", "get_number_of_lines"], [16, 1, 1, "", "initialize_values"], [16, 1, 1, "", "process_input"], [16, 1, 1, "", "read_reference"], [16, 1, 1, "", "read_the_first_part"]], "pycopm.utils.properties_builder": [[17, 1, 1, "", "add_lost_pv_to_all_cells"], [17, 1, 1, "", "add_lost_pv_to_all_eq_cells"], [17, 1, 1, "", "add_lost_pv_to_all_fip_cells"], [17, 1, 1, "", "add_lost_pv_to_boundary_cells"], [17, 1, 1, "", "coarser_properties"], [17, 1, 1, "", "identify_removed_pilars"], [17, 1, 1, "", "identify_removed_pilars_zdir"], [17, 1, 1, "", "initialize_properties"]], "pycopm.utils.runs_executer": [[18, 1, 1, "", "plotting"], [18, 1, 1, "", "simulations"]]}, "objtypes": {"0": "py:module", "1": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"]}, "titleterms": {"about": 0, "pycopm": [0, 1, 4, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], "python": [1, 5], "api": 1, "configur": [2, 3, 8], "file": [2, 3, 8], "exampl": 3, "via": [3, 8], "drogon": 3, "opm": [3, 5, 8], "flow": [3, 5, 8], "deck": [3, 8], "spe10": 3, "smeaheia": 3, "welcom": 4, "": 4, "document": 4, "indic": 4, "tabl": 4, "instal": 5, "packag": [5, 9, 10, 12], "sourc": 5, "build": 5, "linux": 5, "window": 5, "maco": 5, "introduct": 6, "concept": 6, "roadmap": 6, "overview": 6, "output": 8, "folder": 8, "an": 8, "input": 8, "subpackag": 9, "modul": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18], "content": [9, 10, 12], "core": [10, 11], "submodul": [10, 12], "util": [12, 13, 14, 15, 16, 17, 18], "files_writ": 13, "generate_coarser_fil": 14, "grid_build": 15, "input_valu": 16, "properties_build": 17, "runs_execut": 18, "relat": 19, "pyopmspe11": 19, "pyopmnearwel": 19, "plopm": 19, "exprecc": 19, "ad": 19, "micp": 19, "pymm": 19, "gener": 3}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"About pycopm": [[0, "about-pycopm"]], "pycopm Python API": [[1, "pycopm-python-api"]], "pycopm": [[1, "pycopm"], [7, "pycopm"]], "Configuration file": [[2, "configuration-file"]], "Welcome to pycopm\u2019s documentation!": [[4, "welcome-to-pycopm-s-documentation"]], "Indices and tables": [[4, "indices-and-tables"]], "Installation": [[5, "installation"]], "Python package": [[5, "python-package"]], "OPM Flow": [[5, "opm-flow"]], "Source build in Linux/Windows": [[5, "source-build-in-linux-windows"]], "Source build in macOS": [[5, "source-build-in-macos"]], "Via configuration files": [[8, "via-configuration-files"], [3, "via-configuration-files"]], "Output folder": [[8, "output-folder"]], "Via an OPM Flow input deck": [[8, "via-an-opm-flow-input-deck"]], "pycopm package": [[9, "pycopm-package"]], "Subpackages": [[9, "subpackages"]], "Module contents": [[9, "module-pycopm"], [10, "module-pycopm.core"], [12, "module-pycopm.utils"]], "pycopm.core package": [[10, "pycopm-core-package"]], "Submodules": [[10, "submodules"], [12, "submodules"]], "pycopm.core.pycopm module": [[11, "module-pycopm.core.pycopm"]], "pycopm.utils package": [[12, "pycopm-utils-package"]], "pycopm.utils.files_writer module": [[13, "module-pycopm.utils.files_writer"]], "pycopm.utils.generate_coarser_files module": [[14, "module-pycopm.utils.generate_coarser_files"]], "pycopm.utils.grid_builder module": [[15, "module-pycopm.utils.grid_builder"]], "pycopm.utils.input_values module": [[16, "module-pycopm.utils.input_values"]], "pycopm.utils.properties_builder module": [[17, "module-pycopm.utils.properties_builder"]], "pycopm.utils.runs_executer module": [[18, "module-pycopm.utils.runs_executer"]], "Related": [[19, "related"]], "pyopmspe11": [[19, "pyopmspe11"]], "pyopmnearwell": [[19, "pyopmnearwell"]], "plopm": [[19, "plopm"]], "expreccs": [[19, "expreccs"]], "ad-micp": [[19, "ad-micp"]], "pymm": [[19, "pymm"]], "Introduction": [[6, "introduction"]], "Concept": [[6, "concept"]], "Roadmap": [[6, "roadmap"]], "Overview": [[6, "overview"]], "Examples": [[3, "examples"]], "Drogon": [[3, "drogon"]], "Via OPM Flow decks": [[3, "via-opm-flow-decks"]], "SPE10": [[3, "spe10"]], "Smeaheia": [[3, "smeaheia"]], "Generic Drogon": [[3, "generic-drogon"]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["about", "api", "configuration_file", "examples", "index", "installation", "introduction", "modules", "output_folder", "pycopm", "pycopm.core", "pycopm.core.pycopm", "pycopm.utils", "pycopm.utils.files_writer", "pycopm.utils.generate_coarser_files", "pycopm.utils.grid_builder", "pycopm.utils.input_values", "pycopm.utils.properties_builder", "pycopm.utils.runs_executer", "related"], "filenames": ["about.rst", "api.rst", "configuration_file.rst", "examples.rst", "index.rst", "installation.rst", "introduction.rst", "modules.rst", "output_folder.rst", "pycopm.rst", "pycopm.core.rst", "pycopm.core.pycopm.rst", "pycopm.utils.rst", "pycopm.utils.files_writer.rst", "pycopm.utils.generate_coarser_files.rst", "pycopm.utils.grid_builder.rst", "pycopm.utils.input_values.rst", "pycopm.utils.properties_builder.rst", "pycopm.utils.runs_executer.rst", "related.rst"], "titles": ["About pycopm", "pycopm Python API", "Configuration file", "Examples", "Welcome to pycopm\u2019s documentation!", "Installation", "Introduction", "pycopm", "Output folder", "pycopm package", "pycopm.core package", "pycopm.core.pycopm module", "pycopm.utils package", "pycopm.utils.files_writer module", "pycopm.utils.generate_coarser_files module", "pycopm.utils.grid_builder module", "pycopm.utils.input_values module", "pycopm.utils.properties_builder module", "pycopm.utils.runs_executer module", "Related"], "terms": {"tool": [0, 3, 5, 6, 8, 19], "coarsen": [0, 1, 2, 3, 6], "opm": [0, 1, 2, 4, 6, 13, 16, 18, 19], "flow": [0, 1, 2, 4, 6, 13, 18, 19], "geolog": [0, 2, 3, 6, 8], "model": [0, 2, 3, 6, 8, 19], "i": [0, 1, 2, 3, 6, 8, 14, 15], "being": 0, "fund": 0, "center": [0, 14], "sustain": 0, "subsurfac": 0, "resourc": [0, 19], "cssr": [0, 3, 5, 6], "project": [0, 5, 19], "331841": 0, "thi": [0, 2, 3, 5, 6, 8], "work": [0, 6], "progress": 0, "contribut": [0, 5], "ar": [0, 1, 2, 3, 5, 6, 8, 19], "more": 0, "than": 0, "welcom": 0, "us": [0, 1, 2, 3, 5, 6, 8, 17, 19], "fork": 0, "pull": 0, "request": 0, "approach": [0, 2], "The": [1, 2, 3, 6, 8], "main": [1, 2, 3, 9, 10, 11, 14], "script": [1, 5, 11], "execut": [1, 2, 3, 5, 6, 8, 11, 18], "locat": [1, 8], "core": [1, 5, 7, 9], "folder": [1, 3, 4, 5, 6], "differ": [1, 2], "job": 1, "call": [1, 2, 8, 14], "ert": [1, 2, 3, 6, 8, 13, 16, 18], "reference_simul": 1, "contain": [1, 3], "gener": [1, 2, 3, 6, 8, 14, 15, 17, 18, 19], "file": [1, 4, 5, 6, 13, 14, 16, 18], "after": [1, 2, 3, 5, 8], "run": [1, 2, 3, 5, 6, 8, 13, 18], "norn": [1, 2, 4, 6, 8], "drogon": [1, 2, 4, 6, 8], "case": [1, 3], "test": [1, 2, 3, 5, 6], "template_script": 1, "mako": [1, 13], "base": [1, 6, 19], "from": [1, 2, 3, 5, 14, 15, 16, 19], "origin": [1, 3], "deck": [1, 2, 4, 6, 13, 14, 17], "final": [1, 2], "util": [1, 7, 9], "function": [1, 2, 11, 13, 15, 16, 17, 18], "framework": [1, 6, 19], "pyocpm": 1, "packag": [1, 4, 7], "subpackag": [1, 4, 7], "submodul": [1, 7, 9], "modul": [1, 4, 5, 7, 19], "content": [1, 3, 4, 7], "allow": [2, 6], "set": [2, 3, 6, 8, 16], "integr": 2, "studi": [2, 3, 6, 8, 18, 19], "histori": [2, 6, 8], "match": [2, 6, 8], "onli": [2, 3, 5, 6, 8, 14], "To": [2, 3, 5], "pycopm": [2, 3, 5, 6, 8], "ani": 2, "given": [2, 3, 6], "coarser": [2, 3, 6, 8, 14, 17], "can": [2, 3, 5, 8], "achiev": [2, 3, 5], "without": [2, 8], "paramet": [2, 6, 16, 17], "via": [2, 4, 6], "command": [2, 5], "line": [2, 3, 5, 16], "see": [2, 5, 6, 8], "overview": [2, 4], "h": 2, "definit": [2, 3], "argument": [2, 6, 11, 14], "option": [2, 6, 11], "exampl": [2, 4, 8], "here": [2, 3], "we": [2, 3, 8, 14], "an": [2, 4, 5, 19], "one": [2, 3, 6, 8, 14], "txt": [2, 3, 5, 6], "first": [2, 3, 16], "input": [2, 3, 4, 6, 14, 16, 17], "full": [2, 6, 8], "path": [2, 6, 8], "If": [2, 5], "your": [2, 6, 8], "write": [2, 13, 14, 17], "e": [2, 3, 5, 6, 8], "g": [2, 3, 5, 6, 8], "user": [2, 5], "dmar": 2, "github": [2, 3, 5, 6], "build": [2, 4], "simul": [2, 3, 5, 8, 9, 12, 16, 18, 19], "bin": [2, 5], "follow": [2, 3, 5, 6, 8], "delet": 2, "suffix": 2, "save": [2, 3, 6], "storag": [2, 19], "egrid": 2, "dbg": 2, "grdecl": 2, "unrst": 2, "unsmri": 2, "prt": 2, "inc": [2, 6, 16], "infostep": 2, "smspec": 2, "init": 2, "you": [2, 3, 5, 8], "type": [2, 19], "each": [2, 6], "realiz": 2, "complet": 2, "order": [2, 3, 6], "memori": 2, "number": [2, 3, 16], "jump": [2, 3, 14], "2": [2, 3, 6], "4": [2, 3], "sinc": 2, "implement": [2, 3, 6], "white": 2, "space": 2, "between": [2, 6], "block": [2, 17], "need": [2, 3, 5, 6, 8], "next": 2, "entri": 2, "defin": [2, 3, 17], "singl": 2, "0": [2, 3, 5, 6], "1": [2, 3, 5, 6], "vector": [2, 6], "x": [2, 3, 6], "coers": 2, "y": [2, 3, 6], "z": [2, 3, 6, 14, 17], "ensembl": [2, 6], "maximum": [2, 3], "parallel": 2, "mpi": [2, 5], "process": [2, 14, 16], "600": 2, "runtim": 2, "second": 2, "A": [2, 19], "valu": [2, 3, 6, 16], "mean": [2, 6], "unlimit": 2, "minimum": 2, "must": 2, "have": [2, 14], "succeed": 2, "regard": 2, "success": 2, "7": 2, "specif": 2, "seed": 2, "reproduc": 2, "observations_train": 2, "name": [2, 6, 16], "observ": 2, "hm": [2, 3], "observations_test": 2, "observations_complet": 2, "select": [2, 8, 18], "which": [2, 3, 5], "default": [2, 3, 6, 8], "let": [2, 13], "sat": 2, "For": [2, 3, 5, 8], "satnum": [2, 6], "comput": 2, "sandv": 2, "et": 2, "al": 2, "2022": 2, "cell": [2, 3, 6, 14, 15, 16, 17], "correct": [2, 6, 8, 17], "lost": [2, 17], "pv": 2, "boundari": [2, 17], "account": 2, "poros": [2, 3], "all": [2, 3, 6, 8, 14, 17], "initi": [2, 6, 16, 17], "equil": 2, "fine": 2, "scale": [2, 6], "error": [2, 3, 8], "wwpr": 2, "wopr": 2, "wgpr": 2, "100": 2, "100000": 2, "2005": 2, "03": 2, "01": [2, 3], "last": [2, 16], "date": 2, "do": [2, 5, 6], "remov": [2, 3, 6, 14, 17], "current": [2, 3, 5, 6, 8, 14, 18], "read": [2, 6, 16], "result": [2, 8], "inform": 2, "shown": 2, "termin": [2, 3, 5, 6], "instead": 2, "same": [2, 8, 14, 17], "discuss": 2, "later": 2, "three": 2, "pillar": [2, 14], "direct": [2, 3, 6, 17], "respect": 2, "j": [2, 3, 6, 14, 15], "k": [2, 3, 6, 14, 15], "index": [2, 4, 14, 15, 17], "standard": 2, "data": [2, 3, 6], "pilar": [2, 3, 6, 17], "keep": [2, 3, 6, 14], "honor": 2, "shape": 2, "Then": [2, 3, 8], "provid": 2, "chang": 2, "": [2, 3, 6, 14], "add": [2, 3, 6, 14], "back": 2, "remain": 2, "mpirun": 2, "avail": [2, 5, 6], "stop": 2, "time": [2, 3, 18], "random": 2, "satur": [2, 13, 16], "consid": 2, "region": [2, 3, 14], "ntg": 2, "poro": [2, 3, 6], "properti": [2, 3, 6, 13, 14, 17], "modifi": [2, 5, 13, 14, 15, 16, 17, 18], "activ": [2, 3, 5, 6, 14, 17], "gui": 2, "test_run": 2, "ensemble_experi": 2, "ensemble_smooth": 2, "iterative_ensemble_smooth": 2, "es_mda": 2, "weight": 2, "flag": [2, 3, 6, 14, 16], "support": [2, 5, 6, 14], "confer": 2, "document": [2, 6], "descript": [2, 6], "enabl": [2, 6], "rst": 2, "true": 2, "newton": 2, "min": [2, 3, 6], "iter": 2, "dist": 2, "distpara": 2, "lw": 2, "3": [2, 3, 5, 6], "uniform": 2, "5": [2, 3], "ew": 2, "tw": 2, "lo": 2, "eo": 2, "lg": 2, "eg": 2, "tg": 2, "log": 2, "eog": 2, "tog": 2, "lmlto": 2, "emlto": 2, "9": [2, 5], "tmlto": 2, "lmltg": 2, "emltg": 2, "tmltg": 2, "permeabl": 2, "rock": 2, "coars": [2, 3, 6, 8, 14, 15, 17], "max": [2, 3, 6], "permx": [2, 6], "permi": [2, 6], "permz": [2, 6], "distribut": [2, 14, 17], "interv": 2, "perm_min": 2, "perm_max": 2, "correspond": [2, 6, 14], "perform": [3, 6], "insid": [3, 5], "o": [3, 6, 8, 14], "drogon_coars": 3, "test_generic_deck": 8, "py": [8, 18], "where": [3, 6], "spe10_model2": 3, "download": 3, "c": [3, 6], "8": 3, "left": [3, 8], "right": [3, 8, 14], "By": 3, "statoil_feasibility_sim_model_with_depletion_kross_inj_sector_20": 3, "mode": [3, 6], "decid": [], "should": 5, "inact": [3, 6], "dry": [3, 6], "grid": [3, 5, 6, 13, 14, 15, 17], "static": 6, "variabl": [13, 16], "statoil_feasibility_sim_model_with_depletion_kross_inj_sector_20_pycopm": 3, "our": 3, "plopm": [3, 4], "friend": 3, "png": [3, 19], "figur": [3, 8], "instal": [3, 4], "pip": [3, 5], "git": [3, 5], "http": [3, 5, 6], "com": [3, 5, 6], "In": [3, 5, 6], "handl": [3, 14], "requir": [3, 5, 14, 16, 17], "indic": [3, 6, 14], "fault": [3, 6, 14, 15], "wellspec": 3, "assum": 3, "includ": [3, 5, 8], "replac": 3, "those": 3, "actual": 3, "note": 3, "abov": 3, "drogon_hist": 3, "l127": 3, "128": 3, "schedul": 3, "l242": 3, "243": 3, "n": [3, 6, 14], "p": [3, 6], "drogon_hist_pycopm": 3, "would": [3, 6, 8], "total": 3, "pore": [3, 6, 14, 17], "volum": [3, 6, 14, 17], "conserv": 3, "reduc": 3, "31": 3, "11": 3, "trial": 3, "avoid": [3, 6], "connect": [3, 6], "across": 3, "generet": [], "prop": 14, "swatinit": 6, "introduct": [3, 4, 8], "concept": 4, "roadmap": 4, "python": [4, 19], "sourc": [4, 19], "linux": 4, "window": 4, "maco": 4, "configur": [4, 6], "spe10": [4, 8], "smeaheia": 4, "api": 4, "output": [4, 6, 16], "relat": [3, 4, 13], "pyopmspe11": 4, "pyopmnearwel": 4, "exprecc": 4, "ad": [3, 4, 6], "micp": 4, "pymm": 4, "about": 4, "search": [4, 14], "page": 4, "exist": 5, "environ": 5, "interest": [5, 19], "code": 5, "clone": [3, 5], "repositori": 5, "virtual": 5, "repo": 5, "get": 5, "cd": 5, "creat": [3, 5, 6, 8, 14], "python3": 5, "m": [3, 5, 6], "venv": 5, "vpycopm": 5, "upgrad": 5, "setuptool": 5, "wheel": 5, "lint": 5, "dev": 5, "r": 5, "also": [3, 5, 14], "org": 5, "releas": 5, "2024": 5, "04": 5, "master": 5, "branch": 5, "ci": 5, "yml": 5, "binari": 5, "subsystem": 5, "could": [5, 8], "try": [5, 6], "prerequisit": 5, "turn": 5, "current_directori": 5, "pwd": 5, "common": 5, "done": [5, 6], "mkdir": 5, "cmake": 5, "duse_mpi": 5, "dwith_ndebug": 5, "dcmake_build_typ": 5, "dcmake_prefix_path": 5, "make": [3, 5, 6, 14], "j5": 5, "sh": 5, "build_opm_mpi": 5, "copi": [5, 8], "previou": [3, 5], "so": [5, 14], "built": 5, "addit": 5, "dune": 5, "librari": 5, "macport": 5, "brew": 5, "geometri": 5, "istl": 5, "gitlab": 5, "v2": 5, "dunecontrol": 5, "dcmake_disable_find_package_mpi": 5, "dpython_execut": 5, "dopm_enable_python": 5, "ON": 5, "least": [3, 5, 6, 14], "version": 5, "10": 5, "due": 5, "resdata": 5, "describ": [3, 6, 8], "host": 6, "simplifi": 6, "flexibl": 6, "develop": [3, 6, 8], "focu": [6, 8], "were": 6, "two": 6, "reservoir": 6, "focus": [3, 6], "give": [6, 8], "manual": 6, "templat": [6, 13], "wa": [3, 6, 8], "adapt": [6, 8], "favourit": [6, 8], "optim": [6, 8], "pet": [6, 8], "everest": [6, 8], "name_of_input_fil": 6, "f": 6, "just": 6, "level": 6, "dir": [6, 15], "either": 6, "ones": 6, "ha": 6, "6": 6, "while": 6, "them": [6, 19], "actnum": [6, 14], "new": [6, 14], "endnum": 6, "eqlnum": [6, 17], "fipnum": [6, 17], "fluxnum": 6, "imbnum": 6, "miscnum": 6, "multnum": 6, "pvtnum": 6, "rocknum": 6, "mult": 6, "xyz": 6, "arithmet": 6, "averag": 6, "harmon": 6, "rest": 6, "closest": 6, "tune": 6, "creation": 6, "neighbour": [3, 6, 14], "discontinu": 6, "along": 6, "around": 6, "noth": 6, "prep": 6, "exectut": 6, "prep_deck": 6, "deck_dri": 6, "w": 6, "plu": 6, "_pycopm": 6, "l": 6, "text": [6, 16], "befor": [6, 16], "pycopm_": 6, "porv": 6, "pycopm_porv": 6, "etc": 6, "utf8": 6, "iso": 6, "8859": 6, "encod": 6, "jk": 6, "return": [6, 13, 14, 15, 16, 17, 18], "posit": [6, 14, 15], "empti": 6, "As": 8, "earli": 8, "screenshot": 8, "show": 8, "some": [8, 19], "postprocess": 8, "directli": 8, "further": 8, "plot": [8, 9, 12, 18], "visual": 8, "resinsight": 8, "focuc": 8, "load_pars": [9, 10, 11], "files_writ": [9, 12], "coarser_fil": [9, 12, 13], "ert_fil": [9, 12, 13], "grid_featur": [9, 12, 13], "opm_properti": [9, 12, 13], "write_let_t": [9, 12, 13], "generate_coarser_fil": [9, 12], "create_deck": [9, 12, 14], "find_neighbor": [9, 12, 14], "get_ijk": [9, 12, 14], "handle_clust": [9, 12, 14], "handle_cp_grid": [9, 12, 14], "handle_fault": [9, 12, 14, 15], "handle_grid_prop": [9, 12, 14], "handle_mapax": [9, 12, 14], "handle_op": [9, 12, 14], "handle_prop": [9, 12, 14], "handle_pv": [9, 12, 14], "handle_region": [9, 12, 14], "handle_segmented_wel": [9, 12, 14], "handle_wel": [9, 12, 14], "handle_zcorn": [9, 12, 14], "map_ijk": [9, 12, 14], "map_properti": [9, 12, 14], "process_the_deck": [9, 12, 14], "write_grid": [9, 12, 14], "write_prop": [9, 12, 14], "grid_build": [9, 12], "coarser_grid": [9, 12, 15], "handle_face_dir_im": [9, 12, 15], "handle_face_dir_ip": [9, 12, 15], "handle_face_dir_jm": [9, 12, 15], "handle_face_dir_jp": [9, 12, 15], "input_valu": [9, 12], "assign_hm_paramet": [9, 12, 16], "assign_standard_valu": [9, 12, 16], "get_number_of_lin": [9, 12, 16], "initialize_valu": [9, 12, 16], "process_input": [9, 12, 16], "read_refer": [9, 12, 16], "read_the_first_part": [9, 12, 16], "properties_build": [9, 12], "add_lost_pv_to_all_cel": [9, 12, 17], "add_lost_pv_to_all_eq_cel": [9, 12, 17], "add_lost_pv_to_all_fip_cel": [9, 12, 17], "add_lost_pv_to_boundary_cel": [9, 12, 17], "coarser_properti": [9, 12, 17], "identify_removed_pilar": [9, 12, 17], "identify_removed_pilars_zdir": [9, 12, 17], "initialize_properti": [9, 12, 17], "runs_execut": [9, 12], "utilii": [13, 14, 15, 16, 17, 18], "necessari": [13, 14], "dic": [13, 14, 15, 16, 17, 18], "method": [13, 14, 15, 17], "arg": [13, 14, 15, 16, 17, 18], "dict": [13, 14, 15, 16, 17, 18], "global": [13, 14, 15, 16, 17, 18], "dictionari": [13, 14, 15, 16, 17, 18], "none": [13, 14, 18], "tabl": 13, "scrip": 14, "diffeent": 14, "ind": [14, 16], "i_d": 14, "find": [8, 14], "list": [14, 16], "int": [14, 15, 16, 17], "its": 14, "increas": 14, "shift": 14, "cluster": 14, "zcord": 14, "nrwo": 14, "splite": 14, "row": 14, "section": [3, 14], "map": [14, 15], "view": [3, 14], "oper": [3, 14], "clusmin": 14, "clusmax": 14, "rmv": 14, "sure": 14, "nor": 14, "destroi": 14, "panda": 14, "datafram": 14, "mask": 14, "segment": 14, "well": [2, 14, 19], "keyword": 14, "ir": 14, "zcorn": 14, "coordin": 14, "corner": [14, 15], "d_z": 14, "z_t": 14, "z_b": 14, "z_b_t": 14, "arrai": [14, 17], "integ": [3, 14], "float": [14, 18], "dz": 14, "top": [3, 14], "bottom": 14, "identifi": [14, 17], "point": [14, 15], "cell_index": 15, "face": 15, "refer": [15, 17], "requiri": 16, "lol": 16, "num_lin": 16, "inject": 16, "obtain": 16, "dic1": 16, "local": 16, "in_fil": 16, "str": 16, "quantiti": 16, "uncoars": 16, "29": 16, "inx": 17, "num": 17, "below": 19, "might": [8, 19], "check": 19, "out": 19, "csp": 19, "spe11": 19, "benchmark": 19, "dynam": 19, "quick": 19, "gif": [3, 19], "vtk": 19, "expans": 19, "co2": 19, "horda": 19, "platform": 19, "leakag": 19, "remedi": 19, "microbi": 19, "induc": 19, "calcit": 19, "precipit": 19, "open": 19, "imag": 19, "cfd": 19, "microsystem": 19, "norne_coars": 3, "hello": 4, "world": 4, "other": 8, "summari": 8, "recommend": [3, 8], "appear": 8, "otherwis": 8, "hello_world": 3, "made": 3, "statoil_feasibility_sim_model_with_depletion_kross_inj_sector_20_prep_pycopm_dryrun": 3, "v": 3, "subfig": 3, "t": 3, "xunit": 3, "km": 3, "xformat": 3, "0f": 3, "yunit": 3, "yformat": 3, "d": 3, "suptitl": 3, "cet_rainbow_bgyrm_35_85_c69": 3, "cbsfax": 3, "30": 3, "02": 3, "cformat": 3, "2f": 3, "multregt": 3, "lot": 3, "divid": 3, "conquer": 3, "apporach": 3, "directon": 3, "miss": 3, "certain": 3, "featur": 3, "norne_atw2013": 3}, "objects": {"": [[9, 0, 0, "-", "pycopm"]], "pycopm": [[10, 0, 0, "-", "core"], [12, 0, 0, "-", "utils"]], "pycopm.core": [[11, 0, 0, "-", "pycopm"]], "pycopm.core.pycopm": [[11, 1, 1, "", "load_parser"], [11, 1, 1, "", "main"], [11, 1, 1, "", "pycopm"]], "pycopm.utils": [[13, 0, 0, "-", "files_writer"], [14, 0, 0, "-", "generate_coarser_files"], [15, 0, 0, "-", "grid_builder"], [16, 0, 0, "-", "input_values"], [17, 0, 0, "-", "properties_builder"], [18, 0, 0, "-", "runs_executer"]], "pycopm.utils.files_writer": [[13, 1, 1, "", "coarser_files"], [13, 1, 1, "", "ert_files"], [13, 1, 1, "", "grid_features"], [13, 1, 1, "", "opm_properties"], [13, 1, 1, "", "write_let_tables"]], "pycopm.utils.generate_coarser_files": [[14, 1, 1, "", "create_deck"], [14, 1, 1, "", "find_neighbors"], [14, 1, 1, "", "get_ijk"], [14, 1, 1, "", "handle_clusters"], [14, 1, 1, "", "handle_cp_grid"], [14, 1, 1, "", "handle_fault"], [14, 1, 1, "", "handle_grid_props"], [14, 1, 1, "", "handle_mapaxes"], [14, 1, 1, "", "handle_oper"], [14, 1, 1, "", "handle_props"], [14, 1, 1, "", "handle_pv"], [14, 1, 1, "", "handle_regions"], [14, 1, 1, "", "handle_segmented_wells"], [14, 1, 1, "", "handle_wells"], [14, 1, 1, "", "handle_zcorn"], [14, 1, 1, "", "map_ijk"], [14, 1, 1, "", "map_properties"], [14, 1, 1, "", "process_the_deck"], [14, 1, 1, "", "write_grid"], [14, 1, 1, "", "write_props"]], "pycopm.utils.grid_builder": [[15, 1, 1, "", "coarser_grid"], [15, 1, 1, "", "handle_face_dir_im"], [15, 1, 1, "", "handle_face_dir_ip"], [15, 1, 1, "", "handle_face_dir_jm"], [15, 1, 1, "", "handle_face_dir_jp"], [15, 1, 1, "", "handle_faults"]], "pycopm.utils.input_values": [[16, 1, 1, "", "assign_hm_parameters"], [16, 1, 1, "", "assign_standard_values"], [16, 1, 1, "", "get_number_of_lines"], [16, 1, 1, "", "initialize_values"], [16, 1, 1, "", "process_input"], [16, 1, 1, "", "read_reference"], [16, 1, 1, "", "read_the_first_part"]], "pycopm.utils.properties_builder": [[17, 1, 1, "", "add_lost_pv_to_all_cells"], [17, 1, 1, "", "add_lost_pv_to_all_eq_cells"], [17, 1, 1, "", "add_lost_pv_to_all_fip_cells"], [17, 1, 1, "", "add_lost_pv_to_boundary_cells"], [17, 1, 1, "", "coarser_properties"], [17, 1, 1, "", "identify_removed_pilars"], [17, 1, 1, "", "identify_removed_pilars_zdir"], [17, 1, 1, "", "initialize_properties"]], "pycopm.utils.runs_executer": [[18, 1, 1, "", "plotting"], [18, 1, 1, "", "simulations"]]}, "objtypes": {"0": "py:module", "1": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"]}, "titleterms": {"about": 0, "pycopm": [0, 1, 4, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], "python": [1, 5], "api": 1, "configur": [2, 3, 8], "file": [2, 3, 8], "exampl": 3, "via": [3, 8], "drogon": 3, "opm": [3, 5, 8], "flow": [3, 5, 8], "deck": [3, 8], "spe10": 3, "smeaheia": 3, "gener": [], "welcom": 4, "": 4, "document": 4, "indic": 4, "tabl": 4, "instal": 5, "packag": [5, 9, 10, 12], "sourc": 5, "build": 5, "linux": 5, "window": 5, "maco": 5, "introduct": 6, "concept": 6, "roadmap": 6, "overview": 6, "output": 8, "folder": 8, "an": 8, "input": 8, "subpackag": 9, "modul": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18], "content": [9, 10, 12], "core": [10, 11], "submodul": [10, 12], "util": [12, 13, 14, 15, 16, 17, 18], "files_writ": 13, "generate_coarser_fil": 14, "grid_build": 15, "input_valu": 16, "properties_build": 17, "runs_execut": 18, "relat": 19, "pyopmspe11": 19, "pyopmnearwel": 19, "plopm": 19, "exprecc": 19, "ad": 19, "micp": 19, "pymm": 19, "hello": 3, "world": 3, "norn": 3}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"About pycopm": [[0, "about-pycopm"]], "pycopm Python API": [[1, "pycopm-python-api"]], "pycopm": [[1, "pycopm"], [7, "pycopm"]], "Welcome to pycopm\u2019s documentation!": [[4, "welcome-to-pycopm-s-documentation"]], "Indices and tables": [[4, "indices-and-tables"]], "Installation": [[5, "installation"]], "Python package": [[5, "python-package"]], "OPM Flow": [[5, "opm-flow"]], "Source build in Linux/Windows": [[5, "source-build-in-linux-windows"]], "Source build in macOS": [[5, "source-build-in-macos"]], "pycopm package": [[9, "pycopm-package"]], "Subpackages": [[9, "subpackages"]], "Module contents": [[9, "module-pycopm"], [10, "module-pycopm.core"], [12, "module-pycopm.utils"]], "pycopm.core package": [[10, "pycopm-core-package"]], "Submodules": [[10, "submodules"], [12, "submodules"]], "pycopm.utils package": [[12, "pycopm-utils-package"]], "pycopm.utils.files_writer module": [[13, "module-pycopm.utils.files_writer"]], "pycopm.utils.grid_builder module": [[15, "module-pycopm.utils.grid_builder"]], "pycopm.utils.input_values module": [[16, "module-pycopm.utils.input_values"]], "pycopm.utils.properties_builder module": [[17, "module-pycopm.utils.properties_builder"]], "pycopm.utils.runs_executer module": [[18, "module-pycopm.utils.runs_executer"]], "Related": [[19, "related"]], "pyopmspe11": [[19, "pyopmspe11"]], "pyopmnearwell": [[19, "pyopmnearwell"]], "plopm": [[19, "plopm"]], "expreccs": [[19, "expreccs"]], "ad-micp": [[19, "ad-micp"]], "pymm": [[19, "pymm"]], "Configuration file": [[2, "configuration-file"]], "Introduction": [[6, "introduction"]], "Concept": [[6, "concept"]], "Roadmap": [[6, "roadmap"]], "Overview": [[6, "overview"]], "Via configuration files": [[8, "via-configuration-files"], [3, "via-configuration-files"]], "Output folder": [[8, "output-folder"]], "Via an OPM Flow input deck": [[8, "via-an-opm-flow-input-deck"]], "pycopm.core.pycopm module": [[11, "module-pycopm.core.pycopm"]], "pycopm.utils.generate_coarser_files module": [[14, "module-pycopm.utils.generate_coarser_files"]], "Examples": [[3, "examples"]], "Via OPM Flow decks": [[3, "via-opm-flow-decks"]], "Hello world": [[3, "hello-world"]], "SPE10": [[3, "spe10"]], "Smeaheia": [[3, "smeaheia"]], "Drogon": [[3, "drogon"]], "Norne": [[3, "norne"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/text/configuration_file.rst b/docs/text/configuration_file.rst index 55316a4..8ddcef1 100644 --- a/docs/text/configuration_file.rst +++ b/docs/text/configuration_file.rst @@ -6,7 +6,7 @@ Configuration file only for the drogon and norne model. To use **pycopm** in any given OPM Flow geological model to generate the coarser files, this can be achieve without a configuration file, but setting the parameters via command lines (see the :ref:`overview` or run `pycopm -h` for the definition - of the argument options, and the :doc:`examples <./examples>`.) + of the argument options, as well as the examples in :ref:`generic`.) Here we use as an example one of the configuration files used in the tests diff --git a/docs/text/examples.rst b/docs/text/examples.rst index bf1edd5..c3b8f87 100644 --- a/docs/text/examples.rst +++ b/docs/text/examples.rst @@ -6,11 +6,8 @@ Examples Via configuration files ======================= -Drogon ------- - The `examples `_ folder contains configuration files -to perform HM studies in drogon and norne. For example, by executing inside the `example folder for drogon `_: +to perform HM studies in drogon and norne using `ERT `_. For example, by executing inside the `example folder for drogon `_: .. code-block:: bash @@ -20,17 +17,50 @@ The following are the drogon model from `opm-tests ` was generated using the generated coarse model. + +.. _generic: ================== Via OPM Flow decks ================== +The current development of **pycopm** focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck. + +Hello world +----------- +For the `HELLO_WORLD.DATA `_ deck, by executing: + +.. code-block:: bash + + pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all + +This would generated the following: + +.. figure:: figs/hello_world_1.png + + Dry run from the input cloned deck (left) and (right) coarsed model. Adding the flag -p 1 adds the remove pore volume to the neighbouring cells. + +To make active the coarse cell where there is only one active cell, this can be achieve by: + +.. code-block:: bash + + pycopm -i HELLO_WORLD.DATA -c 5,1,5 -m all -a max + +.. figure:: figs/hello_world_2.png + + Dry run from the input cloned deck (left) and (right) coarsed model. The region numbers by default are given by the mode, e.g., use the flag -n max to keep the maximum integer. + SPE10 ----- -See/run the `test_generic_deck.py `_ -for an example where **pycopm** is used to coarse the -`SPE10_MODEL2 model `_ by downloading the OPM files and running: +By downloading the `SPE10_MODEL2 model `_, then: .. code-block:: bash @@ -48,26 +78,20 @@ then: .. code-block:: bash - pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a mode - -will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the mode is -used to decide if a coarser cell should be active or inactive. + pycopm -i Statoil_Feasibility_sim_model_with_depletion_KROSS_INJ_SECTOR_20.DATA -o . -c 5,4,3 -a min -m all -We can execute a dry run of OPM Flow to generate the grid and static variables of the coarser model: - -.. code-block:: bash - - flow STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM.DATA --enable-dry-run=true +will generate a coarser model 5 times in the x direction, 4 in the y direction, and 3 in the z direction, where the coarse cell is +made inactive if at least one cell is inactive (-a min). We use our `plopm `_ friend to generate PNG figures: .. code-block:: bash - plopm -i STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM -s ,,0 + plopm -i ' STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PREP_PYCOPM_DRYRUN STATOIL_FEASIBILITY_SIM_MODEL_WITH_DEPLETION_KROSS_INJ_SECTOR_20_PYCOPM' -s ,,0 -v poro -subfigs 1,2 -save smeaheia -t 'Smeaheia Coarsed smeaheia' -xunits km -xformat .0f -yunits km -yformat .0f -d 5,5.2 -suptitle 0 -c cet_rainbow_bgyrm_35_85_c69 -cbsfax 0.30,0.01,0.4,0.02 -cformat .2f .. figure:: figs/smeia.png - Porosity values for the (left) original and (right) coarsed model. + Top view of porosity values for the (left) original and (right) coarsed model (note that we also coarse on the z direction). .. tip:: You can install plopm by executing in the terminal: pip install git+https://github.com/cssr-tools/plopm.git. @@ -77,16 +101,16 @@ We use our `plopm `_ friend to generate PNG (e.g., FAULTS, WELLSPECS) are assumed to be define in the main .DATA deck. Then, in order to use **pycopm** for simulation models where these properties are define via include files, replace those includes in the .DATA deck with the actual content of the include files. -Generic Drogon --------------- +Drogon +------ Following the note above, then by downloading the `DROGON model `_, replacing the lines in `DROGON_HIST.DATA `_ for the FAULTS (L127-128) and SCHEDULE (L242-243) with the actual content of those include files, then by executing: .. code-block:: bash - pycopm -i DROGON_HIST.DATA -o . -c 1,1,3 -a min -n max -p 1 - pycopm -i DROGON_HIST_PYCOPM.DATA -o . -c 1,3,1 -a mode -n mode -p 1 -j 1.9 + pycopm -i DROGON_HIST.DATA -c 1,1,3 -p 1 + pycopm -i DROGON_HIST_PYCOPM.DATA -c 1,3,1 -p 1 -j 2.5 this would generate the following coarse model: @@ -95,8 +119,23 @@ this would generate the following coarse model: Note that the total pore volume is conserved for the coarse model. Here, we first coarse in the z direction, which reduces the number of cells from 31 to 11, and after we coarse in the y direction. -After trial and error, the jump (-j) is set to 1.9 to avoid generated connections across the faults. +After trial and error, the jump (-j) is set to 2.5 to avoid generated connections across the faults. For geological models with a lot of +inactive cells and faults, this divide and conquer apporach is recommended, i.e., coarsening first in the z directon and after coarsening +in the x and y directions. .. note:: - After genereting the first coarser deck (DROGON_HIST_PYCOPM.DATA), change the path '../include/props/drogon.swatinit' to 'SWATINIT.INC', - which contains the right number of values for the coarse model. \ No newline at end of file + Add to the generated coarse deck the missing include files in the grid section related to the region operations (e.g., + ../include/grid/drogon.multregt for this case). + +Norne +----- +By downloading the `Norne model `_ (and replacing the needed include files as described in the previous +example), then here we create a coarser model by removing certain pilars in order to keep the main features of the geological model: + +.. code-block:: bash + + pycopm -i NORNE_ATW2013.DATA -x 0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,2,0,2,2,2,2,0 -y 0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,2,2,2,2,2,2,2,2,0 -z 0,0,2,0,0,2,2,2,2,2,02,2,2,2,2,0,0,2,0,2,2,0,0,0,0,0,0,0,0,0,0 -a min -p 1 + +this would generate the following coarse model: + +.. figure:: figs/norne_vec.png diff --git a/docs/text/figs/hello_world_1.png b/docs/text/figs/hello_world_1.png new file mode 100644 index 0000000..dad7676 Binary files /dev/null and b/docs/text/figs/hello_world_1.png differ diff --git a/docs/text/figs/hello_world_2.png b/docs/text/figs/hello_world_2.png new file mode 100644 index 0000000..59f6e0e Binary files /dev/null and b/docs/text/figs/hello_world_2.png differ diff --git a/docs/text/figs/norne_vec.png b/docs/text/figs/norne_vec.png new file mode 100644 index 0000000..96b88bc Binary files /dev/null and b/docs/text/figs/norne_vec.png differ diff --git a/docs/text/figs/output_generic.png b/docs/text/figs/output_generic.png index 37d880a..9f553cb 100644 Binary files a/docs/text/figs/output_generic.png and b/docs/text/figs/output_generic.png differ diff --git a/docs/text/figs/smeia.png b/docs/text/figs/smeia.png index cd4845d..5c75516 100644 Binary files a/docs/text/figs/smeia.png and b/docs/text/figs/smeia.png differ diff --git a/docs/text/introduction.rst b/docs/text/introduction.rst index b68ab76..3388bdb 100644 --- a/docs/text/introduction.rst +++ b/docs/text/introduction.rst @@ -12,8 +12,8 @@ Simplified and flexible framework to create coarser OPM Flow geological models. Roadmap ------- -In the initial development of the framework, the focus was two available models in `opm-tests `_: `norne `_ -and `drogon `_, where the coarser models are used to perform history matching studies using +In the initial development of the framework, the focus were two available models in `opm-tests `_: `norne `_ +and `drogon `_, where the coarser models were used to perform history matching studies using the Ensemble based reservoir tool `ERT `_, via a :doc:`configuration file <./configuration_file>`. The current development of **pycopm** focuses on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files @@ -32,16 +32,20 @@ The current implementation supports the following executable with the argument o where --i The base name of the :doc:`configuration file <./configuration_file>` or the name of the deck, e.g., `DROGON.DATA`, (`input.txt` by default). --o The base name of the :doc:`output folder <./output_folder>` ('.'' by default, i.e., the folder where pycopm is executed). --f OPM Flow full path to executable or just `flow` (`flow` by default). --c Level of coarsening in the x, y, and z dir (`2,2,2` by default). --a Use `min`, `max`, or `mode` to scale the actnum, e.g., min makes the new coarser cell inactive it at least one cell is inactive, while max makes it active it at least one cell is active (`max` by default). --j Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults ('' by default, i.e., nothing corrected; if need it, try with values of the order of 1). --x Vector of x-coarsening, e.g., if the grid has 6 cells in the x direction, then `0,2,0,2,0,2,0` would generate a coarser model with 3 cells, while `0,2,2,2,2,2,0` would generate a coarser model with 1 cell, i.e., 0 keeps the pilars while 2 removes them ('' by default), --y Vector of y-coarsening, see the description for -x ('' by default). --z Vector of z-coarsening, see the description for -x ('' by default). --e Use `utf8` or `ISO-8859-1` encoding to read the deck (`ISO-8859-1` by default). --p Add the removed pore volume to the closest coarser cells (`0` by default, `1` to enable). --n Use `min`, `max`, or `mode` to scale satnum, fipnum, pvtnum, eqlnum, imbnum, and multnum (`mode` by default). --s Use `min`, `max`, or `mean` to scale permx, permy, permz, and poro ('' by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the porosity). \ No newline at end of file +-i The base name of the :doc:`configuration file <./configuration_file>` or the name of the deck, e.g., `DROGON.DATA`, (`input.txt` by default). +-o The base name of the :doc:`output folder <./output_folder>` ('.'' by default, i.e., the folder where pycopm is executed). +-f OPM Flow full path to executable or just `flow` (`flow` by default). +-c Level of coarsening in the x, y, and z dir (`2,2,2` by default; either use this flag or the -x, -y, and -z ones). +-x Vector of x-coarsening, e.g., if the grid has 6 cells in the x direction, then `0,2,0,2,0,2,0` would generate a coarser model with 3 cells, while `0,2,2,2,2,2,0` would generate a coarser model with 1 cell, i.e., 0 keeps the pilars while 2 removes them ('' by default), +-y Vector of y-coarsening, see the description for -x ('' by default). +-z Vector of z-coarsening, see the description for -x ('' by default). +-a Use `min`, `max`, or `mode` to scale the actnum, e.g., min makes the new coarser cell inactive if at least one cell is inactive, while max makes it active it at least one cell is active (`mode` by default). +-n Use `min`, `max`, or `mode` to scale endnum, eqlnum, fipnum, fluxnum, imbnum, miscnum, multnum, pvtnum, rocknum, and satnum (`mode` by default). +-s Use `min`, `max`, or `mean` to scale permx, permy, permz, poro, swatinit, and all mult(-)xyz ('' by default, i.e., using the arithmetic average for permx/permy, harmonic average for permz, and the mean for the rest). +-p Add the removed pore volume to the closest coarser cells (`0` by default, `1` to enable). +-j Tuning parameter to avoid creation of neighbouring connections in the coarser model where there are discontinuities between cells along the z direction, e.g., around faults ('' by default, i.e., nothing corrected; if need it, try with values of the order of 1). +-m Execute a dry run on the input deck to generate the static properties ('prep'), generate only the coarse files ('deck'), only exectute a dry run on the generated coarse model ('dry'), 'prep_deck', 'deck_dry', or do all ('all') (`prep_deck` by default). +-w Name of the generated deck ('' by default, i.e., the name of the input deck plus _PYCOPM.DATA). +-l Added text before each generated .INC (`PYCOPM_` by default, i.e., the coarse porv is saved in PYCOPM_PORV.INC; set to '' to generate PORV.INC, PERMX.INC, etc). +-e Use `utf8` or `ISO-8859-1` encoding to read the deck (`ISO-8859-1` by default). +-ijk Given i,j,k indices in the input model, return the coarse i,j,k corresponding positions ('' by default; if not empty, e.g., 1,2,3 then the -m is set to deck and there will not be generation of coarse files, only the i,j,k coarse indices in the terminal). \ No newline at end of file diff --git a/docs/text/output_folder.rst b/docs/text/output_folder.rst index 5e04a73..da7515f 100644 --- a/docs/text/output_folder.rst +++ b/docs/text/output_folder.rst @@ -21,7 +21,7 @@ are generated in the postprocessing folder. The OPM simulation results can be vi Via an OPM Flow input deck -------------------------- -The current development of **pycopm** focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by only giving the OPM Flow input files. +The current development of **pycopm** focuces on only creating coarser models (i.e., all needed input files to run OPM Flow) by using the input deck. The following screenshot shows the input deck and generated files in the selected output folder (coarser for this example) after executing **pycopm** on the SPE10 model (see the `test_generic_deck.py `_) file. @@ -29,4 +29,10 @@ The following screenshot shows the input deck and generated files in the selecte .. figure:: figs/output_generic.png Then, after running **pycopm**, one could adapt the generated files with the coarser geological model in your -favourite history matching/optimization tool (e.g., `ERT `_, `PET `_, `everest `_). \ No newline at end of file +favourite history matching/optimization tool (e.g., `ERT `_, `PET `_, `everest `_). + +.. Note:: + For input decks that include other files without giving the full path (e.g., './include/summary...'), then we recommend + to use the default output folder (-o .), i.e., the generated deck and coarse files would be generated in the same location as + the input deck and no errors would appear for not finding the include files; otherwise, you might need to copy all needed folders + with the include files to the output folder or setting the correct path to the include files in the generated coarse deck. \ No newline at end of file diff --git a/src/pycopm/core/pycopm.py b/src/pycopm/core/pycopm.py index 90ac289..7bf44de 100644 --- a/src/pycopm/core/pycopm.py +++ b/src/pycopm/core/pycopm.py @@ -29,6 +29,10 @@ def pycopm(): dic["nhow"] = cmdargs["nhow"].strip() # Max, min, or mode for other nums dic["show"] = cmdargs["show"].strip() # Max, min, or mean for static props dic["jump"] = cmdargs["jump"].strip() # Tuning parameter to remove nnc + dic["write"] = cmdargs["write"].strip() # Name of the generated deck + dic["mode"] = cmdargs["mode"].strip() # What to run + dic["label"] = cmdargs["label"].strip() # Prefix to the generted inc files + dic["ijk"] = cmdargs["ijk"].strip() # ijk indices to map to the coarse model dic["encoding"] = cmdargs["encoding"].strip() dic["pvcorr"] = int(cmdargs["pvcorr"]) dic["cijk"] = "yes" @@ -122,30 +126,14 @@ def load_parser(): "-f", "--flow", default="flow", - help="OPM Flow path to executable or just 'flow' ('flow' by default)", + help="OPM Flow path to executable or just 'flow' ('flow' by default).", ) parser.add_argument( "-c", "--coarsening", default="2,2,2", - help="Level of coarsening in the x, y, and z dir ('2,2,2' by default)", - ) - parser.add_argument( - "-a", - "--how", - default="max", - help="Use 'min', 'max', or 'mode' to scale the actnum, e.g., min makes " - "the new coarser cell inactive it at least one cell is inactive, while " - " max makes it active it at least one cell is active ('max' by default)", - ) - parser.add_argument( - "-j", - "--jump", - default="", - help="Tuning parameter to avoid creation of neighbouring connections in " - "the coarser model where there are discontinuities between cells along " - "the z direction, e.g., around faults ('' by default, i.e., nothing " - "corrected; if need it, try with values of the order of 1)", + help="Level of coarsening in the x, y, and z dir ('2,2,2' by default; " + "either use this flag or the -x, -y, and -z ones).", ) parser.add_argument( "-x", @@ -154,46 +142,95 @@ def load_parser(): help="Vector of x-coarsening, e.g., if the grid has 6 cells in the x " "direction, then 0,2,0,2,0,2,0 would generate a coarser model with 3 " "cells, while 0,2,2,2,2,2,0 would generate a coarser model with 1 cell, " - "i.e., 0 keeps the pilars while 2 removes them ('' by default)", + "i.e., 0 keeps the pilars while 2 removes them ('' by default).", ) parser.add_argument( "-y", "--ycoar", default="", - help="Vector of y-coarsening, see the description for -x ('' by default)", + help="Vector of y-coarsening, see the description for -x ('' by default).", ) parser.add_argument( "-z", "--zcoar", default="", - help="Vector of z-coarsening, see the description for -x ('' by default)", + help="Vector of z-coarsening, see the description for -x ('' by default).", ) parser.add_argument( - "-e", - "--encoding", - default="ISO-8859-1", - help="Use 'utf8' or 'ISO-8859-1' encoding to read the deck ('ISO-8859-1' by default)", - ) - parser.add_argument( - "-p", - "--pvcorr", - default=0, - help="Add the removed pore volume to the closest coarser cells ('0' by default)", + "-a", + "--how", + default="mode", + help="Use 'min', 'max', or 'mode' to scale the actnum, e.g., min makes " + "the new coarser cell inactive if at least one cell is inactive, while " + " max makes it active it at least one cell is active ('mode' by default).", ) parser.add_argument( "-n", "--nhow", default="mode", - help="Use 'min', 'max', or 'mode' to scale satnum, fipnum, pvtnum, eqlnum, imbnum, and " - "multnum ('mode' by default)", + help="Use 'min', 'max', or 'mode' to scale endnum, eqlnum, fipnum, fluxnum, imbnum, " + "miscnum, multnum, pvtnum, rocknum, and satnum ('mode' by default).", ) parser.add_argument( "-s", "--show", default="", - help="Use 'min', 'max', or 'mean' to scale permx, permy, permz, and poro ('' by default," - " i.e., using the arithmetic average for permx/permy, harmonic average for permz, and " - "the mean for the porosity).", + help="Use 'min', 'max', or 'mean' to scale permx, permy, permz, poro, swatinit, and all " + "mult(-)xyz ('' by default, i.e., using the arithmetic average for permx/permy, harmonic" + " average for permz, and the mean for the rest).", + ) + parser.add_argument( + "-p", + "--pvcorr", + default=0, + help="Add the removed pore volume to the closest coarser cells ('0' by default).", + ) + parser.add_argument( + "-j", + "--jump", + default="", + help="Tuning parameter to avoid creation of neighbouring connections in " + "the coarser model where there are discontinuities between cells along " + "the z direction, e.g., around faults ('' by default, i.e., nothing " + "corrected; if need it, try with values of the order of 1).", + ) + parser.add_argument( + "-m", + "--mode", + default="prep_deck", + help="Execute a dry run on the input deck to generate the static properties ('prep'), " + "generate only the coarse files ('deck'), only exectute a dry run on the generated " + "coarse model ('dry'), 'prep_deck', 'deck_dry', or do all ('all') ('prep_deck' by " + "default).", + ) + parser.add_argument( + "-w", + "--write", + default="", + help="Name of the generated deck ('' by default, i.e., the name of the input deck plus " + "_PYCOPM.DATA).", + ) + parser.add_argument( + "-l", + "--label", + default="PYCOPM_", + help="Added text before each generated .INC ('PYCOPM_' by default, i.e., the coarse porv " + "is saved in PYCOPM_PORV.INC; set to '' to generate PORV.INC, PERMX.INC, etc).", + ) + parser.add_argument( + "-e", + "--encoding", + default="ISO-8859-1", + help="Use 'utf8' or 'ISO-8859-1' encoding to read the deck ('ISO-8859-1' by default).", + ) + parser.add_argument( + "-ijk", + "--ijk", + default="", + help="Given i,j,k indices in the input model, return the coarse i,j,k corresponding " + "positions ('' by default; if not empty, e.g., 1,2,3 then the -mode is set to deck and " + "there will not be generation of coarse files, only the i,j,k coarse indices in the " + "terminal).", ) return vars(parser.parse_known_args()[0]) diff --git a/src/pycopm/template_scripts/common/grid.mako b/src/pycopm/template_scripts/common/grid.mako index 7af126a..8507d8f 100644 --- a/src/pycopm/template_scripts/common/grid.mako +++ b/src/pycopm/template_scripts/common/grid.mako @@ -23,15 +23,6 @@ ${f"{dic['zc'][i] : .3f}"} / % if dic['field']=='generic': -INIT -INCLUDE -'PORO.INC' / -INCLUDE -'PERMX.INC' / -INCLUDE -'PERMY.INC' / -INCLUDE -'PERMZ.INC' / ACTNUM % for i in range(len(dic['actnum_c'])): ${f"{dic['actnum_c'][i]}"} diff --git a/src/pycopm/utils/generate_coarser_files.py b/src/pycopm/utils/generate_coarser_files.py index 7136d29..8be07aa 100644 --- a/src/pycopm/utils/generate_coarser_files.py +++ b/src/pycopm/utils/generate_coarser_files.py @@ -8,6 +8,7 @@ import os import csv +import sys import numpy as np from resdata.grid import Grid from resdata.resfile import ResdataFile @@ -26,82 +27,162 @@ def create_deck(dic): dic (dict): Modified global dictionary """ - dic["flags"] = "--parsing-strictness=low --enable-dry-run=true" - os.system(f"{dic['flow']} {dic['deck'].upper()}.DATA {dic['flags']} & wait\n") - - # Read the data - dic["field"] = "generic" - dic["props"] = ["poro", "permx", "permy", "permz"] - dic["regions"] = [] - dic["grids"] = [] - dic["grid"] = Grid(f"{dic['exe']}/" + dic["deck"] + ".EGRID") - dic["ini"] = ResdataFile(f"{dic['exe']}/" + dic["deck"] + ".INIT") - if dic["ini"].has_kw("SWATINIT"): - dic["props"] += ["swatinit"] - if dic["ini"].has_kw("MULTNUM"): - dic["grids"] += ["multnum"] - for name in ["satnum", "eqlnum", "fipnum", "pvtnum", "imbnum"]: - if dic["ini"].has_kw(name.upper()): - if max(dic["ini"].iget_kw(name.upper())[0]) > 1: - dic["regions"] += [name] - nc = dic["grid"].nx * dic["grid"].ny * dic["grid"].nz - dic["con"] = np.array([0 for _ in range(nc)]) - dic["porv"] = np.array(dic["ini"].iget_kw("PORV")[0]) - actnum = np.array([0 for _ in range(nc)]) - d_z = np.array([np.nan for _ in range(nc)]) - z_t = np.array([np.nan for _ in range(nc)]) - z_b = np.array([np.nan for _ in range(nc)]) - z_b_t = np.array([np.nan for _ in range(nc)]) - for name in dic["props"] + dic["regions"] + dic["grids"]: - dic[name] = 1.0 * np.ones(nc) * np.nan - n = 0 - zti = [2, 5, 8, 11] - zbi = [14, 17, 20, 23] - cxyz = dic["grid"].export_corners(dic["grid"].export_index()) - for cell in dic["grid"].cells(): - actnum[cell.global_index] = cell.active - z_t[cell.global_index] = min(cxyz[cell.global_index][i] for i in zti) - z_b[cell.global_index] = max(cxyz[cell.global_index][i] for i in zti) - tmp = max(cxyz[cell.global_index][i] for i in zbi) - z_b_t[cell.global_index] = tmp - z_t[cell.global_index] - if cell.active == 1: - d_z[cell.global_index] = dic["grid"].cell_dz(ijk=(cell.i, cell.j, cell.k)) - for name in dic["props"] + dic["regions"] + dic["grids"]: - dic[name][cell.global_index] = dic["ini"].iget_kw(name.upper())[0][n] - if not dic["show"]: - dic["permx"][cell.global_index] = ( - dic["ini"].iget_kw("PERMX")[0][n] * d_z[cell.global_index] + if dic["ijk"]: + dic["ijk"] = [int(val) for val in dic["ijk"].split(",")] + dic["mode"] = "deck" + if not dic["write"]: + dic["write"] = dic["deck"] + "_PYCOPM" + dic["flags"] = "--parsing-strictness=low --enable-dry-run=true --output-mode=none" + if dic["mode"] in ["prep", "prep_deck", "all"]: + os.system(f"cp {dic['deck']}.DATA {dic['deck']}_PREP_PYCOPM_DRYRUN.DATA") + print( + f"\nCloning {dic['deck']}.DATA to {dic['deck']}_PREP_PYCOPM_DRYRUN.DATA for" + " the intial dry run to generate the grid (.EGRID) and static (.INIT) " + "properties\n" + ) + os.system( + f"{dic['flow']} {dic['deck']}_PREP_PYCOPM_DRYRUN.DATA {dic['flags']} " + f"--output-dir={dic['fol']}" + ) + os.system(f"mv {dic['deck']}_PREP_PYCOPM_DRYRUN.DATA " + f"{dic['fol']}") + for name in [".INIT", ".EGRID"]: + files = f"{dic['fol']}/{dic['deck']}_PREP_PYCOPM_DRYRUN" + name + if not os.path.isfile(files): + if name == ".INIT": + print( + f"\nThe {files} is not found, try adding the keyword INIT in" + f" the GRID section in the original deck {dic['deck']}.DATA\n" + ) + else: + print( + f"\nThe {files} is not found, try removing the keyword GRIDFILE in" + f" the GRID section in the original deck {dic['deck']}.DATA\n" + ) + sys.exit() + print("\nThe dry run succeeded") + + if dic["mode"] in ["prep_deck", "deck", "deck_dry", "all"]: + dic["deck"] = f"{dic['fol']}/{dic['deck']}_PREP_PYCOPM_DRYRUN" + for name in [".INIT", ".EGRID"]: + files = dic["deck"] + name + if not os.path.isfile(files): + print( + f"\nThe {files} is not found, try running pycopm with -m prep_deck " + "and without -ijk" ) - dic["permy"][cell.global_index] = ( - dic["ini"].iget_kw("PERMY")[0][n] * d_z[cell.global_index] + sys.exit() + dic["field"] = "generic" + dic["props"] = ["poro", "permx", "permy", "permz"] + dic["base"] = dic["props"] + ["grid"] + dic["regions"] = [] + dic["grids"] = [] + dic["mults"] = [] + dic["special"] = [] + dic["grid"] = Grid(f"{dic['exe']}/" + dic["deck"] + ".EGRID") + dic["ini"] = ResdataFile(f"{dic['exe']}/" + dic["deck"] + ".INIT") + if not dic["ijk"]: + print("\nInitializing pycopm to generate the coarse files, please wait") + if dic["ini"].has_kw("SWATINIT"): + dic["props"] += ["swatinit"] + dic["special"] += ["swatinit"] + for name in ["multx", "multx-", "multy", "multy-", "multz", "multz-"]: + if dic["ini"].has_kw(name.upper()): + tmp = np.array(dic["ini"].iget_kw(name.upper())[0]) + if 0 < sum(tmp != 1): + dic["props"] += [name] + dic["mults"] += [name] + for name in ["multnum", "fluxnum"]: + if dic["ini"].has_kw(name.upper()): + if max(dic["ini"].iget_kw(name.upper())[0]) > 1: + dic["grids"] += [name] + for name in [ + "endnum", + "eqlnum", + "fipnum", + "imbnum", + "miscnum", + "pvtnum", + "rocknum", + "satnum", + ]: + if dic["ini"].has_kw(name.upper()): + if max(dic["ini"].iget_kw(name.upper())[0]) > 1: + dic["regions"] += [name] + nc = dic["grid"].nx * dic["grid"].ny * dic["grid"].nz + dic["con"] = np.array([0 for _ in range(nc)]) + dic["porv"] = np.array(dic["ini"].iget_kw("PORV")[0]) + actnum = np.array([0 for _ in range(nc)]) + d_z = np.array([np.nan for _ in range(nc)]) + z_t = np.array([np.nan for _ in range(nc)]) + z_b = np.array([np.nan for _ in range(nc)]) + z_b_t = np.array([np.nan for _ in range(nc)]) + for name in dic["props"] + dic["regions"] + dic["grids"]: + dic[name] = 1.0 * np.ones(nc) * np.nan + n = 0 + zti = [2, 5, 8, 11] + zbi = [14, 17, 20, 23] + cxyz = dic["grid"].export_corners(dic["grid"].export_index()) + for cell in dic["grid"].cells(): + actnum[cell.global_index] = cell.active + z_t[cell.global_index] = min(cxyz[cell.global_index][i] for i in zti) + z_b[cell.global_index] = max(cxyz[cell.global_index][i] for i in zti) + tmp = max(cxyz[cell.global_index][i] for i in zbi) + z_b_t[cell.global_index] = tmp - z_t[cell.global_index] + if cell.active == 1: + d_z[cell.global_index] = dic["grid"].cell_dz( + ijk=(cell.i, cell.j, cell.k) ) - if dic["ini"].iget_kw("PERMZ")[0][n] != 0: - dic["permz"][cell.global_index] = ( - d_z[cell.global_index] / dic["ini"].iget_kw("PERMZ")[0][n] + for name in dic["props"] + dic["regions"] + dic["grids"]: + dic[name][cell.global_index] = dic["ini"].iget_kw(name.upper())[0][ + n + ] + if not dic["show"]: + dic["permx"][cell.global_index] = ( + dic["ini"].iget_kw("PERMX")[0][n] * d_z[cell.global_index] ) - n += 1 + dic["permy"][cell.global_index] = ( + dic["ini"].iget_kw("PERMY")[0][n] * d_z[cell.global_index] + ) + if dic["ini"].iget_kw("PERMZ")[0][n] != 0: + dic["permz"][cell.global_index] = ( + d_z[cell.global_index] / dic["ini"].iget_kw("PERMZ")[0][n] + ) + n += 1 - # Coarsening - handle_clusters(dic) - map_ijk(dic) - clusmin, clusmax, rmv = map_properties(dic, actnum, d_z, z_t, z_b, z_b_t) - if dic["pvcorr"] == 1: - handle_pv(dic, clusmin, clusmax, rmv) - handle_cp_grid(dic) - write_grid(dic) - write_props(dic) - process_the_deck(dic) - with open( - f"{dic['exe']}/{dic['fol']}/{dic['deck'].upper()}_PYCOPM.DATA", - "w", - encoding="utf8", - ) as file: - for row in dic["lol"]: - file.write(row + "\n") - # os.chdir(dic["fol"]) - # os.system( - # f"{dic['flow']} {dic['deck'].upper()}_PYCOPM.DATA --enable-dry-run=1 & wait\n" - # ) + # Coarsening + handle_clusters(dic) + map_ijk(dic) + if dic["ijk"]: + print( + dic["ic"][dic["ijk"][0]], + dic["jc"][dic["ijk"][1]], + dic["kc"][dic["ijk"][2]], + ) + sys.exit() + clusmin, clusmax, rmv = map_properties(dic, actnum, d_z, z_t, z_b, z_b_t) + if dic["pvcorr"] == 1: + handle_pv(dic, clusmin, clusmax, rmv) + handle_cp_grid(dic) + write_grid(dic) + write_props(dic) + process_the_deck(dic) + with open( + f"{dic['exe']}/{dic['fol']}/{dic['write']}.DATA", + "w", + encoding="utf8", + ) as file: + for row in dic["lol"]: + file.write(row + "\n") + print( + f"\nThe generation of coarse files succeeded, see {dic['fol']}/" + f"{dic['write']}.DATA and {dic['fol']}/{dic['label']}*.INC" + ) + + if dic["mode"] in ["deck_dry", "dry", "all"]: + print("\nCall OPM Flow for a dry run of the coarse model\n") + os.chdir(dic["fol"]) + os.system(f"{dic['flow']} {dic['write']}.DATA {dic['flags']}") + print("\nThe dry run of the coarse model succeeded\n") def map_properties(dic, actnum, d_z, z_t, z_b, z_b_t): @@ -121,7 +202,7 @@ def map_properties(dic, actnum, d_z, z_t, z_b, z_b_t): """ clusmax = pd.Series(actnum).groupby(dic["con"]).max() freq = pd.Series(actnum).groupby(dic["con"]).sum() - dz_c = pd.Series(z_b_t).groupby(dic["con"]).max() + dz_c = pd.Series(z_b_t).groupby(dic["con"]).mean() h_tot = pd.Series(d_z).groupby(dic["con"]).sum() if dic["how"] == "min": clusmin = pd.Series(actnum).groupby(dic["con"]).min() @@ -184,21 +265,23 @@ def map_properties(dic, actnum, d_z, z_t, z_b, z_b_t): for name in dic["regions"] + dic["grids"]: if dic["nhow"] == "min": c_c = pd.Series(dic[name]).groupby(dic["con"]).min() + dic[f"{name}_c"] = [ + f"{int(val)}" if not np.isnan(val) else "0" for val in c_c + ] elif dic["nhow"] == "max": c_c = pd.Series(dic[name]).groupby(dic["con"]).max() + dic[f"{name}_c"] = [ + f"{int(val)}" if not np.isnan(val) else "0" for val in c_c + ] else: c_c = ( pd.Series(dic[name]) .groupby(dic["con"]) - .agg( - lambda x: ( - pd.Series.mode(x).iat[0] - if len(pd.Series.mode(x)) > 1 - else pd.Series.mode(x) - ) - ) + .agg(lambda x: list(pd.Series.mode(x))) ) - dic[f"{name}_c"] = [f"{int(val)}" if np.isscalar(val) else "0" for val in c_c] + dic[f"{name}_c"] = [ + f"{int(val[0])}" if len(val) > 0 else "0" for val in c_c + ] return clusmin, clusmax, rmv @@ -321,17 +404,7 @@ def write_grid(dic): dic["files"] = [f for f in os.listdir(f"{dic['exe']}") if f.endswith(".INC")] for file in dic["files"]: copy = True - for prop in [ - "PORO", - "PERM", - "TOPS", - "PHI", - "FIPNUM", - "SATNUM", - "NTG", - "GRID", - "PORV", - ]: + for prop in dic["props"] + dic["regions"] + dic["grids"] + ["porv"]: if prop in file: copy = False if copy: @@ -339,7 +412,9 @@ def write_grid(dic): var = {"dic": dic} mytemplate = Template(filename=f"{dic['pat']}/template_scripts/common/grid.mako") filledtemplate = mytemplate.render(**var) - with open(f"{dic['exe']}/{dic['fol']}/GRID.INC", "w", encoding="utf8") as f: + with open( + f"{dic['exe']}/{dic['fol']}/{dic['label']}GRID.INC", "w", encoding="utf8" + ) as f: f.write(filledtemplate) @@ -362,7 +437,7 @@ def write_props(dic): ) dic[f"{name}_c"].append("/") with open( - f"{dic['exe']}/{dic['fol']}/{name.upper()}.INC", + f"{dic['exe']}/{dic['fol']}/{dic['label']}{name.upper()}.INC", "w", encoding="utf8", ) as file: @@ -547,6 +622,8 @@ def process_the_deck(dic): dic["compdat"] = False dic["compsegs"] = False dic["mapaxes"] = False + dic["props"] = False + dic["oper"] = False dic["region"] = False dic["fault"] = False with open(dic["deck"] + ".DATA", "r", encoding=dic["encoding"]) as file: @@ -563,15 +640,88 @@ def process_the_deck(dic): continue if handle_grid_props(dic, nrwo): continue + if handle_props(dic, nrwo): + continue if handle_regions(dic, nrwo): continue if handle_wells(dic, nrwo): continue if handle_segmented_wells(dic, nrwo): continue + for case in dic["special"]: + if ( + case + "." in nrwo.lower() + or "." + case in nrwo.lower() + or "swinitial." in nrwo.lower() + ): + nrwo = f"{dic['label']}{case.upper()}.INC/" dic["lol"].append(nrwo) +def handle_props(dic, nrwo): + """ + Handle the props sections + + Args: + dic (dict): Global dictionary\n + nrwo (list): Splited row from the input deck + + Returns: + dic (dict): Modified global dictionary + + """ + if nrwo == "PROPS" and not dic["props"]: + dic["props"] = True + dic["lol"].append(nrwo + "\n") + return True + if dic["props"]: + if handle_oper(dic, nrwo): + return True + if nrwo in ["REGIONS", "SOLUTION"]: + dic["props"] = False + return False + + +def handle_oper(dic, nrwo): + """ + We also support operations + + Args: + dic (dict): Global dictionary\n + nrwo (list): Splited row from the input deck + + Returns: + dic (dict): Modified global dictionary + + """ + if nrwo in ["EQUALS", "COPY", "ADD", "MULTIPLY"]: + if not dic["props"] and nrwo == "COPY": + return False + dic["oper"] = True + dic["lol"].append(nrwo) + return True + if dic["oper"]: + edit = nrwo.split() + if edit: + if edit[0] == "/": + dic["oper"] = False + if len(edit) > 7: + if edit[0][:2] != "--": + if "PERM" in edit[0]: + edit[1] = "1" + edit[2] = str(dic["ic"][int(edit[2])]) + edit[3] = str(dic["ic"][int(edit[3])]) + edit[4] = str(dic["jc"][int(edit[4])]) + edit[5] = str(dic["jc"][int(edit[5])]) + edit[6] = str(dic["kc"][int(edit[6])]) + edit[7] = str(dic["kc"][int(edit[7])]) + dic["lol"].append(" ".join(edit)) + return True + if not dic["props"]: + dic["lol"].append(nrwo) + return False + + def handle_regions(dic, nrwo): """ Handle the regions sections @@ -593,7 +743,7 @@ def handle_regions(dic, nrwo): dic["region"] = False for name in dic["regions"]: dic["lol"].append("INCLUDE") - dic["lol"].append(f"'{name.upper()}.INC' /\n") + dic["lol"].append(f"'{dic['label']}{name.upper()}.INC' /\n") else: return True return False @@ -614,22 +764,23 @@ def handle_grid_props(dic, nrwo): if nrwo == "GRID" and not dic["removeg"]: dic["removeg"] = True dic["lol"].append(nrwo + "\n") - dic["lol"].append("INCLUDE") - dic["lol"].append("'GRID.INC' /\n") - for name in dic["grids"]: + dic["lol"].append("INIT") + for name in dic["base"] + dic["grids"] + dic["mults"]: dic["lol"].append("INCLUDE") - dic["lol"].append(f"'{name.upper()}.INC' /\n") + dic["lol"].append(f"'{dic['label']}{name.upper()}.INC' /\n") return True if dic["removeg"]: if handle_fault(dic, nrwo): return True if handle_mapaxes(dic, nrwo): return True + # if handle_oper(dic, nrwo): + # return True if nrwo == "PROPS": dic["removeg"] = False dic["lol"].append("EDIT\n") dic["lol"].append("INCLUDE") - dic["lol"].append("'PORV.INC' /\n") + dic["lol"].append(f"'{dic['label']}PORV.INC' /\n") else: return True return False @@ -647,9 +798,12 @@ def handle_mapaxes(dic, nrwo): dic (dict): Modified global dictionary """ - if nrwo == "MAPAXES": + if "MAPAXES" in nrwo: + edit = nrwo.split() + if edit[0] != "MAPAXES": + return False dic["mapaxes"] = True - dic["lol"].append(nrwo) + dic["lol"].append(edit[0]) return True if dic["mapaxes"]: edit = nrwo.split() diff --git a/tests/decks/HELLO_WORLD.DATA b/tests/decks/HELLO_WORLD.DATA new file mode 100644 index 0000000..c9547dd --- /dev/null +++ b/tests/decks/HELLO_WORLD.DATA @@ -0,0 +1,168 @@ +-- This reservoir simulation deck is made available under the Open Database +-- License: http://opendatacommons.org/licenses/odbl/1.0/. Any rights in +-- individual contents of the database are licensed under the Database Contents +-- License: http://opendatacommons.org/licenses/dbcl/1.0/ + +-- Copyright (C) 2024 NORCE +--------------------------------------------------------------------------- +RUNSPEC +--------------------------------------------------------------------------- +DIMENS +20 1 20 / + +EQLDIMS +/ + +TABDIMS +/ + +GAS +WATER +CO2STORE + +METRIC + +START +18 'JAN' 1991 / + +UNIFOUT +--------------------------------------------------------------------------- +GRID +--------------------------------------------------------------------------- +INIT + +DX +400*1 / + +DY +400*1 / + +DZ +400*1 / + +TOPS +20*0 / + +PORO +20*0.01 +20*0.02 +20*0.03 +20*0.04 +20*0.05 +20*0.06 +20*0.07 +20*0.08 +20*0.09 +20*0.10 +20*0.11 +20*0.12 +20*0.13 +20*0.14 +20*0.15 +20*0.16 +20*0.17 +20*0.18 +20*0.19 +20*0.20 +/ + +PERMX +20*100 +20*200 +20*300 +20*400 +20*500 +20*600 +20*700 +20*800 +20*900 +20*1000 +20*1100 +20*1200 +20*1300 +20*1400 +20*1500 +20*1600 +20*1700 +20*1800 +20*1900 +20*2000 +/ + +PERMY +400*1/ + +PERMZ +20*100 +20*200 +20*300 +20*400 +20*500 +20*600 +20*700 +20*800 +20*900 +20*1000 +20*1100 +20*1200 +20*1300 +20*1400 +20*1500 +20*1600 +20*1700 +20*1800 +20*1900 +20*2000 +/ + +EQUALS +PORO 0 6 10 1* 1* 6 10 / +PORO 0.08 8 8 1* 1* 8 8 / +/ +--------------------------------------------------------------------------- +PROPS +--------------------------------------------------------------------------- +SGWFN +0 0 1 0 +1 1 0 0 / +--------------------------------------------------------------------------- +REGIONS +--------------------------------------------------------------------------- +FIPNUM +20*1 +20*2 +20*3 +20*4 +20*5 +20*6 +20*7 +20*8 +20*9 +20*10 +20*11 +20*12 +20*13 +20*14 +20*15 +20*16 +20*17 +20*18 +20*19 +20*20 +/ +--------------------------------------------------------------------------- +SOLUTION +--------------------------------------------------------------------------- +EQUIL +0 1 0 0 0 0 1 1 0 / + +RPTRST +BASIC=2 / +--------------------------------------------------------------------------- +SCHEDULE +--------------------------------------------------------------------------- +RPTRST +BASIC=2 / + +TSTEP +1 / \ No newline at end of file diff --git a/tests/test_generic_deck.py b/tests/test_generic_deck.py index af4d468..47acde4 100644 --- a/tests/test_generic_deck.py +++ b/tests/test_generic_deck.py @@ -10,35 +10,74 @@ def test_generic_deck(): """pycopm application to coarser a geological model given an input deck""" cwd = os.getcwd() - os.chdir(f"{cwd}/tests") - os.system("mkdir generic_deck") - os.chdir(f"{cwd}/tests/generic_deck") - for name in ["PERM", "PHI", "TOPS"]: - subprocess.run( - [ - "curl", - "-o", - f"./SPE10MODEL2_{name}.INC", - "https://raw.githubusercontent.com/OPM/opm-data/master/spe10model2/" - + f"SPE10MODEL2_{name}.INC", - ], - check=True, - ) + os.chdir(f"{os.getcwd()}/tests/decks") subprocess.run( [ - "curl", + "pycopm", + "-i", + "HELLO_WORLD.DATA", "-o", - "./SPE10_MODEL2.DATA", - "https://raw.githubusercontent.com/OPM/opm-data/master/spe10model2/" - + "SPE10_MODEL2.DATA", + "coarser", + "-c", + "5,1,5", + "-m", + "prep", ], check=True, ) + assert os.path.exists( + f"{cwd}/tests/decks/coarser/HELLO_WORLD_PREP_PYCOPM_DRYRUN.INIT" + ) + assert os.path.exists( + f"{cwd}/tests/decks/coarser/HELLO_WORLD_PREP_PYCOPM_DRYRUN.EGRID" + ) + for ahow in ["max", "min", "mode"]: + for nhow in ["max", "min", "mode"]: + for show in ["max", "min", "mean"]: + subprocess.run( + [ + "pycopm", + "-i", + "HELLO_WORLD.DATA", + "-o", + "coarser", + "-c", + "5,1,5", + "-m", + "deck", + "-a", + ahow, + "-n", + nhow, + "-s", + show, + ], + check=True, + ) + assert os.path.exists( + f"{cwd}/tests/decks/coarser/HELLO_WORLD_PYCOPM.DATA" + ) + os.system(f"rm {cwd}/tests/decks/coarser/HELLO_WORLD_PYCOPM.DATA") subprocess.run( - ["pycopm", "-i", "SPE10_MODEL2.DATA", "-o", "coarser", "-c", "4,8,2"], + [ + "pycopm", + "-i", + "HELLO_WORLD.DATA", + "-o", + "coarser", + "-m", + "deck_dry", + "p", + "1", + "-n", + "mode", + "-x", + "0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0", + "-z", + "0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0", + ], check=True, ) - os.chdir(f"{cwd}/tests/generic_deck/coarser") - os.system("flow SPE10_MODEL2_PYCOPM.DATA --parsing-strictness=low & wait\n") - assert os.path.exists(f"{cwd}/tests/generic_deck/coarser/SPE10_MODEL2_PYCOPM.UNRST") + assert os.path.exists(f"{cwd}/tests/decks/coarser/HELLO_WORLD_PYCOPM.INIT") + assert os.path.exists(f"{cwd}/tests/decks/coarser/HELLO_WORLD_PYCOPM.EGRID") os.chdir(cwd)