This commit is contained in:
Magne Sjaastad 2017-04-24 21:53:45 +02:00
parent 7efe0a996a
commit c701750330
3618 changed files with 6410 additions and 171524 deletions

View File

@ -7,8 +7,8 @@ set(RESINSIGHT_INCREMENT_VERSION "flow.13")
# https://github.com/CRAVA/crava/tree/master/libs/nrlib
set(NRLIB_GITHUB_SHA "ba35d4359882f1c6f5e9dc30eb95fe52af50fd6f")
# https://github.com/Ensembles/ert
set(ERT_GITHUB_SHA "e2a5a9cc20705537d07822958d925e092a323367")
# https://github.com/Statoil/libecl
set(ERT_GITHUB_SHA "f39d2e7fd196350ab1db86bb1bd5a3faca72d75d")
# https://github.com/OPM/opm-flowdiagnostics
set(OPM_FLOWDIAGNOSTICS_SHA "a14dc4ba1302bcc1e0aeb35c5de6b4bd39bce98")

View File

@ -1,65 +1,38 @@
dist: trusty
sudo: false
language: c
matrix:
fast_finish: true
allow_failures:
- os: osx
include:
- os: osx
osx_image: xcode7.3
compiler: clang
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- ubuntu-toolchain-r-test
packages:
- liblapack-dev
- valgrind
- gcc-4.8
- g++-4.8
- clang
install:
- if [[ "$CC" == "gcc" ]]; then export CXX="g++-4.8"; fi
- export TRAVIS_PYTHON_VERSION="2.7"
# We do this conditionally because it saves us some downloading if the version is the same.
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda-latest-MacOSX-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
fi
else
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export CONDA_HOME="$HOME/miniconda"
- export PATH="$CONDA_HOME/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
- conda install pyqt=4 scipy=0.16.1 numpy pandas matplotlib
- liblapack-dev
- valgrind
- gcc-4.8
- g++-4.8
env:
global:
- ERT_SHOW_BACKTRACE=1
- ERT_SHOW_BACKTRACE=1
install:
- if [[ "$CC" == "gcc" ]]; then export CXX="g++-4.8"; fi
- wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh
- bash miniconda.sh -b -p $HOME/miniconda
- export CONDA_HOME="$HOME/miniconda"
- export PATH="$CONDA_HOME/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
- conda info -a # Useful for debugging any issues with conda
- conda install pylint numpy pandas
before_script:
- mkdir build
- cd build
- cmake -DBUILD_ERT=ON -DERT_BUILD_GUI=ON -DBUILD_TESTS=ON -DBUILD_APPLICATIONS=ON -DBUILD_PYTHON=ON -DERT_USE_OPENMP=ON -DERT_DOC=OFF -DERT_BUILD_CXX=ON ..
- mkdir build
- cd build
- cmake -DBUILD_TESTS=ON -DBUILD_PYTHON=ON -DERT_BUILD_CXX=ON -DBUILD_APPLICATIONS=ON ..
script:
- make
- ctest --output-on-failure
- make
- ctest --output-on-failure -E ert_util_ping

View File

@ -8,7 +8,7 @@ endif()
#-----------------------------------------------------------------
set( ERT_VERSION_MAJOR 2 ) # Remember to update release notes whenever
set( ERT_VERSION_MINOR 1 ) # you change the ERT_VERSION_MINOR or MAJOR
set( ERT_VERSION_MINOR 2 ) # you change the ERT_VERSION_MINOR or MAJOR
set( ERT_VERSION_MICRO git ) # with "new in Ert Version X.X.X"!
# If the micro version is not integer, that should be interpreted as a
@ -16,14 +16,12 @@ set( ERT_VERSION_MICRO git ) # with "new in Ert Version X.X.X"!
#-----------------------------------------------------------------
option( BUILD_ERT "Build the full ERT application - Linux only" OFF)
option( BUILD_TESTS "Should the tests be built" OFF)
option( BUILD_APPLICATIONS "Should we build small utility applications" OFF)
option( BUILD_ECL_SUMMARY "Build the commandline application ecl_summary" OFF)
option( BUILD_PYTHON "Run py_compile on the python wrappers" ON )
option( BUILD_SHARED_LIBS "Build shared libraries" ON )
option( INSTALL_ERT "Should anything be installed when issuing make install?" ON )
option( ERT_BUILD_GUI "Should the PyQt based GUI be compiled and installed" OFF)
option( ERT_USE_OPENMP "Use OpenMP" OFF )
option( ERT_DOC "Build ERT documantation" OFF)
option( ERT_BUILD_CXX "Build some CXX wrappers" ON)
@ -182,38 +180,6 @@ include_directories( ${PROJECT_SOURCE_DIR}/libecl_well/include )
add_subdirectory( libecl_well )
#-----------------------------------------------------------------
if (BUILD_ERT)
#-----------------------------------------------------------------
if (BUILD_TESTS)
option( ERT_LSF_SUBMIT_TEST "Build and run tests of LSF submit" OFF)
endif()
add_subdirectory( bin )
include(cmake/ert_module_name.cmake)
include_directories( ${PROJECT_SOURCE_DIR}/libconfig/include )
add_subdirectory( libconfig )
include_directories( ${PROJECT_SOURCE_DIR}/libsched/include )
add_subdirectory( libsched )
include_directories( ${PROJECT_SOURCE_DIR}/librms/include )
add_subdirectory( librms )
include_directories( ${PROJECT_SOURCE_DIR}/libanalysis/include )
add_subdirectory( libanalysis )
include_directories( ${PROJECT_SOURCE_DIR}/libjob_queue/include )
add_subdirectory( libjob_queue )
include_directories( ${PROJECT_SOURCE_DIR}/libenkf/include )
add_subdirectory( libenkf )
install(DIRECTORY ${PROJECT_SOURCE_DIR}/share DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
if (BUILD_PYTHON)
if (ERT_WINDOWS)
message(STATUS "Python is not supported on Windows")

341
ThirdParty/Ert/README vendored
View File

@ -1,341 +0,0 @@
Coming from OPM??
-----------------
ERT is a package for handling an ensemble of reservoir models, an
important part of that is beeing able to read and write the files from
standard reservoir applications; ert has quite extensive support for
reading and writing the result files from the ECLIPSE reservoir
simulator. The capabilities to read and write ECLIPSE result files is
used by the OPM simulator codes.
The ERT build system has many configuration options, but when
compiling for OPM you should be able to use the all defaults route:
git clone https://github.com/Ensembles/ert.git
cd ert
mkdir build
cd build
cmake ..
make
The OPM build system can find an ERT distribution in the sibling
location, i.e. if you have cloned ert beside the opm modules like:
ert/
opm-common/
opm-parser/
opm-material/
....
The opm build system will find the ert distribution in-place,
otherwise you should install ert with 'make install' and the normal
cmake machinery of the opm build system should find it.
------------------------------------------------------------------------
_________________________________
/ \
| ______ ______ _______ |
| | ____| | __ \ |__ __| |
| | |__ | |__) | | | |
| | __| | _ / | | |
| | |____ | | \ \ | | |
| |______| |_| \_\ |_| |
| |
| Ensemble based Reservoir Tool |
\_________________________________/
------------------------------------------------------------------------
1. ERT
2. ECLIPSE utilities.
3. Building ERT
3.1 CMake settings you might want to adjust
4. The code:
4.1 The different libraries
4.2 The general structure
4.3 Python wrappers
5. Tests
------------------------------------------------------------------------
1. ERT
ERT - Ensemble based Reservoir Tool is a tool for managing an ensemble
of reservoir models. The initial motivation for creating ERT was a as
tool to do assisted history matching with the Ensemble Kalman Filter
(EnKF). Very briefly, the process of using EnKF for history matching
can be summarized as:
1. Sample initial reservoir parameters from a (Gaussian) initial
distribution.
2. Simulate the ensemble of of reservoir forward in time through a
part of the historical period for which data is available.
3. Load the results, compare with the observed data, update the
parameters and the state of reservoir by filtering out the most
inacurate results, and restart the forward simulations.
This recipe is quite complex technically, and in particular involves
the ability to read and write input and output files from the
reservoir simulator (i.e. ECLIPSE in the case of ERT), run simulations
with arbitrary external programs, plotting data and so on. This
implies that a quite significant technical machinery must be in place
before the EnKF algorithm as such can be utilizied. This in particular
applies to real industry reservoir models, where typically
imperfections of all kinds flourish.
Despite the fact that the initial motivation for creating ERT was to
be able to use the EnKF algorithm for history matching, ERT is
currently more used with the Ensemble Smoother and also purely as a
workflow manager, i.e. herding a large collection of reservoir models
through the required simulations steps.
2. ECLIPSE Utilities
ERT has a quite large amount of code devoted to reading and writing
the ECLIPSE output files (grid/rft/restart/init/summary). In addition,
there is also reasonable support for reading and writing the grdecl
input files, but there is no general .DATA file parser. The ability to
read and write ECLIPSE output files is valuable in many reservoir
applications, and it is possible to only build and use the libecl
(with support libraries) library for working with ECLIPSE files. In
fact, the default build setup is to only build the ECLIPSE related
library and utilities. This part of the ERT distribution can also be
built on Windows with Visual Studio (albeit with maaaany warnings) and
with MinGW.
3. Building ERT
CMake is the build system for ERT. The top level CMakeLists.txt file
is located in the top level directory of the repository, and this
CMakeLists.txt file includes individual CMakeLists.txt files for the
different libraries.
Building with CMake is performed like this:
1. Create a build directory, this can in principle be anywhere in
the filesystem. One level above the toplevel source directory is
a practical choice.
2. Go to the build directory and invoke the command:
ccmake <path/to/directory/containing/CMakeLists.txt>
Go through several 'configure' steps with CMake and generate
native build files.
3. Exit ccmake and invoke the native build system, i.e. ordinarily
'make' on Linux.
4. Subsequent builds can be performed using just the native make
command, as in step 3.
3.1 CMake settings you might want to adjust
The main setting you should adjust is BUILD_ERT which is default to
OFF, i.e. by default only the ECLIPSE related utilities will be
built. The build system has numerous configurations checks; the
ECLIPSE utilities should build on Windows, but to build all of ERT you
will need a Linux (Posix) system.
4. The code
The code is mainly a collection of libraries written in C.
4.1 The different libraries
The provided libraries are:
libert_util: This library is a collection of utilities of various
sorts; if C++ had been chosen as implementation language, most of
these utilities could probably be replaced by standard C++ classes.
libgeometry: This is a very small geometry library; the main code
is a small implementantion of an alorithm to determine whether a
point is inside a polyhedron. The ECLIPSE library has some
geometry related code which should be moved here.
libwell: This library will load well information from an ECLIPSE
restart file. This is mainly for the purpose of visualization
of the existing wells, and can not be used to update or model
the well configuration.
libecl: This library will read and (partly) write the various
binary ECLIPSE files, including GRID/EGRID, summary, INIT,
restart and RFT files. There is also support for reading an
writing grdecl formatted files, but there is no support for
general parsing of the ECLIPSE input format.
----------------------------------------------------------------------------
librms: This is a library for reading and writing RMS Roff
files. It turns out that ECLIPSE file formats is by far the most
common external file format for RMS and that the ROFF support is
not essential for this reason.
libconfig: This library implements a parser for the ERT config file
format, this format is used in the main ERT configuration file,
and also in several small special-purpose configuration files used
by ERT. The config format parsed by this library was inspired by
the ECLIPSE format, in retrospect that was a mistake - it should
have been based on a standard format like xml.
To confuse things even further, the libconfig library implements
/two/ formats for configuration files -- the 'second format' is
implemented in the file conf.c, and only used as format for the
observations in ERT.
libplot: A *very* simple library for creating plots which only
satisfies the needs of ERT.
libanalysis: The EnKF algorithm is implemented in this library.
libjob_queue: This library implements a system to manage and run
simulations in the form of external programs. The library has a
queue manager, and a system with drivers which communicate with
the underlying system. Currently, the library has a LSF driver
to work with LSF, a LOCAL driver which starts simulations on the
current workstation and a RSH driver which submits jobs to a
'cluster' of workstation using ssh.
libenkf: This is the main functionality which is ERT specific; this
library is too large.
4.2 General structure
The code is written in C, but conventions give a 'scent of object
orientation'. Most of the code is uses the following conventions:
- Every file 'xxx' implements a data type 'xxx_type' - this naming
convention is quite strong.
- All the structure definitions are in the source files,
i.e. external scopes must access the data of a structure
through accessor functions.
- All functions which operate on a type 'xxx_type' take a pointer
to xxx_type as their first argument, the structure closely
resemble the 'self' argument used when implementing Python
classes.
- Memory management is manual; however there are some conventions:
* Functions allocating storage have _alloc_ as part of the name.
* For all functions xxx_alloc() which allocate memory, there
should be a matching xxx_free() function to discard the objects.
* Containers can optionally destroy their content if the content
is installed with a destructor.
- In libert_util/src/type_macros.h there is a macro based
'type-system' which is used to runtime check casts of (void *).
4.3 Python wrappers
Some of the code, in particular the ECLIPSE related functionality, has
been wrapped for usage in Python. Using these wrappers, it is quite
easy work with ECLIPSE files. The python wrappers are quite well
documented both in the directory python/docs and in the Python classes
themselves.
5. Tests
The ERT codebase has a small but increasing test coverage. The tests
are typically located in a per-library subdirectory tests/. The test
framework is based on ctest which basically works like this:
1. In the CMakeLists.txt file testing is enabled with
ENABLE_TESTING().
2. Tests are added with:
add_test( test_name test_executable arg1 arg2 arg3 ... )
If the executable exits with status 0 the test has passed,
otherwise it has failed. The executable run by the test can
typically be an executable built as part of the solution, but can
in principle be an arbitrary executable like a dedicated test
runner or e.g. the Python interpreter.
5.1 Testing of C code
The main part of the testing infrastructure are small C applications
which are added like this:
add_executable( test_exe test_source.c )
target_link_libraries( test_exe lib )
add_test( test_name ${EXECUTABLE_OUTPUT_PATH}/test_exe commandline_arg1 commandline_arg2 )
Where the first two lines create the test executable in the normal
way, and the last line adds it as a test.
5.2 Testing of Python Code
In python/test there are several files with Python tests, these files
are executable files and they are invoked directly from the command
line. A limited number of the tests have been integrated in the ctest
system.
5.3 Test names
The tests in the cmake build system follow the naming convention of
the library regarding the functionality which they are testing: For
example, all tests for the libecl library use a name starting with
'ecl' and all tests for the tests for the config library are prefixed
by 'config'. The ctest options -R and -E can be used to include and
exclude tests based on their name
ctest -R ecl # Run all tests containing the regular expression 'ecl'
ctest -E ecl # Run all tests NOT containing the regular expression 'ecl'
5.4 Test labels
Using the cmake set_property() function it is possible to assign
labels to the test, and the -L and -LE options to ctest can be used to
limit which tests to run. A test can only have one label; in the
current ctest setup different labels are combined into one composite
label with a ":" separator, e.g.
set_property( TEST test_xxx PROPERTY LABELS StatoilData:Python)
will set the 'StatoilData' and 'Python' properties on test_xxx. The
labels currently available in the ERT test setup are:
StatoilData: This implies that the test makes use of Statoil
internal data. If you are work for the Bergen office of Statoil,
you can read the the file test-data/README for instructions on
how to make this data available.
If you are not for Statoil in Bergen, you must pass the option:
"-EL StatoilData" to ctest to skip all the tests which require
Statoil internal data.
StatoilBuild: There is one python test which makes use of Statoil
internal configuration data, this test is labeled with
StatoilBuild. If you want to run this test, you must set the
cmake option ECL_LOCAL_TARGET to point to a file which contains
these local configuration settings, e.g. where the ECLIPSE binary
is installed.
Python: This label is used to indicate that the test uses Python.
LSF: This labels indicates that the test needs a working LSF
environment to run.
5.5 ctest examples
ctest -L Statoil # Run all tests labeled with Statoil - both
# StatoilData and StatoilBuild
ctest -EL "Statoil|LSF" # Exclude all tests labeled with Statoil or LSF.

301
ThirdParty/Ert/README.md vendored Normal file
View File

@ -0,0 +1,301 @@
# libecl [![Build Status](https://travis-ci.org/Statoil/libecl.svg?branch=master)](https://travis-ci.org/Statoil/libecl)
## Coming from OPM?
`libecl` is a package for handling an ensemble of reservoir models, an
important part of that is beeing able to read and write the files from
standard reservoir applications; `libecl` has quite extensive support for
reading and writing the result files from the ECLIPSE reservoir
simulator. The capabilities to read and write ECLIPSE result files is
used by the OPM simulator codes.
The `libecl` build system has many configuration options, but when
compiling for OPM you should be able to use the all defaults route:
```bash
git clone https://github.com/Statoil/libecl.git
cd libecl
mkdir build
cd build
cmake ..
make
```
The OPM build system can find an `libecl` distribution in the sibling
location, i.e. if you have cloned ert beside the opm modules like:
```
libecl/
opm-common/
opm-parser/
opm-material/
...
```
The opm build system will find the ert distribution in-place,
otherwise you should install ert with 'make install' and the normal
cmake machinery of the opm build system should find it.
```
------------------------------------------------------------------------
_________________________________
/ \
| ______ ______ _______ |
| | ____| | __ \ |__ __| |
| | |__ | |__) | | | |
| | __| | _ / | | |
| | |____ | | \ \ | | |
| |______| |_| \_\ |_| |
| |
| Ensemble based Reservoir Tool |
\_________________________________/
------------------------------------------------------------------------
```
1. `libecl`
2. ECLIPSE utilities.
3. Building `libecl`
1. CMake settings you might want to adjust
4. The code:
1. The different libraries
2. The general structure
3. Python wrappers
5. Tests
------------------------------------------------------------------------
## 1. `libecl`
`libecl` - Ensemble based Reservoir Tool is a tool for managing an ensemble
of reservoir models. The initial motivation for creating `libecl` was a as
tool to do assisted history matching with the Ensemble Kalman Filter
(EnKF). Very briefly, the process of using EnKF for history matching
can be summarized as:
1. Sample initial reservoir parameters from a (Gaussian) initial
distribution.
2. Simulate the ensemble of of reservoir forward in time through a
part of the historical period for which data is available.
3. Load the results, compare with the observed data, update the
parameters and the state of reservoir by filtering out the most
inacurate results, and restart the forward simulations.
This recipe is quite complex technically, and in particular involves
the ability to read and write input and output files from the
reservoir simulator (i.e. ECLIPSE in the case of `libecl`), run simulations
with arbitrary external programs, plotting data and so on. This
implies that a quite significant technical machinery must be in place
before the EnKF algorithm as such can be utilizied. This in particular
applies to real industry reservoir models, where typically
imperfections of all kinds flourish.
Despite the fact that the initial motivation for creating `libecl` was to
be able to use the EnKF algorithm for history matching, `libecl` is
currently more used with the Ensemble Smoother and also purely as a
workflow manager, i.e. herding a large collection of reservoir models
through the required simulations steps.
## 2. ECLIPSE Utilities
`libecl` has a quite large amount of code devoted to reading and writing
the ECLIPSE output files (grid/rft/restart/init/summary). In addition,
there is also reasonable support for reading and writing the grdecl
input files, but there is no general .DATA file parser. The ability to
read and write ECLIPSE output files is valuable in many reservoir
applications, and it is possible to only build and use the libecl
(with support libraries) library for working with ECLIPSE files. In
fact, the default build setup is to only build the ECLIPSE related
library and utilities. This part of the `libecl` distribution can also be
built on Windows with Visual Studio (albeit with maaaany warnings) and
with MinGW.
## 3. Building `libecl`
CMake is the build system for `libecl`. The top level CMakeLists.txt file
is located in the top level directory of the repository, and this
CMakeLists.txt file includes individual CMakeLists.txt files for the
different libraries.
Building with CMake is performed like this:
1. Create a build directory, this can in principle be anywhere in the
filesystem. One level above the toplevel source directory is a practical choice.
2. Go to the build directory and invoke the command:
```
ccmake <path/to/directory/containing/CMakeLists.txt>
```
Go through several 'configure' steps with CMake and generate native build files.
3. Exit ccmake and invoke the native build system, i.e. ordinarily 'make' on
Linux.
4. Subsequent builds can be performed using just the native make command, as in
step 3.
### 3.1 CMake settings you might want to adjust
The main setting you should adjust is `BUILD_ERT` which is default to
`OFF`, i.e. by default only the ECLIPSE related utilities will be
built. The build system has numerous configurations checks; the
ECLIPSE utilities should build on Windows, but to build all of `libecl` you
will need a Linux (Posix) system.
## 4. The code
The code is mainly a collection of libraries written in C.
### 4.1 The different libraries
The _provided libraries_ are:
* `libert_util`: This library is a collection of utilities of various sorts; if
C++ had been chosen as implementation language, most of these utilities could
probably be replaced by standard C++ classes.
* `libgeometry`: This is a very small geometry library; the main code is a small
implementantion of an alorithm to determine whether a point is inside a
polyhedron. The ECLIPSE library has some geometry related code which should be
moved here.
* `libwell`: This library will load well information from an ECLIPSE restart
file. This is mainly for the purpose of visualization of the existing wells,
and can not be used to update or model the well configuration.
* `libecl`: This library will read and (partly) write the various binary ECLIPSE
files, including `GRID/EGRID`, summary, `INIT`, restart and `RFT` files. There
is also support for reading an writing grdecl formatted files, but there is no
support for general parsing of the _ECLIPSE_ input format.
### 4.2 General structure
The code is written in C, but conventions give a 'scent of object
orientation'. Most of the code is uses the following conventions:
* Every file 'xxx' implements a data type 'xxx_type' - this naming convention is
quite strong.
* All the structure definitions are in the source files, i.e. external scopes
must access the data of a structure through accessor functions.
* All functions which operate on a type 'xxx_type' take a pointer to xxx_type as
their first argument, the structure closely resemble the 'self' argument used
when implementing Python classes.
* Memory management is manual; however there are some conventions:
* Functions allocating storage have _alloc_ as part of the name.
* For all functions xxx_alloc() which allocate memory, there
should be a matching xxx_free() function to discard the objects.
* Containers can optionally destroy their content if the content
is installed with a destructor.
* In `libert_util/src/type_macros.h` there is a macro based
'type-system' which is used to runtime check casts of (void *).
### 4.3 Python wrappers
Some of the code, in particular the ECLIPSE related functionality, has
been wrapped for usage in Python. Using these wrappers, it is quite
easy work with ECLIPSE files. The python wrappers are quite well
documented both in the directory python/docs and in the Python classes
themselves.
## 5. Tests
The `libecl` codebase has a small but increasing test coverage. The tests
are typically located in a per-library subdirectory tests/. The test
framework is based on ctest which basically works like this:
1. In the CMakeLists.txt file testing is enabled with `ENABLE_TESTING()`.
2. Tests are added with:
```python
add_test( test_name test_executable arg1 arg2 arg3 ... )
```
If the executable exits with status 0 the test has passed,
otherwise it has failed. The executable run by the test can
typically be an executable built as part of the solution, but can
in principle be an arbitrary executable like a dedicated test
runner or e.g. the Python interpreter.
### 5.1 Testing of C code
The main part of the testing infrastructure are small C applications
which are added like this:
```
add_executable( test_exe test_source.c )
target_link_libraries( test_exe lib )
add_test( test_name ${EXECUTABLE_OUTPUT_PATH}/test_exe commandline_arg1 commandline_arg2 )
```
Where the first two lines create the test executable in the normal
way, and the last line adds it as a test.
### 5.2 Testing of Python Code
In python/test there are several files with Python tests, these files
are executable files and they are invoked directly from the command
line. A limited number of the tests have been integrated in the ctest
system.
### 5.3 Test names
The tests in the cmake build system follow the naming convention of
the library regarding the functionality which they are testing: For
example, all tests for the libecl library use a name starting with
'ecl' and all tests for the tests for the config library are prefixed
by 'config'. The ctest options -R and -E can be used to include and
exclude tests based on their name
```
ctest -R ecl # Run all tests containing the regular expression 'ecl'
ctest -E ecl # Run all tests NOT containing the regular expression 'ecl'
```
### 5.4 Test labels
Using the cmake set_property() function it is possible to assign
labels to the test, and the -L and -LE options to ctest can be used to
limit which tests to run. A test can only have one label; in the
current ctest setup different labels are combined into one composite
label with a ":" separator, e.g.
```
set_property( TEST test_xxx PROPERTY LABELS StatoilData:Python)
```
will set the 'StatoilData' and 'Python' properties on test_xxx. The
labels currently available in the `libecl` test setup are:
StatoilData: This implies that the test makes use of Statoil
internal data. If you are work for the Bergen office of Statoil,
you can read the the file test-data/README for instructions on
how to make this data available.
If you are not for Statoil in Bergen, you must pass the option:
"-EL StatoilData" to ctest to skip all the tests which require
Statoil internal data.
StatoilBuild: There is one python test which makes use of Statoil
internal configuration data, this test is labeled with
StatoilBuild. If you want to run this test, you must set the
cmake option ECL_LOCAL_TARGET to point to a file which contains
these local configuration settings, e.g. where the ECLIPSE binary
is installed.
Python: This label is used to indicate that the test uses Python.
LSF: This labels indicates that the test needs a working LSF
environment to run.
### 5.5 ctest examples
```
ctest -L Statoil # Run all tests labeled with Statoil - both
# StatoilData and StatoilBuild
ctest -EL "Statoil|LSF" # Exclude all tests labeled with Statoil or LSF.
```

View File

@ -20,8 +20,8 @@ def compile_file(src_file , target_file):
os.makedirs( path )
try:
py_compile.compile( src_file , cfile = target_file , doraise = True)
except Exception,error:
sys.exit(1)
except Exception as error:
sys.exit(str(error))
target_path = sys.argv[-1]

View File

@ -9,7 +9,7 @@ import os.path
for file in sys.argv[1:]:
try:
py_compile.compile( file , doraise = True )
except Exception,error:
except Exception as error:
sys.exit("py_compile(%s) failed:%s" % (file , error))

View File

@ -24,7 +24,7 @@ for (root , dir_list , file_list) in os.walk( root_path ):
try:
print "Compiling: %s" % py_file
py_compile.compile( py_file , doraise = True )
except Exception,error:
except Exception as error:
sys.exit("py_compile(%s) failed:%s" % (py_file , error))

View File

@ -16,6 +16,8 @@ endif()
find_library( LAPACK_LIBRARY NAMES lapack)
if (LAPACK_LIBRARY)
set(ERT_HAVE_LAPACK ON)
else()
set(ERT_HAVE_LAPACK OFF)
endif()
#-----------------------------------------------------------------
@ -25,9 +27,13 @@ find_path( ZLIB_HEADER zlib.h /usr/include )
if (ZLIB_LIBRARY AND ZLIB_HEADER)
set( ERT_HAVE_ZLIB ON )
else()
message("ZLib not found - zlib support will not be included." )
if(NOT DEFINED ZLIB_LIBRARY)
message(STATUS "ZLib library not found - zlib support will not be included." )
endif()
if(NOT DEFINED ZLIB_HEADER)
message(STATUS "zlib.h not found - zlib support will not be included.")
endif()
endif()
#-----------------------------------------------------------------
try_compile( ERT_HAVE_ISFINITE ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/Tests/test_isfinite.c )
@ -70,5 +76,4 @@ endif()
find_program(PING_PATH NAMES ping)
if (PING_PATH)
set( ERT_HAVE_PING ON )
add_definitions( -DPING_CMD="${PING_PATH}" )
endif()
endif()

View File

@ -73,4 +73,8 @@ if (NOT HAVE_CXX_SHARED_PTR)
set( BUILD_CXX OFF )
endif()
if (HAVE_FORK AND HAVE_PTHREAD AND HAVE_EXECINFO AND HAVE_GETPWUID)
set( HAVE_UTIL_ABORT_INTERCEPT ON)
set( HAVE_BACKTRACE ON)
endif()

View File

@ -9,7 +9,7 @@ from ert.test import ExtendedTestCase
try:
from synthesizer import OilSimulator
except ImportError as e:
share_lib_path = os.path.join(ExtendedTestCase.findShareRoot(), "lib")
share_lib_path = ExtendedTestCase.createShareRoot("lib")
sys.path.insert(0, share_lib_path)
synthesizer_module = __import__("synthesizer")

View File

@ -1,172 +0,0 @@
.. toctree::
:maxdepth: 1
.. _prior_distributions:
Prior distributions avaliable in ERT
====================================
The :ref:`GEN_KW <gen_kw>` keyword is typically used in sensitivy
studies and as parameters which are updated with the Ensemble Smoother
in a model updating project. In your configuration file the
:ref:`GEN_KW <gen_kw>` keyword is configured as:
::
GEN_KW ID my_template.txt my_eclipse_include.txt my_priors.txt
The file ``my_priors.txt`` contains the names of the variables
you are considering, and specifies the distribution which should be
used for the initial sampling.
NORMAL
------
To set a normal (Gaussian) prior, use the keyword NORMAL. It takes two
arguments, a mean value and a standard deviation. Thus, the following
example will assign a normal prior with mean 0 and standard deviation
1 to the variable VAR1:
::
VAR1 NORMAL 0 1
LOGNORMAL
---------
A stochastic variable is log normally distributed if the logarithm of
the variable is normally distributed. In other words, if X is normally
distributed, then Y = exp(X) is log normally distributed.
A log normal prior is suited to model positive quanties with a heavy
tail (tendency to take large values). To set a log normal prior, use
the keyword LOGNORMAL. It takes two arguments, the mean and standard
deviation of the *logarithm* of the variable:
::
VAR2 LOGNORMAL 0
TRUNCATED_NORMAL
-----------------
This *TRUNCATED_NORMAL* distribution works as follows:
1. Draw random variable X ~ N(mu,std)
2. Clamp X to the interval [min, max]
This is **not** a proper truncated normal distribution; hence the
clamping to ``[min,max]` should be an exceptional event. To configure
this distribution for a situation with mean 1, standard deviation 0.25
and hard limits 0 and 10:
::
VAR3 TRUNCATED_NORMAL 1 0.25 0 10
UNIFORM
-------
A stochastic variable is uniformly distributed if has a constant
probability density on a closed interval. Thus, the uniform
distribution is completely characterized by it's minimum and maximum
value. To assign a uniform distribution to a variable, use the keyword
UNIFORM, which takes a minimum and a maximum value for a the
variable. Here is an example, which assigns a uniform distribution
between 0 and 1 to a variable ``VAR4``:
::
VAR4 UNIFORM 0 1
It can be shown that among all distributions bounded below by a and
above by b, the uniform distribution with parameters a and b has the
maximal entropy (contains the least information). Thus, the uniform
distribution should be your preferred prior distribution for robust
modeling of bounded variables.
LOGUNIF
-------
A stochastic variable is log uniformly distributed if it's logarithm
is uniformly distributed on the interval [a,b]. To assign a log
uniform distribution to a a variable, use the keyword LOGUNIF, which
takes a minimum and a maximum value for the output variable as
arguments. The example
::
VAR5 LOGUNIF 0.00001 1
will give values in the range [0.00001,1] - with considerably more
weight towards the lower limit. The log uniform distribution is useful
when modeling a bounded positive variable who has most of it's
probability weight towards one of the bounds.
CONST
-----
The keyword CONST is used to assign a Dirac distribution to a
variable, i.e. set it to a constant value. Here is an example of use:
::
CONST 1.0
DUNIF
-----
The keyword DUNIF is used to assign a discrete uniform distribution. It takes three arguments, the number bins, a minimum and maximum value. Here is an example which creates a discrete uniform distribution on [0,1] with 25 bins:
::
DUNIF 25 0 1
ERRF
-----
The ERRF keyword is used to define a prior resulting from applying the error function to a normally distributed variable with mean 0 and variance 1. The keyword takes four arguments:
::
ERRF MIN MAX SKEWNESS WIDTH
The arguments MIN and MAX sets the minimum and maximum value of the transform. Zero SKEWNESS results in a symmetric distribution, whereas negative SKEWNESS will shift the distribution towards the left and positive SKEWNESS will shift it towards the right. Letting WIDTH be larger than one will cause the distribution to be unimodal, whereas WIDTH less than one will create a bi-modal distribution.
DERRF
-----
The keyword DERRF is similar to ERRF, but will create a discrete output. DERRF takes 5 arguments:
::
DERRF NBINS MIN MAX SKEWNESS WIDTH
NBINS set the number of discrete values, and the other arguments have the same effect as in ERRF.
Priors and transformations
==========================
The Ensemble Smoother method, which ERT uses for updating of
parameters, works with normally distributed variables. So internally
in ERT the interplay between ``GEN_KW`` variables and updates is as
follows:
1. ERT samples a random variable ``x ~ N(0,1)`` - before outputing
to the forward model this is *transformed* to ``y ~ F(Y)`` where
the the distribution ``F(Y)`` is the correct prior distribution.
2. When the prior simulations are complete ERT calculates misfits
between simulated and observed values and *updates* the
parameters; hence the variables ``x`` now represent samples from
a posterior distribution which is Normal with mean and standard
deviation *different from (0,1)*.
The transformation prescribed by ``F(y)`` still "works" - but it no
longer maps to a distribution in the same family as initially
specified by the prior. A consequence of this is that the update
process can *not* give you a posterior with updated parameters in the
same distribution family as the Prior.

View File

@ -1,15 +0,0 @@
User documentation for ERT
==========================
Contents:
.. toctree::
:maxdepth: 1
tutorial/index
keywords/index
workflows/index
magic_strings/index
observations/index
distributions/index
localization/index

File diff suppressed because it is too large Load Diff

View File

@ -1,602 +0,0 @@
Keywords for the local configuration file
=========================================
General overview
----------------
To create a configuration for localization you must "program" your own
local config commands by writing a Python script, and invoking it from a workflow.
**Local config python script example:**
::
from ert.enkf import ErtScript
from ert.enkf import LocalConfig, LocalObsdata, LocalObsdataNode, LocalMinistep, LocalUpdateStep, LocalDataset, ActiveList
from ert.ecl import EclGrid, EclRegion, Ecl3DKW, EclFile, EclInitFile, EclKW, EclTypeEnum
class LocalConfigJob(ErtScript):
def run(self):
# This example can be used with the REEK data set from the ERT tutorial
# Get the ert object
ert = self.ert()
# Get local config object
local_config = ert.getLocalConfig()
# Reset internal local config structure. From now you need to specify what to localize
local_config.clear()
# There is only one update step
updatestep = local_config.getUpdatestep()
# A ministep
ministep = local_config.createMinistep("MINISTEP" )
# Add some dataset you want to localize here.
dataset_multflt = local_config.createDataset("DATASET_MULTFLT")
# Add some field and localize inside a box
data_poro = local_config.createDataset("DATA_PORO")
ecl_grid = local_config.getGrid()
ecl_region = EclRegion(ecl_grid, False)
ecl_region.select_box((0,0,0),(3,3,3))
data_poro.addField("PORO", ecl_region)
# Add some index from MULTFLT to the dataset
dataset_multflt.addNode("MULTFLT")
active_list = dataset_multflt.getActiveList("MULTFLT")
active_list.addActiveIndex(0)
# Add existing observations from WOPR:OP_1. Alternatively, use getObservations and filter the observations you want to use for this ministep.
obsdata_wopr = local_config.createObsdata("WOPR:OP_1_10")
for i in range(1,10):
obsdata_wopr.addNode("OBS"+str(i))
# Attach the created dataset and obsset to the ministep
ministep.attachDataset(dataset_multflt)
ministep.attachObsset(obsdata_wopr)
# Then attach the ministep to the update step
updatestep.attachMinistep(ministep)
# Write a .csv file for debugging. The generated file can be imported into Excel for better tabulation of the setup
local_config.writeSummaryFile("tmp/summary_local_config.csv")
=========================================================================================== ==============================================================================================================================================
ERT script function Purpose
=========================================================================================== ==============================================================================================================================================
:ref:`getObservations <all_obs>` Get the observations currently imported, use to filter the observations to localize
:ref:`getGrid <ert_grid>` Get the underlying grid use to define active cells in a field
:ref:`getUpdatestep <create_updatestep>` Creates and gets default updatestep
:ref:`createMinistep <create_ministep>` Creates ministep
:ref:`createDataset <create_dataset>` Creates dataset
:ref:`copyDataset <copy_dataset>` Deep copy of dataset
:ref:`createObsdata <create_obsset>` Creates observation set
:ref:`copyObsdata <copy_obsset>` Deep copy of observation set
:ref:`attachMinistep <attach_ministep>` Attaches ministep to update step
:ref:`attachDataset <attach_dataset>` Attaches dataset to mini step
:ref:`attachObsset <attach_obsset>` Attaches observation set to mini step
:ref:`addNode <add_data>` Adds data node to dataset
:ref:`del (data) <del_data>` Deletes observation node from dataset
:ref:`addNode, addNodeAndRange <add_obs>` Adds observation node to observation set for all times or in a given time range
:ref:`del (obs) <del_obs>` Deletes observation node from observation set
:ref:`clear <dataset_del_all_data>` Delete all the data keys from a dataset
:ref:`addActiveIndex (data) <active_list_add_data_index>` Adds several data indices to the list of active indices
:ref:`addActiveIndex (obs) <active_list_add_obs_index>` Adds several observation indices to the list of active indices
:ref:`addField <add_field>` Adds field node to dataset
:ref:`EclGrid, EclInitFile <load_file>` Loads eclipse file in restart format
:ref:`EclRegion <create_eclregion>` Creates a new region for use when defining active regions for fields
:ref:`select_active <eclregion_select_all>` Selects or deselects cells in a region
:ref:`select_equal <eclregion_select_value_equal>` Selects or deselects cells in a region equal to given value
:ref:`select_less <eclregion_select_value_less>` Selects or deselects cells in a region equal less than a given value
:ref:`select_more <eclregion_select_value_more>` Selects or deselects cells in a region equal greater than a given value
:ref:`select_box <eclregion_select_box>` Selects or deselects cells in a box
:ref:`select_islice, _jslice,_kslice <eclregion_select_slice>` Selects or deselects cells in a slice
:ref:`select_below_plane <eclregion_select_plane>` Selects or deselects cells in a half space defined by a plane
:ref:`select_inside_polygon <eclregion_select_in_polygon>` Selects or deselects cells in region inside polygon
:ref:`Example create polygon <create_polygon>` Creates a geo-polygon based on coordinate list
:ref:`Example load polygon <load_polygon>` Loads polygon in Irap RMS format from file
=========================================================================================== ==============================================================================================================================================
.. ###########################################################################################################
.. _create_updatestep:
.. topic:: getUpdatestep
| This function will create the default updatestep.
| Observe that you must get, otherwise it will not be able to do anything.
*Example:*
::
updatestep = local_config.getUpdatestep()
.. ###########################################################################################################
.. _all_obs:
.. topic:: getObservations
| This function will retrieve ERT's observations
*Example:*
::
all_obs = local_config.getObservations()
.. ###########################################################################################################
.. _ert_grid:
.. topic:: getGrid
| This function will retrieve ERT's grid
*Example:*
::
grid = local_config.getGrid()
.. ###########################################################################################################
.. _create_ministep:
.. topic:: createMinistep
| This function will create a new ministep with a given name and an optional analysis module. The default analysis module for this ministep is ERT's current analysis module.
| A given observation set can be attached to a given ministep with attachObsset.The ministep is then ready for adding data. Before the ministep can be used you must attach it to an updatestep with the attachMinistep command
*Example:*
::
ministep = local_config.createMinistep("MINISTEP")
*Example:*
::
analysis_config = ert.analysisConfig()
std_enkf_analysis_module = analysis_config.getModule("STD_ENKF")
ministep_using_std_enkf = local_config.createMinistep("MINISTEP", std_enkf_analysis_module)
.. ###########################################################################################################
.. _create_dataset:
.. topic:: createDataset
| This function will create a new dataset with a given name, i.e. a collection of enkf_nodes which should be updated together. Before you can actually use a dataset you must attach it to a ministep with the attachDataset command.
*Example:*
::
dataset_multflt = local_config.createDataset("DATASET_MULTFLT")
.. ###########################################################################################################
.. _copy_dataset:
.. topic:: copyDataset
| Will create a new local_obsset instance which is a copy of the
source dataset; this is a deep copy where also the lowest level active_list instances are copied, and can then subsequently be updated independently of each other.
*Example:*
::
dataset_multflt_copy = local_config.copyDataset("DATASET_MULTFLT","DATASET_MULTFLT_COPY")
.. ###########################################################################################################
.. _create_obsset:
.. topic:: createObsdata
| This function will create an observation set, i.e. a collection of observation keys which will be used as the observations in one ministep. Before the obsset can be used it must be attached to a ministep with the attachDataset command.
*Example:*
::
obsset_obs_well = local_config.createObsdata("OBS_WELL")
.. ###########################################################################################################
.. _copy_obsset:
.. topic:: copyObsdata
| Will create a new local_obsset instance which is a copy of the
source dataset; this is a deep copy where also the lowest level active_list instances are copied, and can then subsequently be updated independently of each other.
*Example:*
::
obsset_obs_well_copy = local_config.copyObsdata("OBS_WELL", "OBS_WELL_COPY")
.. ###########################################################################################################
.. _attach_ministep:
.. topic:: attachMinistep
| This function will attach the ministep to the default updatestep.
*Example:*
::
update_step.attachMinistep(ministep)
.. ###########################################################################################################
.. _attach_dataset:
.. topic:: attachDataset
| Will attach the given dataset to the ministep.
*Example:*
::
ministep.attachDataset(dataset_multflt)
.. ###########################################################################################################
.. _attach_obsset:
.. topic:: attachObsset
| Will attach the given obsset to the ministep.
*Example:*
::
ministep.attachObsset(obsset_obs_well)
.. ###########################################################################################################
.. _add_data:
.. topic:: addNode
| This function will add the data KEY as one enkf node which should be updated in this dataset. If you do not manipulate the KEY further with addActiveIndex, the KEY will be added as 'ALL_ACTIVE', i.e. all elements will be updated.
*Example:*
::
dataset_multflt.addNode("MULTFLT")
.. ###########################################################################################################
.. _del_data:
.. topic:: del (data)
| This function will delete the data 'KEY' from the dataset.
*Example:*
::
del dataset_multflt["MULTFLT"]
.. ###########################################################################################################
.. _add_obs:
.. topic:: addNode
| This function will install the observation 'OBS_KEY' as an observation for this obsset - similarly to the addNode function.
*Example:*
::
-- The obsset has a time range
obsset_obs_well.addNodeAndRange("WOPR:OBS_WELL", 0, 1)
-- All times are active
obsset_obs_well.addNode("WOPR:OBS_WELL")
.. ###########################################################################################################
.. _del_obs:
.. topic:: del (obs)
| This function will delete the obs 'OBS_KEY' from the obsset 'NAME_OF_OBSSET'.
*Example:*
::
del obsset_obs_well["WOPR:OBS_WELL"]
.. ###########################################################################################################
.. _dataset_del_all_data:
.. topic:: clear
| This function will delete all the data keys from the dataset.
*Example:*
::
dataset_multflt.clear()
.. ###########################################################################################################
.. _active_list_add_data_index:
.. topic:: addActiveIndex (data)
| This function will say that the data with name 'DATA_KEY' in dataset with name 'DATASTEP_NAME' should have the index 'INDEX' active.
*Example:*
::
active_list = dataset_multflt.getActiveList("MULTFLT")
active_list.addActiveIndex(0);
.. ###########################################################################################################
.. _active_list_add_obs_index:
.. topic:: addActiveIndex (obs)
| This function will say that the observation with name 'OBS_KEY' in obsset with name 'OBSSET_NAME' should have the index 'INDEX' active.
*Example:*
::
active_list = obsset_obs_well.getActiveList("WOPR:OBS_WELL")
active_list.addActiveIndex(0);
.. ###########################################################################################################
.. _add_field:
.. topic:: addField
| This function will install the node with name 'FIELD_NAME' in the dataset 'DATASET_NAME'. It will in addition select all the (currently) active cells in the region 'ECLREGION_NAME' as active for this field/ministep combination. The ADD_FIELD command is actually a shortcut of: ADD_DATA DATASET FIELD_NAME; followed by: ACTIVE_LIST_ADD_MANY_DATA_INDEX <All the indices from the region>
*Example:*
::
# Load Eclipse grid
ecl_grid = EclGrid("path/to/LOCAL.GRDECL")
with open("path/to/LOCAL.GRDECL","r") as fileH:
local_kw = Ecl3DKW.read_grdecl(ecl_grid, fileH, "LOCAL")
# Define Eclipse region
eclreg_poro = EclRegion(ecl_grid, False)
eclreg_poro.select_more(local_kw, 1)
# Create dataset and add field to dataset
data_poro = local_config.createDataset("DATA_PORO")
data_poro.addField("PORO", eclreg_poro)
.. ###########################################################################################################
.. _load_file:
.. topic:: EclGrid, EclInitFile
| This function will load an ECLIPSE file in restart format (i.e. restart file or INIT file), the keywords in this file can then subsequently be used in ECLREGION_SELECT_VALUE_XXX commands below. The 'KEY' argument is a string which will be used later when we refer to the content of this file.
*Example:*
::
# Load Eclipse grid and init file
ecl_grid = EclGrid("path/to/FULLMODEL.GRDECL")
refinit_file = EclInitFile(grid , "path/to/somefile.init")
.. ###########################################################################################################
.. _create_eclregion:
.. topic:: EclRegion
| This function will create a new region 'ECLREGION_NAME', which can subsequently be used when defining active regions for fields. The second argument, SELECT_ALL, is a boolean value. If this value is set to true the region will start with all cells selected, if set to false the region will start with no cells selected.
*Example:*
::
# Define Eclipse region
eclreg_poro = EclRegion(ecl_grid, False)
.. ###########################################################################################################
.. _eclregion_select_all:
.. topic:: select_active
| Will select all the cells in the region (or deselect if SELECT == FALSE).
*Example:*
::
eclreg_poro.select_active()
.. ###########################################################################################################
.. _eclregion_select_value_equal:
.. topic:: select_equal
| This function will compare an ecl_kw instance loaded from file with a user supplied value, and select (or deselect) all cells which match this value. It is assumed that the ECLIPSE keyword is an INTEGER keyword, for float comparisons use the ECLREGION_SELECT_VALUE_LESS and ECLREGION_SELECT_VALUE_MORE functions.
*Example:*
::
# Load Eclipse grid
ecl_grid = EclGrid("path/to/LOCAL.GRDECL")
with open("path/to/LOCAL.GRDECL","r") as fileH:
local_kw = Ecl3DKW.read_grdecl(ecl_grid, fileH, "LOCAL", ecl_type= EclTypeEnum.ECL_INT_TYPE)
# Define Eclipse region
eclreg_poro = EclRegion(ecl_grid, False)
eclreg_poro.select_equal(local_kw, 1)
print 'GRID LOADED%s' % ecl_grid
print ecl_grid.getDims()
print local_kw.header
.. ###########################################################################################################
.. _eclregion_select_value_less:
.. topic:: select_less
| This function will compare an ecl_kw instance loaded from disc with a numerical value, and select all cells which have numerical below the limiting value. The ecl_kw value should be a floating point value like e.g. PRESSURE or PORO. The arguments are just as for ECLREGION_SELECT_VALUE_EQUAL.
*Example:*
::
eclreg_poro.select_less(local_kw, 1)
.. ###########################################################################################################
.. _eclregion_select_value_more:
.. topic:: select_more
| This function will compare an ecl_kw instance loaded from disc with a numerical value, and select all cells which have numerical above the limiting value. The ecl_kw value should be a floating point value like e.g. PRESSURE or PORO. The arguments are just as for ECLREGION_SELECT_VALUE_EQUAL.
*Example:*
::
eclreg_poro.select_more(local_kw, 1)
.. ###########################################################################################################
.. _eclregion_select_box:
.. topic:: select_box
| This function will select (or deselect) all the cells in the box defined by the six coordinates i1 i2 j1 j2 k1 k2. The coordinates are inclusive, and the counting starts at 1.
*Example:*
::
eclreg_poro.select_box((0,2,4),(1,3,5))
.. ###########################################################################################################
.. _eclregion_select_slice:
.. topic:: select_islice, _jslice,_kslice
| This function will select a slice in the direction given by 'dir', which can 'x', 'y' or 'z'. Depending on the value of 'dir' the numbers n1 and n2 are interpreted as (i1 i2), (j1 j2) or (k1 k2) respectively. The numbers n1 and n2 are inclusice and the counting starts at 1. It is OK to use very high/low values to imply "the rest of the cells" in one direction.
*Example:*
::
eclreg_poro.select_kslice(2,3)
.. ###########################################################################################################
.. _eclregion_select_plane:
.. topic:: select_below_plane
| Will select all points which have positive (sign > 0) distance to the plane defined by normal vector n = (nx,ny,nz) and point p = (px,py,pz). If sign < 0 all cells with negative distance to plane will be selected.
*Example:*
::
eclreg_poro.select_below_plane((1,1,1),(0,0,0))
.. ###########################################################################################################
.. _eclregion_select_in_polygon:
.. topic:: select_inside_polygon
| Well select all the points which are inside the polygon with name 'POLYGON_NAME'. The polygon should have been created with command CREATE_POLYGON or loaded with command 'LOAD_POLYGON' first.
*Example:*
::
polygon = [(0,0) , (0,1) , (1,0)]
eclreg_poro.select_inside_polygon(polygon)
.. ###########################################################################################################
.. _create_polygon:
.. topic:: Example create polygon
| Will create a geo_polygon instance based on the coordinate list: (x1,y1), (x2,y2), (x3,y3), ... The polygon should not be explicitly closed - i.e. you should in general have (x1,y1) != (xn,yn). The polygon will be stored under the name 'POLYGON_NAME' - which should later be used when referring to the polygon in region select operations.
*Example:*
::
polygon = [(0,0) , (0,1) , (1,0)]
.. ###########################################################################################################
.. _load_polygon:
.. topic:: Example load polygon
| Will load a polygon instance from the file 'FILENAME' - the file should be in irap RMS format. The polygon will be stored under the name 'POLYGON_NAME' which can then later be used to refer to the polygon for e.g. select operations.
*Example:*
::
polygon = []
with open("polygon.ply","r") as fileH:
for line in fileH.readlines():
tmp = line.split()
polygon.append( (float(tmp[0]) , float(tmp[1])))

View File

@ -1,30 +0,0 @@
.. _ert_magic_strings_full_doc:
Magic Strings
===================================
Magic strings are special keywords that can be used in configuration files and templates which have special meanings.
ERT Config
----------
These magic strings are available in the ERT config file.
**<CONFIG_FILE>**
Inserts the config file name with extension into the config file.
::
ENSPATH storage/<CONFIG_FILE>/ensemble
If the config file is named *config.ert* then the resulting storage path will be:
::
storage/config.ert/ensemble
**<CONFIG_FILE_BASE>**
Same as <CONFIG_FILE> but inserts the config file name without the extension into the config file.

View File

@ -1,463 +0,0 @@
Configuring observations for ERT
================================
General overview
----------------
When using ERT to condition on dynamic data, it is necessary to
specify which data to condition on. In particular, for a given piece
of data to condition on, the ERT application needs to know:
- The actual measured value of the data.
- The uncertainty of the measured data.
- The time of measurement.
- How to simulate a response of the data given a parametrized ECLIPSE model.
To provide this observation to ERT, an observation file must be
created. The observation file is a plain text file, and is in essence
built around for different classes of observations and has an
associated keyword for each class:
- Well or group rates from an existing ECLIPSE reference case: The
HISTORY_OBSERVATION keyword.
- Well logs, RFTS and PLTs: The BLOCK_OBSERVATION keyword.
- Separator tests, region pressures, etc.: The SUMMARY_OBSERVATION
keyword.
- Exotic observations (e.g. data from 4D seismic): The
GENERAL_OBSERVATION keyword.
The HISTORY_OBSERVATION keyword
-------------------------------
The keyword HISTORY_OBSERVATION is used to condition on observations
from the WCONHIST and WCONINJH keywords in schedule file provided to
the enkf project (or alternatively an ECLIPSE summary file if you have
changed the HISTORY_SOURCE keyword in the enkf project). The keyword
is typically used to condition on production and injection rates for
groups and wells, as well as bottom hole and tubing head pressures. An
observation entered with the HISTORY_OBSERVATION keyword will be
active at all report steps where data for the observation can be
found.
In it's simplest form, a history observation is created as follows::
HISTORY_OBSERVATION WOPR:P1;
This will condition on WOPR in well P1 using a default observation
error. The default observation error is a relative error of 10% to the
measurement with a minimum error of 0.10. See below on how explicitly
set the error.
In general, to condition on variable VAR in well or group WGNAME, one
uses::
HISTORY_OBSERVATION VAR:WGNAME;
Note that there must be a colon ":" between VAR and WGNAME and that
the statement shall end with a semi-colon ";". Thus, to condition on
WOPR, WWCT and WGOR in well C-17, and for the GOPR for the whole
field, one would add the following to the observation configuration::
HISTORY_OBSERVATION WOPR:C-17;
HISTORY_OBSERVATION WWCT:C-17;
HISTORY_OBSERVATION WGOR:C-17;
HISTORY_OBSERVATION GOPR:FIELD;
By default, the observation error is set to 10% of the observed value,
with a minimum of 0.10. It can be changed as follows::
HISTORY_OBSERVATION GOPR:FIELD
{
ERROR = 1000;
ERROR_MODE = ABS;
};
This will set the observation error to 1000 for all observations of
GOPR:FIELD. Note that both the items ERROR and ERROR_MODE as well as
the whole definition shall end with a semi-colon.
The item ERROR_MODE can take three different values: ABS, REL or
RELMIN. If set to REL, all observation errors will be set to the
observed values multiplied by ERROR. Thus, the following will
condition on water injection rate for the whole field with 20%
observation uncertainity::
HISTORY_OBSERVATION GWIR:FIELD
{
ERROR = 0.20;
ERROR_MODE = REL;
};
If you do not want the observation error to drop below a given
threshold, say 100, you can use RELMIN and the keyword ERROR_MIN::
HISTORY_OBSERVATION GWIR:FIELD
{
ERROR = 0.20;
ERROR_MODE = RELMIN;
ERROR_MIN = 100;
};
Note that the configuration parser does not threat carriage return
different from space. Thus, the following statement is equivalent to
the previous::
HISTORY_OBSERVATION GWIR:FIELD { ERROR = 0.20; ERROR_MODE = RELMIN; ERROR_MIN = 100; };
Also note that the special keyword include can be used to read an
external file. This can be very useful if you want to change the
standard configuration for a lot of observations in one go. For
example, consider the following code::
HISTORY_OBSERVATION WOPR:P1 { include "hist_obs_wells.txt"; };
HISTORY_OBSERVATION WOPR:P2 { include "hist_obs_wells.txt"; };
HISTORY_OBSERVATION WOPR:P3 { include "hist_obs_wells.txt"; };
HISTORY_OBSERVATION WOPR:P4 { include "hist_obs_wells.txt"; };
HISTORY_OBSERVATION WOPR:P5 { include "hist_obs_wells.txt"; };
Where the contents of the file hist_obs_wells.txt may be something
like::
ERROR_MODE = RELMIN;
ERROR = 0.25;
ERROR_MIN = 100;
In this case, changing the file hist_obs_wells.txt will affect all of
the observations.
Note that the keyword include can be used anywhere in the
configuration file. However, nested inclusion (use of include in a
file that has already been included with include) is not allowed.
By default, an observation entered with the HISTORY_OBSERVATION
keyword will get the observed values, i.e. the 'true' values, from the
WCONHIST and WCONINJH keywords in the schedule file provided to the
ERT project. However it also possible to get the observed values from
a reference case. In that case you must set set HISTORY_SOURCE
variable in the ERT configuration file, see Creating a configuration
file for ERT.
To change the observation error for a HISTORY_OBSERVATION for one or
more segments of the historic period, you can use the SEGMENT
keyword. For example::
HISTORY_OBSERVATION GWIR:FIELD
{
ERROR = 0.20;
ERROR_MODE = RELMIN;
ERROR_MIN = 100;
SEGMENT FIRST_YEAR
{
START = 0;
STOP = 10;
ERROR = 0.50;
ERROR_MODE = REL;
};
SEGMENT SECOND_YEAR
{
START = 11;
STOP = 20;
ERRROR = 1000;
ERROR_MODE = ABS;
};
};
The items START and STOP sets the start and stop of the segment in
terms of ECLIPSE restart steps. The keywords ERROR, ERROR_MODE and
ERROR_MIN behaves like before. If the segments overlap, they are
computed in alphabetical order. Error covariance for "merged" updates
When merging the historical observations from several report steps
together in one update the different steps are not independent, and it
is beneficial to use a error covariance matrix, by using the keywords
AUTO_CORRF and AUTO_CORRF_PARAM ERT will automatically estimate a
error-covariance matrix based on the auto correlation function
specified by the AUTO_CORRF keyword, with the parameter given by the
AUTO_CORRF_PARAM parameter (i.e. the auto correlation length). The
currently available auto correlation functions are:
EXP ~ exp(-x)
GAUSS ~ exp(-x*x/2)
where the parameter x is given as:
x = (t2 - t1) / AUTO_CORRF_PARAM
The SUMMARY_OBSERVATION keyword
-------------------------------
The keyword SUMMARY_OBSERVATION can be used to condition on any
observation whos simulated value is written to the ECLIPSE summary
file, e.g. well rates, region properties, group and field rates etc. A
quite typical usage of SUMMARY_OBSERVATION is to condition on the
results of a separator test.
Note: Although it is possible to condition on well and group rates
with SUMMARY_OBSERVATION, it is usually easier to use
HISTORY_OBSERVATION for this.
In order to create a summary observation, four pieces of information
are needed: The observed value, the observation error, the time of
observation and a summary key. A typical summary observation is
created as follows::
SUMMARY_OBSERVATION SEP_TEST_2005
{
VALUE = 100;
ERROR = 5;
DATE = 21/08/2005;
KEY = GOPR:BRENT;
};
This will create an observation of group oil production for the brent
group on 21th of august 2005. The observed value was 100 with a
standard deviation of 5. The name SEP_TEST_2005 will be used as a
label for the observation within the ERT and must be unique.
Similarly to the name of a HISTORY_OBSERVATION, the item KEY in a
SUMMARY_OBSERVATION is used to look up the simulated value from the
summary file. And again, as when declaring a HISTORY_OBSERVATION, to
condition on VAR in well, group or region WGRNAME, one uses::
KEY = VAR:WGRNAME;
For example, to condition on RPPW in region 8, one uses::
KEY = RPPW:8;
It is also possible to give the observation time as a restart number
using the RESTART item or as time in days from simulation start using
the DAYS item. Here are two examples::
-- Giving the observation time in terms of restart number.
SUMMARY_OBSERVATION SEP_TEST_2005
{
VALUE = 100;
ERROR = 5;
RESTART = 42;
KEY = GOPR:BRENT;
};
-- Giving the observation time in terms of days
-- from simulation start.
SUMMARY_OBSERVATION SEP_TEST_2008
{
VALUE = 213;
ERROR = 10;
DAYS = 911;
KEY = GOPR:NESS;
};
The BLOCK_OBSERVATION keyword
------------------------------
This is observations of variables in grid blocks/cells. The
observations can be of arbitrary ECLIPSE fields like PRESSURE
(typically for an RFT), PORO or PERM. A block observation is entered
with the BLOCK_OBSERVATION keyword. Here is an example of a typical
block observation::
BLOCK_OBSERVATION RFT_2006
{
FIELD = PRESSURE;
DATE = 22/10/2006;
OBS P1 { I = 1; J = 1; K = 1; VALUE = 100; ERROR = 5; };
OBS P2 { I = 2; J = 2; K = 1; VALUE = 101; ERROR = 5; };
OBS P3 { I = 2; J = 3; K = 1; VALUE = 102; ERROR = 5; };
};
This will condition on observations of the pressure in grid blocks
(1,1,1), (2,2,1) and (2,3,1) on the 22/10/2006.
By default the BLOCK_OBSERVATION requires that the specific field
which has been observed (e.g. PRESSURE in the example above) must have
been specified in main ERT configuration file using the FIELD keyword,
and ECLIPSE must be configured to produce a restart file for this
particular time. Alternatively it is possible to tell ERT to use the
summary vector as source of the data::
BLOCK_OBSERVATION RFT_2006
{
FIELD = PRESSURE;
DATE = 22/10/2006;
SOURCE = SUMMARY;
OBS P1 { I = 1; J = 1; K = 1; VALUE = 100; ERROR = 5; };
OBS P2 { I = 2; J = 2; K = 1; VALUE = 101; ERROR = 5; };
OBS P3 { I = 2; J = 3; K = 1; VALUE = 102; ERROR = 5; };
};
In this case the data will be loaded from the BPR vectors in the
summary file.
Note the use of the sub class OBS to specify the actUal observed
values, the observation errors and their grid location. Each OBS shall
have a unique key within the BLOCK_OBSERVATION instance, and is
required to have the items I, J, K, VALUE and ERROR. These are the
grid i,j and k indicies for the observation point, the observed value
and it's standard deviation.
As with a SUMMARY_OBSERVATION, the observation time can be given as
either a date, days since simulation start or restart number. The
respective keys for setting giving it as date, days or restart number
are DATE, DAYS and RESTART. Note that each BLOCK_OBSERVATION instance
must have an unique global name (RFT_2006 in the example above).
Block observations can often be quite long. Thus, it is often a good
idea to use the special keyword include in order to store the OBS
structures in a different file. This is done as follows::
BLOCK_OBSERVATION RFT_2006
{
FIELD = PRESSURE;
RESTART = 20;
include 'RFT_2006_OBS_DATA.txt';
};
Where the file RFT_2006_OBS_DATA.txt contains the OBS instances::
OBS P1 { I = 1; J = 1; K = 1; VALUE = 100; ERROR = 5; };
OBS P2 { I = 2; J = 2; K = 1; VALUE = 101; ERROR = 5; };
OBS P3 { I = 2; J = 3; K = 1; VALUE = 112; ERROR = 5; };
OBS P4 { I = 3; J = 3; K = 1; VALUE = 122; ERROR = 5; };
OBS P5 { I = 4; J = 3; K = 1; VALUE = 112; ERROR = 5; };
OBS P6 { I = 5; J = 3; K = 1; VALUE = 122; ERROR = 5; };
The GENERAL_OBSERVATION keyword
--------------------------------
The GENERAL_OBSERVATION keyword is used together with the GEN_DATA and
GEN_PARAM type. This pair of observation and data types are typically
used when you want to update something special which does not fit into
any of the predefined enkf types. The ERT application just treats
GENERAL_OBSERVATION (and also GEN_DATA) as a range of number with no
particular structure, this is very flexible, but of course also a bit
more complex to use::
GENERAL_OBSERVATION GEN_OBS1{
DATA = SOME_FIELD;
RESTART = 20;
OBS_FILE = some_file.txt;
};
This example a minimum GENERAL_OBSERVATION. The keyword DATA points to
the GEN_DATA instance this observation is 'observing', RESTART gives
the report step when this observation is active. OBS_FILE should be
the name of a file with observation values, and the corresponding
uncertainties. The file with observations should just be a plain text
file with numbers in it, observations and corresponding uncertainties
interleaved. An example of an OBS_FILE::
1.46 0.26
25.0 5.0
5.00 1.00
This OBS_FILE has three observations: 1.46 +/- 0.26, 25.0 +/- 5.0 and
5.00 +/- 1.00. In the example above it is assumed that the DATA
instance we are observing (i.e. comparing with) has the same number of
elements as the observation, i.e. three in this case. By using the
keywords INDEX_LIST or INDEX_FILE you can select the elements of the
GEN_DATA instance you are interested in. Consider for example::
GENERAL_OBSERVATION GEN_OBS1{
DATA = SOME_FIELD;
INDEX_LIST = 0,3,9;
RESTART = 20;
OBS_FILE = some_file.txt;
};
Here we use INDEX_LIST to indicate that we are interested in element
0,3 and 9 of the GEN_DATA instance::
GEN_DATA GEN_OBS1
======== ===========
1.56 <---------------------> 1.46 0.26
23.0 /--------------> 25.0 5.00
56.0 | /---------> 5.00 1.00
27.0 <------/ | ===========
0.2 |
1.56 |
1.78 |
6.78 |
9.00 |
4.50 <-----------/
========
In addition to INDEX_LIST it is possible to use INDEX_FILE which
should just point at an plain text file with indexes (without any ','
or anything). Finally, if your observation only has one value, you can
embed it in the config object with VALUE and ERROR.
Matching GEN_OBS and GEN_DATA
.............................
It is important to match up the GEN_OBS observations with the
corresponding GEN_DATA simulation data correctly. The GEN_DATA result
files must have an embedded '%d' to indicate the report step in them -
in the case of smoother based workflows the actual numerical value
here is not important. To ensure that GEN_OBS and corresponding
GEN_DATA values match up correctly only the RESTART method is allowed
for GEN_OBS when specifying the time. So consider a setup like this::
-- Config file:
GEN_DATA RFT_BH67 INPUT_FORMAT:ASCII RESULT_FILE:rft_BH67_%d REPORT_STEPS:20
... /|\ /|\
... | |
-- Observation file: | |
GENERAL_OBSERVATION GEN_OBS1{ +------------------/
DATA = RFT_BH67; |
RESTART = 20; <------------------------------------/
OBS_FILE = some_file.txt;
};
Here we see that the observation is active at report step 20, and we
expect the forward model to create a file rft_BH67_20 in each
realization directory. Error covariance
The optional keyword ERROR_COVAR can be used to point to an existing
file, containing an error covariance matrix. The file should contain
the elements of the matrix as formatted numbers; newline formatting is
allowed but not necessary. Since the matrix should by construction be
symmetric there is no difference between column-major and row-major
order! The covariance matrix
[ 1 0.75 -0.25]
C = [ 0.75 1.25 -0.50]
[-0.25 -0.50 0.85]
Can be represented by the file::
1
0.75
-0.25
0.75
1.25
-0.50
-0.25
-0.50
0.85
without newlines, or alternatively::
1 0.75 -0.25
0.75 1.25 -0.50
-0.25 -0.50 0.85
with newlines.

View File

@ -1,3 +0,0 @@
ERT Tutorial
============
Tutorial for ert

View File

@ -1,401 +0,0 @@
.. _built_in_workflow_jobs:
Built in workflow jobs
======================
ERT comes with a list of default workflow jobs which invoke internal
ERT functionality. The internal workflows include:
Jobs related to case management
-------------------------------
**SELECT_CASE**
The job SELECT_CASE can be used to change the currently selected
case. The SELECT_CASE job should be used as:
::
SELECT_CASE newCase
if the case newCase does not exist it will be created.
**CREATE_CASE**
The job CREATE_CASE can be used to create a new case without selecting
it. The CREATE_CASE job should be used as:
::
CREATE_CASE newCase
**INIT_CASE_FROM_EXISTING**
The job INIT_CASE_FROM_EXISTING can be used to initialize a case from
an existing case. The argument to the workflow should be the name of
the workflow you are initializing from; so to initialize the current
case from the existing case "oldCase":
::
INIT_CASE_FROM_EXISTING oldCase
By default the job will initialize the 'current case', but optionally
you can give the name of a second case which should be initialized. In
this example we will initialize "newCase" from "oldCase":
::
INIT_CASE_FROM_EXISTING oldCase newCase
When giving the name of a second case as target for the initialization
job the 'current' case will not be affected.
Jobs related to export
----------------------
**EXPORT_FIELD**
The EXPORT_FIELD workflow job exports field data to roff or grdecl
format dependent on the extension of the export file argument.The job
takes the following arguments:
#. Field to be exported
#. Filename for export file, must contain %d
#. Report_step
#. Realization range
The filename must contain a %d. This will be replaced with the
realization number.
The realization range parameter is optional. Default is all
realizations.
Example use of this job in a workflow:
::
EXPORT_FIELD PERMZ path_to_export/filename%d.grdecl 0 0,2
**EXPORT_FIELD_RMS_ROFF**
The EXPORT_FIELD_RMS_ROFF workflow job exports field data to roff
format. The job takes the following arguments:
#. Field to be exported
#. Filename for export file, must contain %d
#. Report_step
#. Realization range
The filename must contain a %d. This will be replaced with the
realization number.
The realization range parameter is optional. Default is all realizations.
Example uses of this job in a workflow:
::
EXPORT_FIELD_RMS_ROFF PERMZ path_to_export/filename%d.roff 0
EXPORT_FIELD_RMS_ROFF PERMX path_to_export/filename%d 0 0-5
**EXPORT_FIELD_ECL_GRDECL**
The EXPORT_FIELD_ECL_GRDECL workflow job exports field data to grdecl
format. The job takes the following arguments:
#. Field to be exported
#. Filename for export file, must contain %d
#. Report_step
#. Realization range
The filename must contain a %d. This will be replaced with the realization number.
The realization range parameter is optional. Default is all realizations.
Example uses of this job in a workflow:
::
EXPORT_FIELD_ECL_GRDECL PERMZ path_to_export/filename%d.grdecl 0
EXPORT_FIELD_ECL_GRDECL PERMX path_to_export/filename%d 0 0-5
**EXPORT_RUNPATH**
The EXPORT_RUNPATH workflow job writes the runpath file RUNPATH_FILE
for the selected case.
The job can have no arguments, or one can set a range of realizations
and a range of iterations as arguments.
Example uses of this job in a workflow:
::
EXPORT_RUNPATH
With no arguments, entries for all realizations are written to the
runpath file. If the runpath supports iterations, entries for all
realizations in iter0 are written to the runpath file.
::
EXPORT_RUNPATH 0-5 | *
A range of realizations and a range of iterations can be given. "|" is
used as a delimiter to separate realizations and iterations. "*" can
be used to select all realizations or iterations. In the example
above, entries for realizations 0-5 for all iterations are written to
the runpath file.
Jobs related to analysis update
-------------------------------
**ANALYSIS_UPDATE**
This job will perform a update and store the updated parameters as
initial parameters of a different case. The name of the source case
and the target case must be given as arguments:
::
ANALYSIS_UPDATE prior posterior
Will fetch prior parameters and simulated responses from the
case:`prior` and store updated parameters in the case:`posterior`. If
you have configured local updates that will be respected, otherwise
all available data will be used - and all parameters will be updated.
Jobs related to running simulations - including updates
-------------------------------------------------------
**RUN_SMOOTHER**
The RUN_SMOOTHER job will run a simulation and perform an update. The
job has one required argument - the name of a case where the updated
parameters are stored. Optionally the job can take a second boolean
argument, if the second argument is set to true the job will rerun
based on the updated parameters.
Run a simulation and an update. Store the updated parameters in the
specified case. This case is created if it does not exist:
::
RUN_SMOOTHER new_case
Run a simulation and an update. Store the updated parameters in the
specified case, then run a simulation on this case:
::
RUN_SMOOTHER new_case true
**RUN_SMOOTHER_WITH_ITER**
This is exactly like the RUN_SMOOTHER job, but it has an additional
first argumeent iter which can be used to control the iter number in
the RUNPATH. When using the RUN_SMOOTHER job the iter number will be
defaultetd to zero, and one in the optional rerun.
**ENSEMBLE_RUN**
The ENSEMBLE_RUN job will run a simulation, no update. The job take as
optional arguments a range and/or list of which realizations to run.
::
ENSEMBLE_RUN
::
ENSEMBLE_RUN 1-5, 8
**LOAD_RESULTS**
The LOAD_RESULTS loads result from simulation(s). The job takes as
optional arguments a range and/or list of which realizations to load
results from. If no realizations are specified, results for all
realizations are loaded.
::
LOAD_RESULTS
::
LOAD_RESULTS 1-5, 8
In the case of multi iteration jobs, like e.g. the integrated smoother
update, the LOAD_RESULTS job will load the results from iter==0. To
control which iteration is loaded from you can use the
LOAD_RESULTS_ITER job.
**LOAD_RESULTS_ITER**
The LOAD_RESULTS_ITER job is similar to the LOAD_RESULTS job, but it
takes an additional first argument which is the iteration number to
load from. This should be used when manually loading results from a
multi iteration workflow:
::
LOAD_RESULTS_ITER
::
LOAD_RESULTS_ITER 3 1-3, 8-10
Will load the realisations 1,2,3 and 8,9,10 from the fourth iteration
(counting starts at zero).
**MDA_ES**
This workflow job (plugin) is used to run the *Multiple Data
Assimilation Ensemble Smoother* :code:`MDA ES`. Only two arguments
are required to start the MDA ES process; target case format and
iteration weights. The weights implicitly indicate the number of
iterations and the normalized global standard deviation scaling
applied to the update step.
::
MDA_ES target_case_%d observations/obs.txt
This command will use the weights specified in the obs.txt file. This
file should have a single floating point number per line.
Alternatively the weights can be given as arguments as shown here.
::
MDA_ES target_case_%d 8,4,2,1
This command will use the normalized version of the weights 8,4,2,1
and run for four iterations. The prior will be in *target_case_0* and
the results from the last iteration will be in *target_case_4*.
**Note: the weights must be listed with no spaces and separated with
commas.**
If this is run as a plugin from Ertshell or the GUI a convenient user
interface can be shown.
Jobs for ranking realizations
-----------------------------
**OBSERVATION_RANKING**
The OBSERVATION_RANKING job will rank realizations based on the delta
between observed and simulated values for selected variables and time
steps. The data for selected variables and time steps are summarized
for both observed and simulated values, and then the simulated versus
observed delta is used for ranking the realizations in increasing
order. The job takes a name for the ranking as the first parameter,
then the time steps, a "|" character and then variables to rank on. If
no time steps and/or no variables are given, all time steps and
variables are taken into account.
Rank the realizations on observation/simulation delta value for all
WOPR data for time steps 0-20:
::
OBSERVATION_RANKING Ranking1 0-20 | WOPR:*
Rank the simulations on observation/simulation delta value for all
WOPR and WWCT data for time steps 1 and 10-50
::
OBSERVATION_RANKING Ranking2 1, 10-50 | WOPR:* WWCT:*
Rank the realizations on observation/simulation delta value for
WOPR:OP-1 data for all time steps
::
OBSERVATION_RANKING Ranking3 | WOPR:OP-1
**DATA_RANKING**
The DATA_RANKING job will rank realizations in increasing or
decreasing order on selected data value for a selected time step. The
job takes as parameters the name of the ranking, the data key to rank
on, increasing order and selected time steps. If no time step is
given, the default is the last timestep.
Rank the realizations on PORO:1,2,3 on time step 0 in decreasing order
::
DATA_RANKING Dataranking1 PORO:1,2,3 false 0
**EXPORT_RANKING**
The EXPORT_RANKING job exports ranking results to file. The job takes
two parameters; the name of the ranking to export and the file to
export to.
::
EXPORT_RANKING Dataranking1 /tmp/dataranking1.txt
**INIT_MISFIT_TABLE**
Calculating the misfit for all observations and all timesteps can
potentially be a bit timeconsuming, the results are therefor cached
internally. If you need to force the recalculation of this cache you
can use the INIT_MISFIT_TABLE job to initialize the misfit table that
is used in observation ranking.
::
INIT_MISFIT_TABLE
**STD_SCALE_CORRELATED_OBS**
The workflow job :code:`STD_SCALE_CORRELATED_OBS` is used to scale the
observation standard deviation in an attempt to reduce the effect of
correlations in the observed data. The job expects the observation
keys you want to consider as arguments:
::
STD_SCALE_CORRELATED_OBS WWCT:OP_1 WWCT:OP_2
In this example the observation uncertainty corresponding to
:code:`WWCT:OP_1` and :code:`WWCT:OP_2` will be scaled. Observe that
the :code:`STD_SCALE_CORRELATED_OBS` keyword will "flatten" in both
time and spatial direction. Wildcards are allow, i.e.
::
STD_SCALE_CORRELATED_OBS W*:OP_1
Will scale based on all the observations of well 'OP_1'. For more
advanced selections of observations, where you only want to scale
based on parts of the observation - spatially or temporaly you must
write your own plugin.

View File

@ -1,30 +0,0 @@
Workflows and plugins
=====================
Contents
.. toctree::
:maxdepth: 1
workflows
plugins
built_in
The Forward Model in ERT runs in the context of a single realization,
i.e. there is no communication between the different processes, and
the jobs are run outside of the main ERT process.
As an alternative to the forward model ERT has a system with
*workflows*. Using workflows way you can automate cumbersome normal
ERT processes, and also invoke external programs. The workflows are
run serially on the workstation actually running ERT, and should not
be used for computationally heavy tasks.
In addition to workflows ERT has a system for *plugins*, a plugin is
quite similar to a workflow job, but the plugin appears in a gui
dropdown, and can even have a gui of it's own. A plugin is written in
Python and has *full access* to ERT internals. The plugins hook into
the running Python process, and can only be invoked from the gui or
:code:`ertshell`.

View File

@ -1,246 +0,0 @@
Python plugins
==============
When you are using one of the python based frontends :code:`gert` or
:code:`ertshell` you can write plugins to ert in Python. The plugins
will run as part of the running ert process, and can do anything ert
can do itself. Writing a plugin is quite similar to writing an
:ref:`ert_script` - the main difference is that the class should
inherit from :code:`ErtPlugin`. This plugin will print the ensemble
size in the console:
.. code:: python
from ert.util import DoubleVector
from ert.enkf import ErtScript
class PrintEnsembleSize(ErtPlugin):
# The run method is the entry point which is called
# when the plugin is invoked.
def run(self):
ert = self.ert()
print("Ensemble size: %d" % ert.getEnsembleSize( ))
# This is the name of the plugin which will appear in the
# "Plugin" menu in the gui.
def getName(self):
return "Size plugin"
The plugins should be *installed* with a small configuration
file. Assume that the small code above is implemented in the script
file :code:`script/ens_size.py` then it is installed in ert as:
INTERNAL TRUE -- The job will call an internal function of the current running ERT instance.
SCRIPT sripts/ens_size.py -- An existing Python script
ERT will detect that the class inherits from :code:`ErtPlugin`, and
the functionality will be available as :code:`Size plugin` in the plugin menu.
As an example of a more complete plugin is the :code:`CSV export`
plugin from the ert code, this code can be used to export simulated
results, parameters and observations to a CSV file[#csv_export]_.
.. code:: python
import os
import re
import pandas
from PyQt4.QtGui import QCheckBox
from ert.enkf import ErtPlugin, CancelPluginException
from ert.enkf.export import SummaryCollector, GenKwCollector, MisfitCollector, DesignMatrixReader, CustomKWCollector
from ert_gui.ertwidgets.customdialog import CustomDialog
from ert_gui.ertwidgets.listeditbox import ListEditBox
from ert_gui.ertwidgets.models.path_model import PathModel
from ert_gui.ertwidgets.pathchooser import PathChooser
class CSVExportJob(ErtPlugin):
"""
Export of summary, custom_kw, misfit, design matrix data and gen kw into a single CSV file.
The script expects a single argument:
output_file: this is the path to the file to output the CSV data to
Optional arguments:
case_list: a comma separated list of cases to export (no spaces allowed)
if no list is provided the current case is exported
a single * can be used to export all cases
design_matrix: a path to a file containing the design matrix
infer_iteration: If True the script will try to infer the iteration number by looking at the suffix of the case name
(i.e. default_2 = iteration 2)
If False the script will use the ordering of the case list: the first item will be iteration 0,
the second item will be iteration 1...
The script also looks for default values for output path and design matrix path to present in the GUI. These can
be specified with DATA_KW keyword in the config file:
DATA_KW CSV_OUTPUT_PATH <some path>
DATA_KW DESIGN_MATRIX_PATH <some path>
"""
INFER_HELP = ("<html>"
"If this is checked the iteration number will be inferred from the name i.e.:"
"<ul>"
"<li>case_name -> iteration: 0</li>"
"<li>case_name_0 -> iteration: 0</li>"
"<li>case_name_2 -> iteration: 2</li>"
"<li>case_0, case_2, case_5 -> iterations: 0, 2, 5</li>"
"</ul>"
"Leave this unchecked to set iteration number to the order of the listed cases:"
"<ul><li>case_0, case_2, case_5 -> iterations: 0, 1, 2</li></ul>"
"<br/>"
"</html>")
def getName(self):
return "CSV Export"
def getDescription(self):
return "Export GenKW, CustomKW, design matrix, misfit data and summary data into a single CSV file."
def inferIterationNumber(self, case_name):
pattern = re.compile("_([0-9]+$)")
match = pattern.search(case_name)
if match is not None:
return int(match.group(1))
return 0
def run(self, output_file, case_list=None, design_matrix_path=None, infer_iteration=True):
cases = []
if case_list is not None:
if case_list.strip() == "*":
cases = self.getAllCaseList()
else:
cases = case_list.split(",")
if case_list is None or len(cases) == 0:
cases = [self.ert().getEnkfFsManager().getCurrentFileSystem().getCaseName()]
if design_matrix_path is not None:
if not os.path.exists(design_matrix_path):
raise UserWarning("The design matrix file does not exists!")
if not os.path.isfile(design_matrix_path):
raise UserWarning("The design matrix is not a file!")
data = pandas.DataFrame()
for index, case in enumerate(cases):
case = case.strip()
if not self.ert().getEnkfFsManager().caseExists(case):
raise UserWarning("The case '%s' does not exist!" % case)
if not self.ert().getEnkfFsManager().caseHasData(case):
raise UserWarning("The case '%s' does not have any data!" % case)
if infer_iteration:
iteration_number = self.inferIterationNumber(case)
else:
iteration_number = index
case_data = GenKwCollector.loadAllGenKwData(self.ert(), case)
custom_kw_data = CustomKWCollector.loadAllCustomKWData(self.ert(), case)
if not custom_kw_data.empty:
case_data = case_data.join(custom_kw_data, how='outer')
if design_matrix_path is not None:
design_matrix_data = DesignMatrixReader.loadDesignMatrix(design_matrix_path)
if not design_matrix_data.empty:
case_data = case_data.join(design_matrix_data, how='outer')
misfit_data = MisfitCollector.loadAllMisfitData(self.ert(), case)
if not misfit_data.empty:
case_data = case_data.join(misfit_data, how='outer')
summary_data = SummaryCollector.loadAllSummaryData(self.ert(), case)
if not summary_data.empty:
case_data = case_data.join(summary_data, how='outer')
else:
case_data["Date"] = None
case_data.set_index(["Date"], append=True, inplace=True)
case_data["Iteration"] = iteration_number
case_data["Case"] = case
case_data.set_index(["Case", "Iteration"], append=True, inplace=True)
data = pandas.concat([data, case_data])
data = data.reorder_levels(["Realization", "Iteration", "Date", "Case"])
data.to_csv(output_file)
export_info = "Exported %d rows and %d columns to %s." % (len(data.index), len(data.columns), output_file)
return export_info
def getArguments(self, parent=None):
description = "The CSV export requires some information before it starts:"
dialog = CustomDialog("CSV Export", description, parent)
default_csv_output_path = self.getDataKWValue("CSV_OUTPUT_PATH", default="output.csv")
output_path_model = PathModel(default_csv_output_path)
output_path_chooser = PathChooser(output_path_model)
design_matrix_default = self.getDataKWValue("DESIGN_MATRIX_PATH", default="")
design_matrix_path_model = PathModel(design_matrix_default, is_required=False, must_exist=True)
design_matrix_path_chooser = PathChooser(design_matrix_path_model)
list_edit = ListEditBox(self.getAllCaseList())
infer_iteration_check = QCheckBox()
infer_iteration_check.setChecked(True)
infer_iteration_check.setToolTip(CSVExportJob.INFER_HELP)
dialog.addLabeledOption("Output file path", output_path_chooser)
dialog.addLabeledOption("Design Matrix path", design_matrix_path_chooser)
dialog.addLabeledOption("List of cases to export", list_edit)
dialog.addLabeledOption("Infer iteration number", infer_iteration_check)
dialog.addButtons()
success = dialog.showAndTell()
if success:
design_matrix_path = design_matrix_path_model.getPath()
if design_matrix_path.strip() == "":
design_matrix_path = None
case_list = ",".join(list_edit.getItems())
return [output_path_model.getPath(), case_list, design_matrix_path, infer_iteration_check.isChecked()]
raise CancelPluginException("User cancelled!")
def getDataKWValue(self, name, default):
data_kw = self.ert().getDataKW()
if name in data_kw:
return data_kw[data_kw.indexForKey(name)][1]
return default
def getAllCaseList(self):
fs_manager = self.ert().getEnkfFsManager()
all_case_list = fs_manager.getCaseList()
all_case_list = [case for case in all_case_list if fs_manager.caseHasData(case)]
return all_case_list
.. rubric:: Footnotes
.. [csv_export] There are many solutions for CSV export; this plugin
is an example which is implemented based on the
internal ert datastructures, other - probably more
widely used alterantives are based on an external
process running through the simulation folders.

View File

@ -1,369 +0,0 @@
.. _workflows:
Configuring workflows in ERT consists of two steps: *installing the
jobs* which should be available for ERT to use in workflows, and then
subsequently assemble one or more jobs, with arguments, in a
workflow. You can use predefined workflow jobs, or create your
own. There are no predefined complete workflows.
Workflow jobs
=============
The workflow jobs are quite similar to the jobs in the forward model,
in particular the jobs are described by a configuration file which
resembles the one used by the forward model jobs. The workflow jobs
can be of two fundamentally different types - *external* and *internal*.
External workflow jobs
----------------------
These jobs invoke an external program/script to do the job, this is
very similar to the jobs of the forward model, but instead of running
as separate jobs on the cluster - one for each realization, the
workflow jobs will be invoked on the workstation running ert, and
typically go through all the realizations in one loop.
The executable invoked by the workflow job can be an executable you
have written yourself - in any language, or it can be an existing
Linux command like e.g. :code:`cp` or :code:`mv`.
Internal workflow jobs
----------------------
These jobs invoke a function in the address space of the ERT program
itself; i.e. they are run as part of the running ERT process - and can
in principle do anything that ERT can do itself. There are two two
varieties of the internal workflow jobs:
Invoke a pre exported function
..............................
This is the simplest, where you can invoke a a predefined ERT
function. The function must already have been marked as *exported* in
the ert code base. The list of predefined workflow jobs based on this
method can be found here: :ref:`built_in_workflow_jobs`. Marking a new
function as exported is quite simple, but it requires changes to the
core code and a new version must be installed.
.. _ert_script:
Run a Python Script
...................
If you are using one of the Python based frontends, *gert* or
*erthsell*, you can write your own Python script which is run as part
of the existing process. By using the full ert Python api you get
access to powerful customization/automization features. Below is an
example of :code:`ErtScript` which calculates the misfit for all
observations and prints the result to a text file. All Python scripts
of this kind must:
1. Be implemented as a class which iherits from :code:`ErtScript`
2. Have a method :code:`run(self)` which does the actual job
.. code:: python
from ert.util import DoubleVector
from ert.enkf import ErtScript
class ExportMisfit(ErtScript):
def run(self):
# Get a handle to running ert instance
ert = self.ert()
# Get a handle to the case / filesystem we are interested in;
# this should ideally come as an argument - not just use current.
fs = ert.getEnkfFsManager().getCurrentFileSystem()
# How many realisations:
ens_size = ert.getEnsembleSize( )
# Get a handle to all the observations
observations = ert.getObservations()
# Iterate through all the observations; each element in this
# iteration corresponds to one key in the observations file.
for obs in observations:
misfit = DoubleVector()
for iens in range(ens_size):
chi2 = obs.getTotalChi2( fs , iens )
misfit[iens] = chi2
permutation = misfit.permutationSort( )
print " # Realisation Misfit:%s" % obs.getObservationKey()
print "-----------------------------------"
for index in range(len(misfit)):
iens = permutation[index]
print "%2d %2d %10.5f" % (index , iens , misfit[iens])
print "-----------------------------------\n"
Configuring workflow jobs
-------------------------
Workflow jobs are configured with a small configuration file much like
the configuration file used to install forward model jobs. The
keywords used in the configuration file are in two *clases* - those
related to how the job should located/run and the arguments which
should passed from the workflow to the job.
Configure an internal job
.........................
When configuring an internal workflow job the keyword :code:`INTERNAL`
is given the value :code:`TRUE` to indicate that this is an internal
job. In addition you give the name of the C function you wish to
invoke. By default the workflow job will search for the function
symbol in the current process space, but by passing the :code:`MODULE`
keyword you can request the loading of an external shared library:
::
INTERNAL TRUE -- The job will call an internal function of the current running ERT instance.
FUNCTION enkf_main_plot_all -- Name of the ERT function we are calling; must be marked exportable.
MODULE /name/of/shared/library -- Very optional - to load an extra shared library.
Configure a an internal job: Python
...................................
If you wish to implement your job as a Python class, derived from
:code:`ErtScript` you should use the :code:`SCRIPT` keyword instead of
:code:`FUNCTION`, to point to an existing Python script:
::
INTERNAL TRUE -- The job will call an internal function of the current running ERT instance.
SCRIPT sripts/my_script.py -- An existing Python script
Observe that the important thing here is the fact that we are writing
an *internal* Python script; if you are writing an external script to
loop through all your realization folders that will typically be an
*external* script, and in that case the implementation language -
i.e. Python, Perl, C++, F77 ... has no relevance.
Configure an external job
.........................
An *external* job is a workflow job which is implemented in an
external executable, i.e. typically a script written in for instance
Python. When configuring an external job the most important keyword is
:code:`EXECUTABLE` which is used to give the path to the external
executable:
::
INTERNAL FALSE -- This is the default - not necessary to include.
EXECUTABLE path/to/program -- Path to a program/script which will be invoked by the job.
Configuring the arguments
.........................
In addition to the INTERNAL, FUNCTION, MODULE and EXECUTABLE keys
which are used to configure what the job should do there are some keys
which can be used to configure the number of arguments and their
type. These arguments apply to both internal and external jobs:
::
MIN_ARG 2 -- The job should have at least 2 arguments.
MAX_ARG 3 -- The job should have maximum 3 arguments.
ARG_TYPE 0 INT -- The first argument should be an integer
ARG_TYPE 1 FLOAT -- The second argument should be a float value
ARG_TYPE 2 STRING -- The third argument should be a string - the default.
The MIN_ARG,MAX_ARG and ARG_TYPE arguments are used to validate workflows.
**Example 1 : Plot variables**
::
-- FILE: PLOT --
INTERNAL TRUE
FUNCTION ert_tui_plot_JOB
MIN_ARG 1
This job will use the ERT internal function ert_tui_plot_JOB to plot
an ensemble of an arbitrary ERT variable. The job needs at least one
argument; there is no upper limit on the number of arguments.
**Example 2 : Run external script**
::
-- FILE: ECL_HIST --
EXECUTABLE Script/ecl_hist.py
MIN_ARG 3
This job will invoke the external script Script/ecl_host.py; the
script should have at least three commandline arguments. The path to
the script, Script/ecl_hist.py is interpreted relative to the location
of the configuration file.
Loading workflow jobs into ERT
------------------------------
Before the jobs can be used in workflows they must be 'loaded' into
ERT. This is done with two different ERT keywords:
::
LOAD_WORKFLOW_JOB jobConfigFile JobName
The LOAD_WORKFLOW_JOB keyword will load one workflow job. The name of
the job is optional, if not provided the job will get name from the
configuration file. Alternatively you can use the command
WORKFLOW_JOB_DIRECTORY which will load all the jobs in a
directory. The command:
::
WORKFLOW_JOB_DIRECTORY /path/to/jobs
will load all the workflow jobs in the /path/to/jobs
directory. Observe that all the files in the /path/to/jobs directory
should be job configuration files. The jobs loaded in this way will
all get the name of the file as the name of the job. The
:code:`WORKFLOW_OB_DIRECTORY` keyword will *not* load configuration
files recursively.
Complete Workflows
==================
A workflow is a list of calls to jobs, with additional arguments. The
job name should be the first element on each line. Based on the two
jobs PLOT and ECL_HIST we can create a small workflow example:
::
PLOT WWCT:OP_1 WWCT:OP_3 PRESSURE:10,10,10
PLOT FGPT FOPT
ECL_HIST <RUNPATH_FILE> <QC_PATH>/<ERTCASE>/wwct_hist WWCT:OP_1 WWCT:OP_2
In this workflow we create plots of the nodes
WWCT:OP_1;WWCT:OP_3,PRESSURE:10,10,10,FGPT and FOPT. The plot job we
have created in this example is completely general, if we limited
ourselves to ECLIPSE summary variables we could get wildcard
support. Then we invoke the ECL_HIST example job to create a
histogram. See below for documentation of <RUNPATH_FILE>,<QC_PATH> and
<ERTCASE>.
Loading workflows
-----------------
Workflows are loaded with the configuration option LOAD_WORKFLOW:
::
LOAD_WORKFLOW /path/to/workflow/WFLOW1
LOAD_WORKFLOW /path/to/workflow/workflow2 WFLOW2
The LOAD_WORKFLOW takes the path to a workflow file as the first
argument. By default the workflow will be labeled with the filename
internally in ERT, but optionally you can supply a second extra
argument which will be used as name for the workflow. Alternatively
you can load a workflow interactively.
Automatically run workflows : HOOK_WORKFLOW
-------------------------------------------
.. _hook_workflow:
.. topic:: HOOK_WORKFLOW
With the keyword :code:`HOOK_WORKFLOW` you can configure workflow
'hooks'; meaning workflows which will be run automatically at certain
points during ERTs execution. Currently there are four points in ERTs
flow of execution where you can hook in a workflow, before
the simulations start, :code:`PRE_SIMULATION`; after all the
simulations have completed :code:`POST_SIMULATION`;
before the update step, :code:`PRE_UPDATE` and after the update step, :code:`POST_UPDATE`. The
:code:`POST_SIMULATION` hook is typically used to trigger QC
workflows:
::
HOOK_WORKFLOW initWFLOW PRE_SIMULATION
HOOK_WORKFLOW preUpdateWFLOW PRE_UPDATE
HOOK_WORKFLOW postUpdateWFLOW POST_UPDATE
HOOK_WORKFLOW QC_WFLOW1 POST_SIMULATION
HOOK_WORKFLOW QC_WFLOW2 POST_SIMULATION
In this example the workflow :code:`initWFLOW` will run after all
the simulation directories have been created, just before the forward
model is submitted to the queue. The workflow :code:`preUpdateWFLOW` will be run before the
update step and :code:`postUpdateWFLOW` will be run after the
update step. When all the simulations are complete
the two workflows :code:`QC_WFLOW1` and :code:`QC_WFLOW2` will be
run.
Observe that the workflows being 'hooked in' with the
:code:`HOOK_WORKFLOW` must be loaded with the :code:`LOAD_WORKFLOW`
keyword.
Currently, :code:`PRE_UPDATE` and :code:`POST_UPDATE` are only
available from python.
Locating the realisations: <RUNPATH_FILE>
-----------------------------------------
Context must be passed between the main ERT process and the script
through the use of string substitution, in particular the 'magic' key
<RUNPATH_FILE> has been introduced for this purpose.
Many of the external workflow jobs involve looping over all the
realisations in a construction like this:
::
for each realisation:
// Do something for realisation
summarize()
When running an external job in a workflow there is no direct transfer
of information between the main ERT process and the external
script. We therefor must have a convention for transfering the
information of which realisations we have simulated on, and where they
are located in the filesystem. This is done through a file which looks
like this:
::
0 /path/to/real0 CASE_0000
1 /path/to/real1 CASE_0001
...
9 /path/to/real9 CASE_0009
The name and location of this file is available as the magical string
<RUNPATH_FILE> and that is typically used as the first argument to
external workflow jobs which should iterate over all realisations. The
realisations referred to in the <RUNPATH_FILE> are meant to be last
simulations you have run; the file is updated every time you run
simulations. This implies that it is (currently) not so convenient to
alter which directories should be used when running a workflow.

View File

@ -1,308 +0,0 @@
#!/usr/bin/python
# Copyright (C) 2011 Statoil ASA, Norway.
#
# The file 'job_dispatch.py' is part of ERT - Ensemble based Reservoir Tool.
#
# ERT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.
#
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.
import sys
import os
import os.path
import socket
import time
import random
OK_file = "OK"
EXIT_file = "EXIT"
STATUS_file = "STATUS"
run_path = sys.argv[1]
sleep_time = 10 # Time to sleep before exiting the script - to let the disks sync up.
short_sleep = 2
#################################################################
def redirect(file , fd , open_mode):
new_fd = os.open(file , open_mode , 0644)
os.dup2(new_fd , fd)
os.close(new_fd)
def cond_symlink(target , src):
if not os.path.exists(src):
os.symlink( target , src )
def cond_unlink(file):
if os.path.exists(file):
os.unlink(file)
def exec_job(job , executable):
if job["stdin"]:
redirect(job["stdin"] , 0 , os.O_RDONLY)
if job["stdout"]:
redirect(job["stdout"] , 1 , os.O_WRONLY | os.O_TRUNC | os.O_CREAT )
if job["stderr"]:
redirect(job["stderr"] , 2 , os.O_WRONLY | os.O_TRUNC | os.O_CREAT )
if job["environment"]:
env = job["environment"]
for key in env.keys():
os.putenv(key , env[key])
os.execvp(executable , [executable] + job["argList"])
def unlink_empty(file):
if os.path.exists(file):
st = os.stat( file )
if st.st_size == 0:
os.unlink( file )
def cleanup( job ):
if job["stdout"]:
unlink_empty( job["stdout"] )
if job["stderr"]:
unlink_empty( job["stderr"] )
if job["license_link"]:
os.unlink(job["license_link"])
# This function implements a simple "personal license" system limiting
# how many instances of this job can run concurrently. Observe that the
# limiting is based on pr. invocation of the queue system (i.e. ERT
# binary) and pr user. The system works as follows:
#
# 1. The job is initilized with a license_path and a max_running
# variable.
#
# 2. In the licens_path directory a license file is made.
#
# 3. For each instance a random hard-link is created to the license
# file - this is how the number of concurrent uses is counted.
#
# 4. When the external program is finished the hard link is removed.
def license_check( job ):
job["license_link"] = None
if job.has_key("max_running"):
if job["max_running"]:
job["license_file"] = "%s/%s" % (job["license_path"] , job["name"])
max_running = job["max_running"]
license_file = job["license_file"]
while True:
job["license_link"] = "%s/%d" % (job["license_path"] , random.randint(100000,999999))
if not os.path.exists(job["license_link"]):
break
if not os.path.exists(license_file):
fileH = open(license_file , "w")
fileH.write("This is a license file for job:%s" % job["name"])
fileH.close()
stat_info = os.stat(license_file)
currently_running = stat_info[3] - 1
while True:
stat_info = os.stat(license_file)
currently_running = stat_info[3] - 1
if currently_running < max_running:
break
else:
time.sleep(5)
os.link(license_file , job["license_link"])
while True:
stat_info = os.stat(license_file)
currently_running = stat_info[3] - 1
if currently_running <= max_running:
break # OK - now we can leave the building - and let the job start
else:
time.sleep(5)
# Compatibility mode which must be retained until all ert prior to
# svn 2709 has been removed.
def get_executable( job ):
executable = job.get("executable")
if not executable:
executable = job.get("portable_exe")
if not executable:
cpu = os.uname()[4]
if job["platform_exe"].has_key(cpu):
executable = job["platform_exe"][cpu]
else:
return (False, 0 , "%s : did not recognize platform:%s" % (job["name"] , cpu))
return executable
def run_one(job):
license_check( job )
if job["stdin"]:
if not os.path.exists(job["stdin"]):
return (False , 0 , "Could not locate stdin file: %s" % job["stdin"])
if job["start_file"]:
if not os.path.exists(job["start_file"]):
return (False , -1 , "Could not locate start_file:%s" % job["start_file"])
executable = get_executable( job )
start_time = time.time()
pid = os.fork()
if pid == 0:
exec_job(job , executable)
else:
if job["max_running_minutes"]:
proc_path = "/proc/%d" % pid
# There is max run time on the job.
while True:
time.sleep( short_sleep )
if os.path.exists( proc_path ): # Checking if the
run_time = time.time() - start_time
if run_time > (60 * job["max_running_minutes"]):
return (False , 0 , "Run time of %d minutes exceeded for job:%s" % ( job["max_running_minutes"] , job["name"]))
else:
break # The job is no longer running
else:
(return_pid , exit_status) = os.waitpid(pid , 0)
if job["target_file"]:
if os.path.exists(job["target_file"]):
stat = os.stat(job["target_file"])
if stat.st_ctime > start_time:
cleanup(job)
return (True , 0 , "")
else:
cleanup(job)
return (True , 0 , "Hmmm - seems the target file has not been updated - let the job suceed anyway...??")
else:
cleanup(job)
return (False , exit_status , "%s : could not find target_file:%s" % (job["name"] , job["target_file"]))
else:
cleanup(job)
return (True , exit_status , "Target file not speced") # Do not really look at exit status yet...
#################################################################
#################################################################
os.nice(19)
if not os.path.exists( run_path ):
sys.stderr.write("*****************************************************************\n");
sys.stderr.write("** FATAL Error: Could not find dirctory: %s \n" % run_path)
sys.stderr.write("** CWD: %s\n" % os.getcwd())
sys.stderr.write("*****************************************************************\n");
fileH = open(EXIT_file , "w")
fileH.write("Could not locate:%s " % run_path)
fileH.write("CWD: %s" % os.getcwd())
fileH.close()
sys.exit(-1)
os.chdir( run_path )
cond_unlink(EXIT_file)
cond_unlink(STATUS_file)
cond_unlink(OK_file)
fileH = open(STATUS_file , "a")
fileH.write("%-40s: %s/%s\n" % ("Current host:" , socket.gethostname() , os.uname()[4]))
fileH.close()
sys.path.append( os.getcwd() )
import jobs
random.seed()
for job in jobs.jobList:
# To ensure compatibility with old versions.
if not job.has_key("max_running_minutes"):
job["max_running_minutes"] = None
if len(sys.argv) == 2:
# Normal batch run.
for job in jobs.jobList:
fileH = open(STATUS_file , "a")
now = time.localtime()
fileH.write("%-32s: %02d:%02d:%02d .... " % (job["name"] , now.tm_hour , now.tm_min , now.tm_sec))
fileH.close()
(OK , exit_status, error_msg) = run_one(job)
now = time.localtime()
if OK:
fileH = open(STATUS_file , "a")
fileH.write("%02d:%02d:%02d \n" % (now.tm_hour , now.tm_min , now.tm_sec))
fileH.close()
else:
fileH = open(EXIT_file , "w")
fileH.write("%02d:%02d:%02d \n" % (now.tm_hour , now.tm_min , now.tm_sec))
fileH.write("%s : failed\n" % job["name"])
fileH.write("%s\n" % error_msg)
fileH.close()
sys.exit(exit_status)
if OK:
fileH = open("OK" , "w")
fileH.write("All jobs complete")
fileH.close()
time.sleep( sleep_time ) # Let the disks sync up
else:
#Interactive run
jobHash = {}
for job in jobs.jobList:
jobHash[job["name"]] = job
for job_name in sys.argv[2:]:
if jobHash.has_key( job_name ):
job = jobHash[job_name]
print "Running job: %s ... " % job_name,
sys.stdout.flush()
(OK , exit_status, error_msg) = run_one( job )
if OK:
print "OK"
else:
print "failed ...."
print "-----------------------------------------------------------------"
if job["stderr"]:
print "Error:%s " % error_msg
if os.path.exists(job["stderr"]):
fileH = open(job["stderr"],"r")
for line in fileH.readlines():
print line,
fileH.close()
print "-----------------------------------------------------------------"
sys.exit()
else:
print "Job: %s does not exist. Available jobs:" % job_name
for j in jobs.jobList:
print " %s" % j["name"]

View File

@ -1,394 +0,0 @@
#!/usr/bin/python
import sys
import os
import re
import random
import time
if os.path.exists( "dot_master.py" ):
sys.path += [ os.getcwd() ]
import dot_master
else:
dot_master = None
dot_master_fmt = "%-39s = %s\n"
error_file = "RMS_20XX_ERRORS_"
multi_seed_file = "random.seeds"
##################################################################
#
# The purpose of this script is to run a per-instance RMS workflow in
# batch from eg ERT. The script expects the following input as arguments
# on the commandline
#
# <SIMULATION_PATH>: The path to where the simulation should run. Directory
# must exist.
#
# <REALIZATION_NR>: An integer saying which realiziton number this is.
#
# <RMS_VERSION> : This is a string which indicates which RMS version
# should be run. The allowed versions are the keys in
# the dictionary rms_version_table below, there should
# be no problems adding more versions to this table.
#
# <RMS_PROJECT> : This is the (full) path to the source RMS project.
#
#
# <REPLACE_PATH>: The absolute path (set in the RMS project) part which
# should be replaced with the current directory.
#
# <RMS_WORKFLOW1>: This is the name of the workflow we want to run.
#
# <RMS_WORKFLOW2>: This is the name of the workflow we want to run.
#
# <RMS_WORKFLOW3>: This is the name of the workflow we want to run.
#
#
# Example:
#
# bash% run_RMS_20xx.py 0 2009.3 /d/MyField/models/rms/geomodel.pro /OLDPATH WorkFlow1 WorkFlow2 ...
#
# The script works as follows:
#
# 1. The first commandline argument is the runpath of the script, and
# it will start by chdir() there.
#
#
# 2. The script recursively walks through the original project
# directory, and does the following:
#
# a) All directories found in the original project are created
# in the copy project, thus creating a empty project
# skeleton.
# If a non-directory entry with the same name is found in the
# copy project the script will exit (this is maybe a bit over
# the top strict??)
#
# b) For files in the source directory the script will do the
# following:
#
# o If the name of the file is ".master" the script will
# _copy_ the file from the source project to the copy
# project, and on the way it will perform the string
# substitutions asked for.
#
# or
#
# o If a file with this name already exists in the target
# project nothing will be done.
#
# else
#
# o A symlink will be created from the copy project to the
# original source project.
#
#
# 3. The lockfiles "project-lock-file" and ".lock" are removed.
#
#
# 4. The program loops as follows:
# o Updating the global seed (incrementing by one with each subsequent iteration).
# o Running the rms binary for each workflow.
#
#
# Observe that this script has no explicit built in support for
# per-instance files (i.e. IPL scripts). The way that is meant to be
# solved is that an external program writes those files to the target
# project (creating necessary directories on the way) prior to calling
# this script.
#
################################################################
rms_license_file = "/prog/roxar/licensing/geomaticLM.lic"
rms_version_table = {"2010.1.1" : "/PATH/RMS/2010.1.1/linux-amd64-gcc_3_4-release/bin/rms",
"2010" : "/PATH/RMS/2010/linux-amd64-gcc_3_2-release/bin/rms",
"2009" : "/PATH/RMS/2009/linux-amd64-gcc_3_2-release/bin/rms",
"2009.2" : "/PATH/RMS/2009.2/linux-amd64-gcc_3_2-release/bin/rms",
"2009.3" : "/PATH/RMS/2009.3/linux-amd64-gcc_3_2-release/bin/rms",
"9.0.7.4" : "/PATH/RMS/9.0.7.4/linux-amd64-gcc_3_2-release/bin/rms"}
# This function will write the error message on both "RMS_20XX_ERRORS_" and
# stderr, and then exit.
def fatal_error( msg ):
fileH = open(error_file , "w")
fileH.write( msg )
fileH.close()
sys.exit( msg )
# This function will copy the file @src_entry to the file
# @target_entry, and on the way it will perform two different string
# substitutions. The .master file is organized like a key value list:
#
# key1 = Value1
# key2 = Value2
# ......
#
# The input argument @value_subst is a list of tuples, where each
# occurence of the first element in the tuple is replaced with the
# second element in the tuple.
#
# The input argument @set_list is a dictionary, if the key in the
# .master file is in the @set_list dictionary the value in the .master
# will be replaced with the value in the set_List dictionary.
def copy_dot_master( src_entry , target_entry , subst_list , set_list):
print "Copying %s -> %s" % (src_entry , target_entry)
if os.path.exists( target_entry ):
os.unlink( target_entry )
srcH = open( src_entry , "r")
targetH = open( target_entry , "w")
for line in srcH.readlines():
for (old , new) in subst_list:
line = line.replace( old , new )
tmp = re.split( "\s*=\s*" , line)
key = tmp[0]
if set_list.has_key( key) :
targetH.write( dot_master_fmt % (key , set_list[key]))
else:
targetH.write( line )
srcH.close()
targetH.close()
def create_project_directory( arg_dict , path , entries ):
offset = arg_dict["offset"]
target_root = arg_dict["target_root"]
src_path = arg_dict["src_path"]
subst = arg_dict["subst_list"]
set_list = arg_dict["set_list"]
newpath = "%s/%s" % ( target_root , path[offset:] )
#Creating all the directories of the project
if not os.path.exists( newpath ):
os.makedirs( newpath )
else:
if os.path.islink( newpath ):
fatal_error("Entry:%s already exists as a symbolic link. Clean up first..." % newpath)
if not os.path.isdir( newpath ):
fatal_error("Entry:%s already exists - and it is not a directory. Clean up first..." % newpath)
# Linking in all the files
for entry in entries:
src_entry = "%s/%s" % (path , entry)
if os.path.isfile( src_entry ):
target_entry = "%s/%s" % (newpath , entry)
if entry == ".master":
copy_dot_master( src_entry , target_entry , subst , set_list)
else:
if not os.path.exists( target_entry ):
os.symlink( src_entry , target_entry )
# This function duplicate the directory structure of the project
# located in src_path. The newly created project will be created in
# the current directory. All files are symlinked.
def create_project_directories( src_path , project , target_path , subst_list , set_list):
src_project = os.path.join( src_path , project )
arg_dict = {"offset" : len(src_path) ,
"target_root": target_path ,
"src_path" : src_path ,
"subst_list" : subst_list ,
"set_list" : set_list}
print "Creating all project directories: %s/%s" % (arg_dict["target_root"] , project )
os.path.walk( src_project , create_project_directory , arg_dict)
print "Setting up RMS project complete."
#################################################################
# This function will update the seed in the master_file. The function
# will update the following lines in the master_file:
#
# global_seed = 12345678
# seeds(n) = 09999999
#
# All the lines will be updated with the __same_seed__. This function is
# only called once, with the root level .master file as argument, if
# there are other random seeds around they are not touched.
#
#
# What seed to use:
# -----------------
#
# There are three different systems for choosing seed to use; the three
# methods are tried out in the following order:
#
# 1. If the file "RMS_SEED" exists in current working directory the
# script will use the value found in that file as seed.
#
# 2. If the file random.seeds exists the script will use integer
# nr @iens as seed. The format of the @multi_seed_file is just a
# list of integer, each on a separate line. The first integer should be the number of seeds
#
# 3. If neither of the seed files exist the script will use
# /dev/urandom to initialize the python rng, and then
# random.randint() to get a seed.
#
# The seed which is actually used in the end is appended to the file
# RMS_SEED_USED. Observe that for both the files RMS_SEED and
# @multi_seed_file the format "better" be right - the script will fail
# hard if these files are not formatted correctly.
def get_seed( target_path , project , iens):
single_seed_file = "%s/RMS_SEED" % target_path
if os.path.exists( single_seed_file ):
# Using existing single seed file
fileH = open( single_seed_file , "r" )
new_seed = int( fileH.readline( ) )
fileH.close()
elif os.path.exists( multi_seed_file ):
fileH = open( multi_seed_file , "r")
seed_list = [ int(x) for x in fileH.readlines() ]
fileH.close()
if seed_list[0] <= iens:
fatal_error("Asking for seed:%d seed_file:%s only has %d seeds\n" % (iens , multi_seed_file , seed_list[0]))
new_seed = seed_list[iens + 1]
else:
# Generate a seed from /dev/urandom
fileH = open( "/dev/urandom" , "r")
buffer = fileH.read( 64 )
fileH.close()
random.seed( buffer )
new_seed = random.randint( 0 , 21047483000 )
fileH = open("%s/RMS_SEED_USED" % target_path , "a+")
fileH.write("%s ... %d\n" % (time.strftime("%d-%m-%Y %H:%M:%S" , time.localtime(time.time())) , new_seed))
fileH.close()
return new_seed
def set_seed( seed ):
master_file = "%s/%s/.master" % ( target_path , project )
if not os.path.exists( master_file ):
fatal_error("Could not find rms master file: %s - seems like a broken project" % master_file )
fileH = open(master_file , "r")
linelist = fileH.readlines()
fileH.close()
fileH = open( master_file , "w" )
for line in linelist:
line = re.sub("^global_seed\s+=\s+\d+" , "global_seed = %d" % seed , line)
line = re.sub("^seeds\((\d+)\)\s+=\s+\d+" , "seeds(\1) = %d" % seed , line)
fileH.write( line )
fileH.close()
#################################################################
def init( arglist ):
if len(arglist) < 7:
msg = """
The run_RMS_20xx script needs the following arguments
\n cwd iens rms_version path_to_project replace_path workflow1 | workflow2 workflow3 ...
The available rms_versions are:%s
""" % rms_version_table.keys()
fatal_error( msg )
cwd = sys.argv[1]
iens = int( sys.argv[2] )
rms_version = sys.argv[3]
if rms_version_table.has_key( rms_version ):
rms_executable = rms_version_table[ rms_version ]
else:
fatal_error("Sorry: rms_version:%s not recognized - available:%s" % ( rms_version , rms_version_table.keys()))
src_project = arglist[4]
if os.path.exists( src_project ):
if os.path.isdir( src_project ):
(src_path , project) = os.path.split( src_project )
else:
fatal_error("Fatal error - %s is not a directory" % src_project)
else:
fatal_error("Fatal error - project:%s does not exist" % src_project)
replace_path = sys.argv[5]
rms_workflows = sys.argv[6:]
return (cwd , iens , rms_executable , src_path , project , replace_path , rms_workflows )
#################################################################
def unlink_lockfiles( project ):
lock_file1 = "%s/.lock" % project
if os.path.exists( lock_file1 ):
os.unlink( lock_file1 )
lock_file2 = "%s/project_lock_file" % project
if os.path.exists( lock_file2 ):
os.unlink( lock_file2 )
#################################################################
def run_rms( rms_executable , project , workflow ):
os.environ["LM_LICENSE_FILE"] = rms_license_file
cmd = "%s -nomesa -project %s -batch %s" % ( rms_executable , project , workflow )
print "Starting rms with command: \"%s\"" % cmd
os.system( cmd )
print "RMS run is complete"
#################################################################
#################################################################
# Main program starting:
(target_path , iens , rms_executable , src_path , project , replace_path , rms_workflows) = init( sys.argv )
if os.path.exists( target_path ):
os.chdir( target_path )
else:
fatal_error("Directory:%s does not exist \n" % target_path )
subst_list = [(replace_path , target_path)]
# If the dot_master module is present we ignore the replace_path commandline argument
if dot_master:
subst_list = dot_master.subst_list
set_list = dot_master.set_list
else:
set_list = {}
create_project_directories( src_path , project , target_path , subst_list , set_list)
unlink_lockfiles( project )
global_seed = get_seed( target_path , project , iens)
for workflow in rms_workflows:
set_seed( global_seed )
run_rms( rms_executable , project , workflow )
global_seed += 1

View File

@ -1,228 +0,0 @@
#!/usr/bin/python
# Copyright (C) 2011 Statoil ASA, Norway.
#
# The file 'run_eclipse.py' is part of ERT - Ensemble based Reservoir Tool.
#
# ERT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.
#
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.
import os
import sys
import socket
#################################################################
#
# This is a small script used to run ECLIPSE simulations from ERT. The
# script will set up some environment variables, initialize file
# descriptors and then exec() to the ECLIPSE executable (or to mpirun in
# the case of parallell simulations).
#
# The script expects three commandline arguments:
#
# run_eclipse.py version eclipse_name <num_cpu>
#
# The @version argument is one of the keys in the the dictionary
# version_table, below. @num_cpu is optional, it will default to one if
# not set.
#
#
#################################################################
# The first element in the tuple is the single CPU version to use, and
# the second element is the MPI version to use.
version_table = {"2007.1" : ("/PATH/ECLIPSE/2007.1/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2007.1/bin/linux_x86_64/eclipse_scampi.exe"),
"2007.2" : ("/PATH/ECLIPSE/2007.2/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2007.2/bin/linux_x86_64/eclipse_scampi.exe"),
"2008.1" : ("/PATH/ECLIPSE/2008.1/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2008.1/bin/linux_x86_64/eclipse_scampi.exe"),
"2008.2" : ("/PATH/ECLIPSE/2008.2/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2008.2/bin/linux_x86_64/eclipse_scampi.exe"),
"2009.1" : ("/PATH/ECLIPSE/2009.1/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2009.1/bin/linux_x86_64/eclipse_scampi.exe"),
"2009.2" : ("/PATH/ECLIPSE/2009.2/bin/linux_x86_64/eclipse.exe" , "/PATH/ECLIPSE/2009.2/bin/linux_x86_64/eclipse_scampi.exe")}
scali_path = "/opt/scali"
ecldir = "/PATH/ECLIPSE"
mpirun = "%s/bin/mpirun" % scali_path
config_file = "%s/macros/CONFIG.ECL" % ecldir
config_link = "ECL.CFG"
env_variables = {"F_UFMTENDIAN" : "big",
"LM_LICENSE_FILE" : "flexlm.server.com" }
max_cpu_sec = 10000000
max_wall_sec = 99999999
stdin_file = "eclipse.stdin"
stdout_file = "eclipse.stdout"
stderr_file = "eclipse.stderr"
# End of configuration options
#################################################################
# Will take a version string as input, and return the path to the
# executable file. If num_cpu == 1 it will return the serial version,
# whereas the Scali MPI version will be used if num_cpu > 1.
#
# If the @version input argument can not be found in the version_table
# dictionary, or the corresponding file does not exist, the function
# will fail with a fatal error.
def get_executable( version , num_cpu ):
t = version_table.get( version , None )
if t:
if num_cpu == 1:
executable = t[0]
else:
executable = t[1]
else:
fatal_error("Eclipse version:\'%s\' not recognized. Available versions:%s" % (version , version_table.keys()))
if not os.path.exists( executable ):
fatal_error("The executable:%s could not be found" % executable)
return executable
def init_mpi( base_name , num_cpu ):
# Before the SCALI MPI executable can run we must update the path by prepending
# ECL_SCALI_LOC/bin and ECL_SCALI_LOC/lib64 to the $PATH and $LD_LIBRARY_PATH
# environment variables.
env_variables["PATH"] = "%s/bin:%s" % ( scali_path , os.getenv("PATH"))
env_variables["LD_LIBRARY_PATH"] = "%s/lib64:%s" % ( scali_path , os.getenv("LD_LIBRARY_PATH"))
machine_list = []
# If the environment variable LSB_HOSTS is set we assume the job is
# running on LSF - otherwise we assume it is running on the current host.
#
# If the LSB_HOSTS variable is indeed set it will be a string like this:
#
# host1 host1 host2 host3
#
# i.e. each processs is listed with one hostname entry (i.e. NOT
# the :num_proc syntax which is used in LSB_MCPU_HOSTS variable.
machine_file = "%s.mpi" % base_name
fileH = open( machine_file , "w")
LSB_HOSTS = os.getenv("LSB_HOSTS")
if LSB_HOSTS:
for host in LSB_HOSTS.split():
fileH.write("%s\n" % host)
else:
localhost = socket.gethostname()
for i in (range(num_cpu)):
fileH.write("%s\n" % localhost)
fileH.close()
return machine_file
def fatal_error( msg ):
fileH = open( stderr_file , "w")
fileH.write( msg )
fileH.close()
sys.exit()
def init_fd( base_name ):
# Creating a stupid input file which is connected to stdin
fileH = open(stdin_file , "w")
fileH.write("%s\n" % base_name);
fileH.write("%s\n" % base_name);
fileH.write("%d\n" % max_cpu_sec);
fileH.write("%d\n\n" % max_wall_sec);
fileH.close()
# Redirecting stdin / stdout / stderr
fd_stdin = os.open(stdin_file , os.O_RDONLY , 0644)
fd_stdout = os.open(stdout_file , os.O_WRONLY | os.O_TRUNC | os.O_CREAT , 0644);
fd_stderr = os.open(stderr_file , os.O_WRONLY | os.O_TRUNC | os.O_CREAT , 0644);
os.dup2(fd_stdin , 0)
os.dup2(fd_stdout , 1)
os.dup2(fd_stderr , 2)
os.close(fd_stdin)
os.close(fd_stdout)
os.close(fd_stderr)
def init_path( base_name ):
smspec_file = "%s.SMSPEC" % base_name
fsmspec_file = "%s.FSMSPEC" % base_name
if os.path.exists( smspec_file ):
os.unlink( smspec_file );
if os.path.exists( fsmspec_file ):
os.unlink( fsmspec_file );
if not os.path.exists( config_link ):
os.symlink( config_file , config_link )
def exec_single(executable , env_variables):
os.execve(executable , [ executable ] , env_variables)
def exec_mpi(executable , base_name , num_cpu , env_variables):
machine_file = init_mpi( base_name , num_cpu )
os.execve( mpirun , [mpirun , "-np" , "%s" % num_cpu , "-machinefile" , machine_file , executable , base_name ] , env_variables)
#################################################################
# Main program starts.
if len(sys.argv) < 3 or len(sys.argv) > 4:
fatal_error("The run_eclipse script needs two/three arguments: eclipse_version eclipse_base [num_cpu]")
version = sys.argv[1]
(run_path , file) = os.path.split( sys.argv[2] )
(base_name , ext ) = os.path.splitext( file )
if run_path:
try:
os.chdir( run_path )
except:
fatal_error("The run_eclipse script could not change to directory:%s" % run_path)
if len(sys.argv) == 4:
# Must support older (svn version before ~ 2844) versions of ERT
# which do not provide a value for the the <num_cpu> argument, so
# in this case the run_eclipse.py script will just get the string
# "<num_cpu>", we catch the ValueError when converting to int, and
# use the default value num_cpu = 1.
try:
num_cpu = int( sys.argv[3] )
except ValueError:
num_cpu = 1
else:
num_cpu = 1
executable = get_executable(version , num_cpu)
init_path( base_name )
init_fd( base_name )
if num_cpu == 1:
exec_single( executable , env_variables)
else:
exec_mpi( executable , base_name , num_cpu , env_variables )

View File

@ -1,3 +0,0 @@
PORTABLE_EXE ../Scripts/run_eclipse.py
TARGET_FILE <RESTART_FILE2>
ARGLIST <ECLIPSE_VERSION> <ECLBASE>

View File

@ -1,3 +0,0 @@
PORTABLE_EXE ../Scripts/run_eclipse.py
TARGET_FILE <RESTART_FILE2>
ARGLIST 2009.2 <ECLBASE> <NUM_CPU>

View File

@ -1,2 +0,0 @@
PORTABLE_EXE ../Scripts/run_eclipse.py
ARGLIST 2009.2 <ECLBASE> <NUM_CPU>

View File

@ -1,8 +0,0 @@
STDERR rms.stderr
STDOUT rms.stdout
PORTABLE_EXE /project/res/etc/ERT/Scripts/run_RMS_20xx
-- RMS_PROJECT should be the full path to the rms project
ARGLIST <RUNPATH> <IENS> <RMS_VERSION> <RMS_PROJECT> /ROXAR <RMS_WORKFLOW>
TARGET_FILE <RMS_TARGET_FILE>
ENV LM_LICENSE_FILE /prog/roxar/licensing/geomaticLM.lic

View File

@ -1,79 +0,0 @@
-- This file is an example of site-wide configuration file for
-- ERT. Observe that the user can override/add to everything which is set
-- in this file in her per-project configuration file. Observe that
-- prior to parsing this file ERT will issue a chdir() system call to
-- the location of this file, i.e. you can safely use paths relative
-- to the location of this file.
-- Setting configuration information about the LSF system:
LSF_QUEUE normal
MAX_RUNNING_LSF 20
LSF_RESOURCES select[cs && x86_64Linux] rusage[ecl100v2000=1:duration=5]
-- Setting configuration information for running with rsh/ssh between
-- workstations. Observe that to actually use this option the user
-- must in addition specify which workstations to use in her project
-- specific configuration file like:
-- RSH_HOST_LIST host1:2 host2:4 host3:4
-- Which will run up to two jobs on 'host1' and four jobs on 'host2'
-- and 'host3'; in addition it is essential to have passwordless login
-- to the hosts 'hostx'.
MAX_RUNNING_RSH 100 -- You will never get more than the hosts allow anyway.
RSH_COMMAND /usr/bin/ssh
-- Configuration for running the local workstation:
MAX_RUNNING_LOCAL 4
-- Which queue system will we use?
QUEUE_SYSTEM LSF
-- How many times will we submit a job before failing it. Setting this
-- to two means first one submit, and then one more.
MAX_SUBMIT 2
-- Not related to the conventional idea of a license - forget about it ....
LICENSE_PATH license
-- The script used to run through the jobs in the forward model - a
-- very important script.
JOB_SCRIPT Scripts/job_dispatch.py
-- Installing a couple of jobs. A site will typically have a much
-- longer list of available jobs. The arguments of the INSTALL_JOB
-- command are first the short name of the job, which will be used
-- to refer to the job when setting up the forward, and secondly a
-- file with more details on how to run this job. Each of these files
-- are used to populate on instance of ext_job_type which is
-- implemented in libjob_queue/src/ext_job.c.
INSTALL_JOB RUN_RMS_20XX Config/jobs/RUN_RMS_20XX
INSTALL_JOB ECLIPSE100 Config/jobs/ECLIPSE100
INSTALL_JOB ECLIPSE100_2009.2 Config/jobs/ECLIPSE100_2009.2
INSTALL_JOB ECLIPSE100_2009.2_NOTARGET Config/jobs/ECLIPSE100_2009.2_NOTARGET
-- You can set environment variables with the SETENV command. The
-- SETENV command understands $VAR, so you can also update variables.
-- The LSF variables must be set for LSF to work, this is similar to
-- sourcing a LSF configuration file.
SETENV LSF_BINDIR /LSF_PATH/bin
SETENV LSF_LIBDIR /LSF_PATH/lib
SETENV XLSF_UIDDIR /LSF_PATH/lib/uid
SETENV LSF_SERVERDIR /LSF_PATH/etc
SETENV LSF_ENVDIR /LS_PATH/conf
-- In addition to SETENV you can also use UPDATE_PATH to update ':'
-- separated path related environment variables. UPDATE_PATH will
-- prepend the existing value of PATH with the new value.
UPDATE_PATH PATH /funky/path/bin
SETENV LD_LIBRARY_PATH /funky/path/lib:$LD_LIBRARY_PATH

View File

@ -1,42 +0,0 @@
This directory contains some example configuration files / scripts for
ERT. This directory should typically be installed in shared location
where it is readably for everyone. The files/directories are:
ERT/site-config
---------------
This is the shared configuration file for all ERT users.
ERT/Scripts
-----------
This is a collection of scripts. These are:
o ERT/Scripts/job_dispatch.py - the executable program started by
ERT, which again will start and run the other programs in the
forward model. A very important script; the path to this script is
set with the JOB_SCRIPT variable in the site-config file.
o ERT/Scripts/run_eclipse.py: This a script to run ECLIPSE - nothing
special about this. If you want to use this script, you must at the
very least update the paths to the ECLIPSE binary.
o ERT/Scripts/run_RMS_20xx: A script to run version 20xx of
RMS. Observe that this script is specifically designed to work
around a bug with exporting RMS datasets to a relative path; that
bug is now fixed in RMS.
ERT/jobs/***
-------------
The files in directory ERT/jobs are job-description files which are
used to 'install' jobs into ERT. The directory ERT/jobs/ contains
small config files to install three different ECLIPSE jobs. (Make the
effort and understand the difference between ECLIPSE100_2009.2 and
ECLIPSE100_2009.2_NOTARGET, this will serve you well when debugging
problems with failed jobs).
The jobs in ERT/jobs are installed into ERT with the INSTALL_JOB
commands in the sitewide configuration file.

View File

@ -1,14 +0,0 @@
include(cmake/ert_module.cmake)
add_subdirectory( script )
add_subdirectory( src )
add_subdirectory( modules )
if (BUILD_TESTS)
add_subdirectory( tests )
endif()
if (BUILD_APPLICATIONS)
add_subdirectory( applications )
endif()

View File

@ -1,20 +0,0 @@
add_executable( ert_module_test ert_module_test.c )
target_link_libraries( ert_module_test analysis ert_util )
if (USE_RUNPATH)
add_runpath( ert_module_test )
endif()
set (destination ${CMAKE_INSTALL_PREFIX}/bin)
install(TARGETS ert_module_test DESTINATION ${destination})
if (INSTALL_GROUP)
install(CODE "EXECUTE_PROCESS(COMMAND chgrp ${INSTALL_GROUP} ${destination}/ert_module_test)")
install(CODE "EXECUTE_PROCESS(COMMAND chmod g+w ${destination}/ert_module_test)")
endif()
if (BUILD_TESTS)
ert_module_name( VAR_RML rml_enkf ${LIBRARY_OUTPUT_PATH} )
add_test( analysis_module_test_RML ${EXECUTABLE_OUTPUT_PATH}/ert_module_test ${VAR_RML})
endif()

View File

@ -1,58 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'module_test.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <dlfcn.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
int check_module( rng_type * rng , const char * lib_name ) {
analysis_module_load_status_enum load_status;
analysis_module_type * module = analysis_module_alloc_external__( rng , lib_name , false , &load_status);
if (module != NULL) {
printf("Module loaded successfully\n");
analysis_module_free( module );
return 0;
} else {
if (load_status == DLOPEN_FAILURE) {
printf("\ndlerror(): %s\n\n",dlerror());
printf("The runtime linker could not open the library:%s.\n", lib_name);
printf("For the runtime linker to succesfully open your library\n");
printf("at least one of two must be satisfied: \n\n");
printf(" 1. You give the FULL PATH to library - including .so extension\n\n");
printf(" 2. The path containing the library is in LD_LIBRARY_PATH.\n\n");
printf("In addition all libraries needed by your module must be found\n");
} else if (load_status == LOAD_SYMBOL_TABLE_NOT_FOUND) {
printf("\nThe library %s was loaded successfully, however\n",lib_name);
printf("the symbol table:\'%s\' was not found. You must make sure\n",EXTERNAL_MODULE_NAME);
printf("that the \'analysis_table_type\' structure at the bottom\n");
printf("of the source file is named exactly: \'analysis_table\'.\n");
printf("See documentation of \'symbol_table\' in modules.txt.\n\n");
}
}
return 1;
}
int main( int argc , char ** argv) {
exit( check_module( NULL , argv[1] ) );
}

View File

@ -1,32 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <analysis_module.h>
#include <rng.h>
int main( int argc , char ** argv) {
rng_type * rng = NULL;
if (0)
{
analysis_module_type * module = analysis_module_alloc_external( rng , "./simple_enkf.so" , "SimpleEnKF" );
if (module != NULL) {
analysis_module_set_var( module , "FLAG" , "42" );
analysis_module_set_var( module , "VarX" , "42.77" );
analysis_module_free( module );
} else
fprintf(stderr,"Hmmmm - failed to load external analysis module. \n");
}
{
analysis_module_type * module = analysis_module_alloc_internal( rng , "simple_enkf_symbol_table", "SimpleEnKF" );
if (module != NULL) {
analysis_module_set_var( module , "FLAG" , "42" );
analysis_module_set_var( module , "VarX" , "42.7708" );
analysis_module_free( module );
} else
fprintf(stderr,"Hmmmm - failed to load internal analysis module. \n");
}
}

View File

@ -1,23 +0,0 @@
function( ert_module target args source_files )
set( build_file ${target}.so )
set( depends analysis )
set( arg_string "${target} ${args}")
separate_arguments( arg_list UNIX_COMMAND "${arg_string}")
foreach (src_file ${source_files} )
list(APPEND arg_list ${CMAKE_CURRENT_SOURCE_DIR}/${src_file} )
list(APPEND depends ${CMAKE_CURRENT_SOURCE_DIR}/${src_file} )
endforeach()
add_custom_command(
OUTPUT ${build_file}
COMMAND ${PROJECT_SOURCE_DIR}/libanalysis/script/ert_module
ARGS ${arg_list}
DEPENDS ${depends})
install(FILES ${build_file} DESTINATION ${CMAKE_INSTALL_LIBDIR})
get_filename_component( module ${target} NAME )
add_custom_target( ${module} ALL DEPENDS ${build_file} )
endfunction()

View File

@ -1,134 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'analysis_module.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_ANALYSIS_MODULE_H
#define ERT_ANALYSIS_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/util/type_macros.h>
#include <ert/util/matrix.h>
#include <ert/util/bool_vector.h>
#include <ert/analysis/module_info.h>
/*
These are option flag values which are used by the core ert code to
query the module of it's needs and capabilities. For instance to to
determine whether the data should be scaled prior to analysis the
core code will issue the call:
if (analysis_module_get_option( module, ANALYSIS_SCALE_DATA))
obs_data_scale( obs_data , S , E , D , R , dObs );
It is the responsability of the module to set the various flags.
*/
typedef enum {
ANALYSIS_NEED_ED = 1,
ANALYSIS_USE_A = 4, // The module will read the content of A - but not modify it.
ANALYSIS_UPDATE_A = 8, // The update will be based on modifying A directly, and not on an X matrix.
ANALYSIS_SCALE_DATA = 16,
ANALYSIS_ITERABLE = 32 // The module can bu used as an iterative smoother.
} analysis_module_flag_enum;
#define ANALYSIS_MODULE_FLAG_ENUM_SIZE 5
#define ANALYSIS_MODULE_FLAG_ENUM_DEFS {.value = ANALYSIS_NEED_ED , .name = "ANALYSIS_NEED_ED"},\
{.value = ANALYSIS_USE_A , .name = "ANALYSIS_USE_A"},\
{.value = ANALYSIS_UPDATE_A , .name = "ANALYSIS_UPDATE_A"},\
{.value = ANALYSIS_SCALE_DATA , .name = "ANALYSIS_SCALE_DATA"},\
{.value = ANALYSIS_ITERABLE , .name = "ANALYSIS_ITERABLE"}
#define EXTERNAL_MODULE_NAME "analysis_table"
#define EXTERNAL_MODULE_SYMBOL analysis_table
typedef enum {
LOAD_OK = 0,
DLOPEN_FAILURE = 1,
LOAD_SYMBOL_TABLE_NOT_FOUND = 2
} analysis_module_load_status_enum;
typedef struct analysis_module_struct analysis_module_type;
analysis_module_type * analysis_module_alloc_internal__( rng_type * rng , const char * symbol_table , bool verbose , analysis_module_load_status_enum * load_status);
analysis_module_type * analysis_module_alloc_internal( rng_type * rng , const char * symbol_table );
analysis_module_type * analysis_module_alloc_external__(rng_type * rng , const char * lib_name , bool verbose , analysis_module_load_status_enum * load_status);
analysis_module_type * analysis_module_alloc_external( rng_type * rng , const char * libname );
void analysis_module_free( analysis_module_type * module );
void analysis_module_free__( void * arg);
void analysis_module_initX(analysis_module_type * module ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D);
void analysis_module_updateA(analysis_module_type * module ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info);
void analysis_module_init_update( analysis_module_type * module ,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D );
const char * analysis_module_get_lib_name( const analysis_module_type * module);
bool analysis_module_internal( const analysis_module_type * module );
bool analysis_module_set_var( analysis_module_type * module , const char * var_name , const char * string_value );
const char * analysis_module_get_table_name( const analysis_module_type * module);
const char * analysis_module_get_name( const analysis_module_type * module );
void analysis_module_set_name( analysis_module_type * module , const char * name);
bool analysis_module_check_option( const analysis_module_type * module , long flag);
void analysis_module_complete_update( analysis_module_type * module );
bool analysis_module_has_var( const analysis_module_type * module , const char * var );
double analysis_module_get_double( const analysis_module_type * module , const char * var);
int analysis_module_get_int( const analysis_module_type * module , const char * var);
bool analysis_module_get_bool( const analysis_module_type * module , const char * var);
void * analysis_module_get_ptr( const analysis_module_type * module , const char * var);
const char * analysis_module_flag_enum_iget( int index, int * value);
UTIL_IS_INSTANCE_HEADER( analysis_module );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,95 +0,0 @@
#ifndef ERT_ANALYSIS_TABLE_H
#define ERT_ANALYSIS_TABLE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/util/matrix.h>
#include <ert/util/rng.h>
#include <ert/util/bool_vector.h>
#include <ert/analysis/module_info.h>
typedef void (analysis_updateA_ftype) (void * module_data ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info);
typedef void (analysis_initX_ftype) (void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D );
typedef bool (analysis_set_int_ftype) (void * module_data , const char * flag , int value);
typedef bool (analysis_set_bool_ftype) (void * module_data , const char * flag , bool value);
typedef bool (analysis_set_double_ftype) (void * module_data , const char * var , double value);
typedef bool (analysis_set_string_ftype) (void * module_data , const char * var , const char * value);
typedef void (analysis_free_ftype) (void * );
typedef void * (analysis_alloc_ftype) ( rng_type * rng );
typedef void (analysis_init_update_ftype) (void * module_data,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D);
typedef void (analysis_complete_update_ftype) (void * module_data );
typedef long (analysis_get_options_ftype) (void * module_data , long option);
typedef bool (analysis_has_var_ftype) (const void * module_data , const char * var_name);
typedef int (analysis_get_int_ftype) (const void * module_data , const char * var_name );
typedef double (analysis_get_double_ftype) (const void * module_data , const char * var_name );
typedef bool (analysis_get_bool_ftype) (const void * module_data , const char * var_name );
typedef void * (analysis_get_ptr_ftype) (const void * module_data , const char * var_name );
/*****************************************************************/
typedef struct {
const char * name;
analysis_updateA_ftype * updateA;
analysis_initX_ftype * initX;
analysis_init_update_ftype * init_update;
analysis_complete_update_ftype * complete_update;
analysis_free_ftype * freef;
analysis_alloc_ftype * alloc;
analysis_set_int_ftype * set_int;
analysis_set_double_ftype * set_double;
analysis_set_bool_ftype * set_bool;
analysis_set_string_ftype * set_string;
analysis_get_options_ftype * get_options;
analysis_has_var_ftype * has_var;
analysis_get_int_ftype * get_int;
analysis_get_double_ftype * get_double;
analysis_get_bool_ftype * get_bool;
analysis_get_ptr_ftype * get_ptr;
} analysis_table_type;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'cv_enkf.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/bool_vector.h>
typedef struct cv_enkf_data_struct cv_enkf_data_type;
void * cv_enkf_data_alloc( rng_type * rng );
void cv_enkf_data_free( void * arg );
void cv_enkf_init_update( void * arg ,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D );
void cv_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D);
bool cv_enkf_set_double( void * arg , const char * var_name , double value);
bool cv_enkf_set_int( void * arg , const char * var_name , int value);
bool cv_enkf_set_bool( void * arg , const char * var_name , bool value );
void cv_enkf_set_truncation( cv_enkf_data_type * data , double truncation );
void cv_enkf_set_pen_press( cv_enkf_data_type * data , bool value );
void cv_enkf_set_subspace_dimension( cv_enkf_data_type * data , int subspace_dimension);

View File

@ -1,115 +0,0 @@
#ifndef ERT_ENKF_LINALG_H
#define ERT_ENKF_LINALG_H
#include <ert/util/matrix_lapack.h>
#include <ert/util/matrix.h>
#include <ert/util/double_vector.h>
int enkf_linalg_get_PC( const matrix_type * S0,
const matrix_type * dObs ,
double truncation,
int ncomp,
matrix_type * PC,
matrix_type * PC_obs ,
double_vector_type * singular_values);
int enkf_linalg_num_PC(const matrix_type * S , double truncation );
void enkf_linalg_init_stdX( matrix_type * X ,
const matrix_type * S ,
const matrix_type * D ,
const matrix_type * W ,
const double * eig ,
bool bootstrap);
void enkf_linalg_init_sqrtX(matrix_type * X5 ,
const matrix_type * S ,
const matrix_type * randrot ,
const matrix_type * innov ,
const matrix_type * W ,
const double * eig ,
bool bootstrap);
void enkf_linalg_Cee(matrix_type * B, int nrens , const matrix_type * R , const matrix_type * U0 , const double * inv_sig0);
int enkf_linalg_svd_truncation(const matrix_type * S ,
double truncation ,
int ncomp ,
dgesvd_vector_enum store_V0T ,
double * sig0,
matrix_type * U0 ,
matrix_type * V0T);
int enkf_linalg_svdS(const matrix_type * S ,
double truncation ,
int ncomp ,
dgesvd_vector_enum jobVT ,
double * sig0,
matrix_type * U0 ,
matrix_type * V0T);
matrix_type * enkf_linalg_alloc_innov( const matrix_type * dObs , const matrix_type * S);
void enkf_linalg_lowrankCinv__(const matrix_type * S ,
const matrix_type * R ,
matrix_type * V0T ,
matrix_type * Z,
double * eig ,
matrix_type * U0,
double truncation,
int ncomp);
void enkf_linalg_lowrankCinv(const matrix_type * S ,
const matrix_type * R ,
matrix_type * W , /* Corresponding to X1 from Eq. 14.29 */
double * eig , /* Corresponding to 1 / (1 + Lambda_1) (14.29) */
double truncation ,
int ncomp);
void enkf_linalg_lowrankE(const matrix_type * S , /* (nrobs x nrens) */
const matrix_type * E , /* (nrobs x nrens) */
matrix_type * W , /* (nrobs x nrmin) Corresponding to X1 from Eqs. 14.54-14.55 */
double * eig , /* (nrmin) Corresponding to 1 / (1 + Lambda1^2) (14.54) */
double truncation ,
int ncomp);
void enkf_linalg_genX2(matrix_type * X2 , const matrix_type * S , const matrix_type * W , const double * eig);
void enkf_linalg_genX3(matrix_type * X3 , const matrix_type * W , const matrix_type * D , const double * eig);
void enkf_linalg_meanX5(const matrix_type * S ,
const matrix_type * W ,
const double * eig ,
const matrix_type * innov ,
matrix_type * X5);
void enkf_linalg_X5sqrt(matrix_type * X2 , matrix_type * X5 , const matrix_type * randrot, int nrobs);
matrix_type * enkf_linalg_alloc_mp_randrot(int ens_size , rng_type * rng);
void enkf_linalg_set_randrot( matrix_type * Q , rng_type * rng);
void enkf_linalg_checkX(const matrix_type * X , bool bootstrap);
//rml_enkf functions
void enkf_linalg_rml_enkfX1(matrix_type *X1, matrix_type * Udr ,matrix_type * S ,matrix_type *R);
void enkf_linalg_rml_enkfX2(matrix_type *X2, double *Wdr, matrix_type * X1 ,double a , int nsign);
void enkf_linalg_rml_enkfX3(matrix_type *X3, matrix_type *VdTr, double *Wdr,matrix_type *X2, int nsign);
double enkf_linalg_data_mismatch(matrix_type *D , matrix_type *R , matrix_type *Sk);
void enkf_linalg_Covariance(matrix_type *Cd, const matrix_type *E, double nsc ,int nrobs);
void enkf_linalg_rml_enkfAm(matrix_type * Um, const double * Wm,int nsign1);
void enkf_linalg_rml_enkfX7(matrix_type * X7, matrix_type * VdT, double * Wdr, double a,matrix_type * X6);
#endif

View File

@ -1,40 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'fwd_step_enkf.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/analysis/module_data_block_vector.h>
#include <ert/analysis/module_info.h>
typedef struct fwd_step_enkf_data_struct fwd_step_enkf_data_type;
void * fwd_step_enkf_data_alloc( rng_type * rng );
void fwd_step_enkf_data_free( void * arg );
void fwd_step_enkf_updateA(void * module_data ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info);

View File

@ -1,45 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'fwd_step_log.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef FWD_STEP_LOG_H
#define FWD_STEP_LOG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
typedef struct fwd_step_log_struct fwd_step_log_type;
fwd_step_log_type * fwd_step_log_alloc();
void fwd_step_log_free(fwd_step_log_type * fwd_step_log);
bool fwd_step_log_get_clear_log( const fwd_step_log_type * data );
void fwd_step_log_set_clear_log( fwd_step_log_type * data , bool clear_log);
void fwd_step_log_set_log_file( fwd_step_log_type * data , const char * log_file );
const char * fwd_step_log_get_log_file( const fwd_step_log_type * data);
void fwd_step_log_open( fwd_step_log_type * fwd_step_log );
void fwd_step_log_close( fwd_step_log_type * fwd_step_log );
void fwd_step_log_line( fwd_step_log_type * fwd_step_log , const char * fmt , ...);
bool fwd_step_log_is_open( const fwd_step_log_type * fwd_step_log );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_data_blocks.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef MODULE_DATA_BLOCKS_H
#define MODULE_DATA_BLOCKS_H
#include <ert/util/vector.h>
#ifdef __cplusplus
extern "C" {
#endif
struct module_data_block_struct {
UTIL_TYPE_ID_DECLARATION;
char * key;
const int * index_list;
int A_row_start;
int n_active;
};
typedef struct module_data_block_struct module_data_block_type;
module_data_block_type * module_data_block_alloc( const char * key, const int * index_list , const int row_start, const int n_active);
const char * module_data_block_get_key(const module_data_block_type * module_data_block);
const int module_data_block_get_row_start(const module_data_block_type * module_data_block);
const int module_data_block_get_row_end(const module_data_block_type * module_data_block);
const int * module_data_block_get_active_indices(const module_data_block_type * module_data_block );
void module_data_block_free(module_data_block_type * module_data_block);
void module_data_block_free__( void * arg );
UTIL_IS_INSTANCE_HEADER( module_data_block );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,42 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_data_block_vector.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_MODULE_DATA_BLOCK_VECTOR_H
#define ERT_MODULE_DATA_BLOCK_VECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/analysis/module_data_block.h>
typedef struct module_data_block_vector_struct module_data_block_vector_type;
module_data_block_vector_type * module_data_block_vector_alloc();
void module_data_block_vector_free();
void module_data_block_vector_add_data_block( module_data_block_vector_type * module_data_block_vector , const module_data_block_type * data_block);
module_data_block_type * module_data_block_vector_iget_module_data_block(const module_data_block_vector_type * module_data_block_vector, int index);
int module_data_block_vector_get_size(const module_data_block_vector_type * module_data_block_vector);
UTIL_IS_INSTANCE_HEADER( module_data_block_vector );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,42 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_info.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_MODULE_INFO_H
#define ERT_MODULE_INFO_H
#include <ert/analysis/module_data_block_vector.h>
#include <ert/analysis/module_obs_block_vector.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct module_info_struct module_info_type;
module_info_type * module_info_alloc(const char* ministep_name);
void module_info_free();
char * module_info_get_ministep_name(const module_info_type * module_info);
module_data_block_vector_type * module_info_get_data_block_vector(const module_info_type * module_info);
module_obs_block_vector_type * module_info_get_obs_block_vector(const module_info_type * module_info);
UTIL_IS_INSTANCE_HEADER( module_info );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_obs_blocks.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef MODULE_OBS_BLOCKS_H
#define MODULE_OBS_BLOCKS_H
#include <ert/util/vector.h>
#ifdef __cplusplus
extern "C" {
#endif
struct module_obs_block_struct {
UTIL_TYPE_ID_DECLARATION;
char * key;
const int * index_list;
int D_row_start;
int n_active;
};
typedef struct module_obs_block_struct module_obs_block_type;
module_obs_block_type * module_obs_block_alloc( const char * key, const int * index_list, const int row_start, const int n_active);
const char * module_obs_block_get_key(const module_obs_block_type * module_obs_block);
const int module_obs_block_get_row_start(const module_obs_block_type * module_obs_block);
const int module_obs_block_get_row_end(const module_obs_block_type * module_obs_block);
const int * module_obs_block_get_active_indices(const module_obs_block_type * module_obs_block );
void module_obs_block_free(module_obs_block_type * module_obs_block);
void module_obs_block_free__( void * arg );
UTIL_IS_INSTANCE_HEADER( module_obs_block );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,43 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_obs_block_vector.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_MODULE_OBS_BLOCK_VECTOR_H
#define ERT_MODULE_OBS_BLOCK_VECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/analysis/module_obs_block.h>
typedef struct module_obs_block_vector_struct module_obs_block_vector_type;
module_obs_block_vector_type * module_obs_block_vector_alloc();
void module_obs_block_vector_free();
void module_obs_block_vector_add_obs_block( module_obs_block_vector_type * module_obs_block_vector , module_obs_block_type * obs_block);
module_obs_block_type * module_obs_block_vector_iget_module_obs_block(const module_obs_block_vector_type * module_obs_block_vector, int index);
const module_obs_block_type * module_obs_block_vector_search_module_obs_block(const module_obs_block_vector_type * module_obs_block_vector, int global_index);
int module_obs_block_vector_get_size(const module_obs_block_vector_type * module_obs_block_vector);
UTIL_IS_INSTANCE_HEADER( module_obs_block_vector );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,56 +0,0 @@
#ifndef ERT_STD_ENKF_H
#define ERT_STD_ENKF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <ert/util/matrix.h>
#include <ert/util/rng.h>
#define DEFAULT_ENKF_TRUNCATION_ 0.98
#define ENKF_TRUNCATION_KEY_ "ENKF_TRUNCATION"
#define ENKF_NCOMP_KEY_ "ENKF_NCOMP"
#define USE_EE_KEY_ "USE_EE"
#define USE_GE_KEY_ "USE_GE"
#define ANALYSIS_SCALE_DATA_KEY_ "ANALYSIS_SCALE_DATA"
typedef struct std_enkf_data_struct std_enkf_data_type;
bool std_enkf_set_double( void * arg , const char * var_name , double value);
int std_enkf_get_subspace_dimension( std_enkf_data_type * data );
void std_enkf_set_truncation( std_enkf_data_type * data , double truncation );
void std_enkf_set_subspace_dimension( std_enkf_data_type * data , int subspace_dimension);
void std_enkf_set_lambda0( std_enkf_data_type * data , double lambda0 );
bool std_enkf_has_var( const void * arg, const char * var_name);
double std_enkf_get_truncation( std_enkf_data_type * data );
void * std_enkf_data_alloc( rng_type * rng);
void std_enkf_data_free( void * module_data );
bool std_enkf_get_bool( const void * arg, const char * var_name);
int std_enkf_get_int( const void * arg, const char * var_name);
double std_enkf_get_double( const void * arg, const char * var_name);
bool std_enkf_has_var( const void * arg, const char * var_name);
long std_enkf_get_options( void * arg , long flag );
bool std_enkf_set_bool( void * arg , const char * var_name , bool value);
bool std_enkf_set_int( void * arg , const char * var_name , int value);
bool std_enkf_set_double( void * arg , const char * var_name , double value);
void std_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,49 +0,0 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set( RML_SOURCE_FILES
rml_enkf_config.c
rml_enkf_log.c
rml_enkf.c
rml_enkf_common.c )
set( header_files analysis_module.h enkf_linalg.h analysis_table.h std_enkf.h rml_enkf_common.h)
add_library( rml_enkf SHARED ${RML_SOURCE_FILES} )
add_library( std_enkf_debug SHARED std_enkf_debug.c )
set_target_properties( rml_enkf PROPERTIES VERSION 1.0 SOVERSION 1.0 PREFIX "")
set_target_properties( std_enkf_debug PROPERTIES VERSION 1.0 SOVERSION 1.0 PREFIX "")
target_link_libraries( rml_enkf analysis dl )
target_link_libraries( std_enkf_debug analysis dl )
if (USE_RUNPATH)
add_runpath( rml_enkf )
add_runpath( std_enkf_debug )
endif()
if (BUILD_TESTS)
add_subdirectory( tests )
endif()
if (INSTALL_ERT)
install(TARGETS rml_enkf DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS std_enkf_debug DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
#-----------------------------------------------------------------
# Alternative script based build:
#if (BUILD_TESTS)
# if (BUILD_APPLICATIONS)
#set( args "--silent --exclude-ert -I${PROJECT_SOURCE_DIR}/libanalysis/include -I${PROJECT_SOURCE_DIR}/libert_util/include -I${CMAKE_CURRENT_SOURCE_DIR} -I${PROJECT_BINARY_DIR}/libert_util/include")
#set( RML_SOURCE_FILES
# rml_enkf.c
# rml_enkf_common.c )
#ert_module( ${LIBRARY_OUTPUT_PATH}/rml_enkf ${args} "${RML_SOURCE_FILES}")

View File

@ -1,427 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'rml_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ert/util/type_macros.h>
#include <ert/util/util.h>
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/bool_vector.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/std_enkf.h>
#include <rml_enkf_common.h>
/*
A random 'magic' integer id which is used for run-time type checking
of the input data.
*/
#define RML_ENKF_TYPE_ID 261123
/*
Observe that only one of the settings subspace_dimension and
truncation can be valid at a time; otherwise the svd routine will
fail. This implies that the set_truncation() and
set_subspace_dimension() routines will set one variable, AND
INVALIDATE THE OTHER. For most situations this will be OK, but if
you have repeated calls to both of these functions the end result
might be a surprise.
*/
#define INVALID_SUBSPACE_DIMENSION -1
#define INVALID_TRUNCATION -1
#define DEFAULT_SUBSPACE_DIMENSION INVALID_SUBSPACE_DIMENSION
/*
The configuration data used by the rml_enkf module is contained in a
rml_enkf_data_struct instance. The data type used for the rml_enkf
module is quite simple; with only a few scalar variables, but there
are essentially no limits to what you can pack into such a datatype.
All the functions in the module have a void pointer as the first
argument, this will immediately be casted to a rml_enkf_data_type
instance, to get some type safety the UTIL_TYPE_ID system should be
used (see documentation in util.h)
The data structure holding the data for your analysis module should
be created and initialized by a constructor, which should be
registered with the '.alloc' element of the analysis table; in the
same manner the desctruction of this data should be handled by a
destructor or free() function registered with the .freef field of
the analysis table.
*/
typedef struct rml_enkf_data_struct rml_enkf_data_type;
struct rml_enkf_data_struct {
UTIL_TYPE_ID_DECLARATION;
double truncation; // Controlled by config key: ENKF_TRUNCATION_KEY
int subspace_dimension; // Controlled by config key: ENKF_NCOMP_KEY (-1: use Truncation instead)
long option_flags;
int iteration_nr; // Keep track of the outer iteration loop
double lambda; // parameter to control the search direction in Marquardt levenberg optimization
double lambda0; // Initial lambda value
double Sk; // Objective function value
double Std; // Standard Deviation of the Objective function
matrix_type *state;
bool_vector_type * ens_mask;
};
/*
This is a macro which will expand to generate a function:
rml_enkf_data_type * rml_enkf_data_safe_cast( void * arg ) {}
which is used for runtime type checking of all the functions which
accept a void pointer as first argument.
*/
static UTIL_SAFE_CAST_FUNCTION( rml_enkf_data , RML_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION_CONST( rml_enkf_data , RML_ENKF_TYPE_ID )
double rml_enkf_get_truncation( rml_enkf_data_type * data ) {
return data->truncation;
}
int rml_enkf_get_subspace_dimension( rml_enkf_data_type * data ) {
return data->subspace_dimension;
}
void rml_enkf_set_truncation( rml_enkf_data_type * data , double truncation ) {
data->truncation = truncation;
if (truncation > 0.0)
data->subspace_dimension = INVALID_SUBSPACE_DIMENSION;
}
void rml_enkf_set_lambda0(rml_enkf_data_type * data , double lambda0 ) {
data->lambda0 = lambda0;
}
void rml_enkf_set_subspace_dimension( rml_enkf_data_type * data , int subspace_dimension) {
data->subspace_dimension = subspace_dimension;
if (subspace_dimension > 0)
data->truncation = INVALID_TRUNCATION;
}
void rml_enkf_set_iteration_number( rml_enkf_data_type *data , int iteration_number ) {
data->iteration_nr = iteration_number;
}
void * rml_enkf_data_alloc( rng_type * rng) {
rml_enkf_data_type * data = util_malloc( sizeof * data );
UTIL_TYPE_ID_INIT( data , RML_ENKF_TYPE_ID );
rml_enkf_set_truncation( data , DEFAULT_ENKF_TRUNCATION_ );
rml_enkf_set_subspace_dimension( data , DEFAULT_SUBSPACE_DIMENSION );
data->option_flags = ANALYSIS_NEED_ED + ANALYSIS_UPDATE_A + ANALYSIS_ITERABLE + ANALYSIS_SCALE_DATA;
data->iteration_nr = 0;
data->Std = 0;
data->state = matrix_alloc(1,1); // This will be resized under use; but we need a valid instance
data->lambda0 = -1.0;
data->ens_mask = bool_vector_alloc(0,false);
return data;
}
void rml_enkf_data_free( void * module_data ) {
rml_enkf_data_type * data = rml_enkf_data_safe_cast( module_data );
matrix_free( data->state );
bool_vector_free(data->ens_mask);
free( data );
}
/*
About the matrix Cd: The matrix Cd is calculated based on the content
of the E input matrix. In the original implementation this matrix was
only calculated in the first iteration, and then reused between subsequent
iterations.
Due to deactivating outliers the number of active observations can change
from one iteration to the next, if the matrix Cd is then reused between
iterations we will get a matrix size mismatch in the linear algebra. In the
current implementation the Cd matrix is recalculated based on the E input
for each iteration.
*/
void rml_enkf_updateA(void * module_data ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D) {
rml_enkf_data_type * data = rml_enkf_data_safe_cast( module_data );
double truncation = data->truncation;
double Sk_new;
double Std_new;
int ens_size = matrix_get_columns( S );
int nrobs = matrix_get_rows( S );
matrix_type * Cd = matrix_alloc( nrobs , nrobs);
double nsc = 1/sqrt(ens_size-1);
matrix_type * Skm = matrix_alloc(matrix_get_columns(D),matrix_get_columns(D));
FILE *fp = util_fopen("rml_enkf_output","a");
int nrmin = util_int_min( ens_size , nrobs);
matrix_type * Ud = matrix_alloc( nrobs , nrmin ); /* Left singular vectors. */
matrix_type * VdT = matrix_alloc( nrmin , ens_size ); /* Right singular vectors. */
double * Wd = util_calloc( nrmin , sizeof * Wd );
Cd = matrix_alloc( nrobs, nrobs );
enkf_linalg_Covariance(Cd ,E ,nsc, nrobs);
matrix_inv(Cd);
if (data->iteration_nr == 0) {
Sk_new = enkf_linalg_data_mismatch(D,Cd,Skm); //Calculate the intitial data mismatch term
Std_new = matrix_diag_std(Skm,Sk_new);
rml_enkf_common_store_state( data->state , A , data->ens_mask );
if (data->lambda0 < 0)
data->lambda = pow(10,floor(log10(Sk_new/(2*nrobs))));
else
data->lambda = data->lambda0;
rml_enkf_common_initA__(A,S,Cd,E,D,truncation,data->lambda,Ud,Wd,VdT);
data->Sk = Sk_new;
data->Std = Std_new;
printf("Prior Objective function value is %5.3f \n", data->Sk);
fprintf(fp,"Iteration number\t Lamda Value \t Current Mean (OB FN) \t Old Mean\t Current Stddev\n");
fprintf(fp, "\n\n");
fprintf(fp,"%d \t\t NA \t %5.5f \t \t %5.5f \n",data->iteration_nr, Sk_new, Std_new);
} else {
Sk_new = enkf_linalg_data_mismatch(D , Cd , Skm); //Calculate the intitial data mismatch term
Std_new= matrix_diag_std(Skm,Sk_new);
printf(" Current Objective function value is %5.3f \n\n",Sk_new);
printf("The old Objective function value is %5.3f \n", data->Sk);
if ((Sk_new< (data->Sk)) && (Std_new< (data->Std)))
{
if ( (1- (Sk_new/data->Sk)) < .0001) // check convergence ** model change norm has to be added in this!!
data-> iteration_nr = 16;
fprintf(fp,"%d \t\t %5.5f \t %5.5f \t %5.5f \t %5.5f \n",data->iteration_nr,data->lambda, Sk_new,data->Sk, Std_new);
data->lambda = data->lambda / 10 ;
data->Std = Std_new;
rml_enkf_common_store_state( data->state , A , data->ens_mask );
data->Sk = Sk_new;
rml_enkf_common_initA__(A,S,Cd,E,D,truncation,data->lambda,Ud,Wd,VdT);
}
else if((Sk_new< (data->Sk)) && (Std_new > (data->Std)))
{
if ( (1- (Sk_new/data->Sk)) < .0001) // check convergence ** model change norm has to be added in this!!
data-> iteration_nr = 16;
fprintf(fp,"%d \t\t %5.5f \t %5.5f \t %5.5f \t %5.5f \n",data->iteration_nr,data->lambda, Sk_new,data->Sk, Std_new);
data->Std=Std_new;
rml_enkf_common_store_state( data->state , A , data->ens_mask );
data->Sk = Sk_new;
rml_enkf_common_initA__(A,S,Cd,E,D,truncation,data->lambda,Ud,Wd,VdT);
}
else {
fprintf(fp,"%d \t\t %5.5f \t %5.5f \t %5.5f \t %5.5f \n",data->iteration_nr,data->lambda, Sk_new,data->Sk, Std_new);
printf("The previous step is rejected !!\n");
data->lambda = data ->lambda * 4;
rml_enkf_common_recover_state( data->state , A , data->ens_mask );
rml_enkf_common_initA__(A,S,Cd,E,D,truncation,data->lambda,Ud,Wd,VdT);
data->iteration_nr--;
}
}
data->iteration_nr++;
// setting the lower bound for lambda
if (data->lambda <.01)
data->lambda= .01;
printf ("The current iteration number is %d \n ", data->iteration_nr);
matrix_free(Cd);
matrix_free(Ud);
matrix_free(VdT);
matrix_free(Skm);
free(Wd);
fclose(fp);
}
void rml_enkf_init_update(void * arg ,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D ) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
bool_vector_memcpy( module_data->ens_mask , ens_mask );
}
bool rml_enkf_set_double( void * arg , const char * var_name , double value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_TRUNCATION_KEY_) == 0)
rml_enkf_set_truncation( module_data , value );
else if (strcmp( var_name , ENKF_LAMBDA0_KEY_) == 0)
rml_enkf_set_lambda0( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
bool rml_enkf_set_int( void * arg , const char * var_name , int value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_NCOMP_KEY_) == 0)
rml_enkf_set_subspace_dimension( module_data , value );
else if(strcmp( var_name , ENKF_ITER_KEY_) == 0)
rml_enkf_set_iteration_number( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
long rml_enkf_get_options( void * arg , long flag ) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
return module_data->option_flags;
}
}
bool rml_enkf_has_var( const void * arg, const char * var_name) {
bool ret = false;
if ((strcmp(var_name , ENKF_ITER_KEY_) == 0) ||
(strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0) ||
(strcmp(var_name , ENKF_LAMBDA0_KEY_) == 0)) {
ret = true;
}
return ret;
}
int rml_enkf_get_int( const void * arg, const char * var_name) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_ITER_KEY_) == 0)
return module_data->iteration_nr;
else
return -1;
}
}
double rml_enkf_get_double( const void * arg, const char * var_name) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return module_data->truncation;
else if (strcmp(var_name , ENKF_LAMBDA0_KEY_) == 0)
return module_data->lambda0;
else
return -1.0;
}
}
/**
gcc -fpic -c <object_file> -I?? <src_file>
gcc -shared -o <lib_file> <object_files>
*/
#ifdef INTERNAL_LINK
#define SYMBOL_TABLE rml_enkf_symbol_table
#else
#define SYMBOL_TABLE EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type SYMBOL_TABLE = {
.alloc = rml_enkf_data_alloc,
.freef = rml_enkf_data_free,
.set_int = rml_enkf_set_int ,
.set_double = rml_enkf_set_double ,
.set_bool = NULL ,
.set_string = NULL ,
.get_options = rml_enkf_get_options ,
.initX = NULL,
.updateA = rml_enkf_updateA ,
.init_update = rml_enkf_init_update ,
.complete_update = NULL,
.has_var = rml_enkf_has_var,
.get_int = rml_enkf_get_int,
.get_double = rml_enkf_get_double,
.get_ptr = NULL,
};

View File

@ -1,824 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'rml_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/bool_vector.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/std_enkf.h>
#include <rml_enkf_common.h>
#include <rml_enkf_config.h>
#include <rml_enkf_log.h>
typedef struct rml_enkf_data_struct rml_enkf_data_type;
//**********************************************
// DEFAULT PARAMS
//**********************************************
/*
Observe that only one of the settings subspace_dimension and
truncation can be valid at a time; otherwise the svd routine will
fail. This implies that the set_truncation() and
set_subspace_dimension() routines will set one variable, AND
INVALIDATE THE OTHER. For most situations this will be OK, but if
you have repeated calls to both of these functions the end result
might be a surprise.
*/
#define USE_PRIOR_KEY "USE_PRIOR"
#define LAMBDA_REDUCE_FACTOR_KEY "LAMBDA_REDUCE"
#define LAMBDA_INCREASE_FACTOR_KEY "LAMBDA_INCREASE"
#define LAMBDA0_KEY "LAMBDA0"
#define LAMBDA_MIN_KEY "LAMBDA_MIN"
#define LAMBDA_RECALCULATE_KEY "LAMBDA_RECALCULATE"
#define ITER_KEY "ITER"
#define LOG_FILE_KEY "LOG_FILE"
#define CLEAR_LOG_KEY "CLEAR_LOG"
#define RML_ENKF_TYPE_ID 261123
//**********************************************
// RML "object" data definition
//**********************************************
/*
The configuration data used by the rml_enkf module is contained in a
rml_enkf_data_struct instance. The data type used for the rml_enkf
module is quite simple; with only a few scalar variables, but there
are essentially no limits to what you can pack into such a datatype.
All the functions in the module have a void pointer as the first
argument, this will immediately be casted to a rml_enkf_data_type
instance, to get some type safety the UTIL_TYPE_ID system should be
used (see documentation in util.h)
The data structure holding the data for your analysis module should
be created and initialized by a constructor, which should be
registered with the '.alloc' element of the analysis table; in the
same manner the desctruction of this data should be handled by a
destructor or free() function registered with the .freef field of
the analysis table.
*/
struct rml_enkf_data_struct {
UTIL_TYPE_ID_DECLARATION;
int iteration_nr; // Keep track of the outer iteration loop
double Sk; // Objective function value
double Std; // Standard Deviation of the Objective function
double * Csc;
bool_vector_type * ens_mask;
matrix_type *Am; // Scaled right singular vectors of ensemble anomalies.
matrix_type *global_prior; // m_pr
matrix_type *previous_state; // m_l
double lambda; // parameter to control the setp length in Marquardt levenberg optimization
rml_enkf_log_type * rml_log;
rml_enkf_config_type * config;
};
static UTIL_SAFE_CAST_FUNCTION( rml_enkf_data , RML_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION_CONST( rml_enkf_data , RML_ENKF_TYPE_ID )
//**********************************************
// Set / Get
//**********************************************
void rml_enkf_set_iteration_nr( rml_enkf_data_type * data , int iteration_nr) {
data->iteration_nr = iteration_nr;
}
int rml_enkf_get_iteration_nr( const rml_enkf_data_type * data ) {
return data->iteration_nr;
}
//**********************************************
// Log-file related stuff
//**********************************************
static void rml_enkf_write_log_header( rml_enkf_data_type * data, const char * format) {
if (rml_enkf_log_is_open( data->rml_log )) {
const char * column1 = "Iter#";
const char * column2 = "Lambda";
const char * column3 = "Sk old";
const char * column4 = "Sk_new";
const char * column5 = "std(Sk)";
rml_enkf_log_line(data->rml_log, format, column1, column2, column3, column4, column5);
}
}
static void rml_enkf_write_iter_info( rml_enkf_data_type * data , double prev_Sk , double Sk_new, double Std_new ) {
if (rml_enkf_log_is_open( data->rml_log )) {
const char * format = "\n%2d-->%-2d %-7.3f %-7.3f --> %-7.3f %-7.3f";
const char * format_headers = "\n%-7s %-7s %-7s --> %-7s %-7s";
static bool has_printed_header = false;
if (!has_printed_header) {
rml_enkf_write_log_header( data, format_headers );
has_printed_header = true;
}
rml_enkf_log_line( data->rml_log , format, data->iteration_nr, data->iteration_nr+1, data->lambda, prev_Sk, Sk_new, Std_new);
}
}
//**********************************************
// Memory
//**********************************************
void * rml_enkf_data_alloc( rng_type * rng) {
rml_enkf_data_type * data = util_malloc( sizeof * data);
UTIL_TYPE_ID_INIT( data , RML_ENKF_TYPE_ID );
data->config = rml_enkf_config_alloc();
data->rml_log = rml_enkf_log_alloc();
data->Csc = NULL;
data->iteration_nr = 0;
data->Std = 0;
data->previous_state = matrix_alloc(1,1);
data->global_prior = NULL;
data->ens_mask = NULL;
return data;
}
void rml_enkf_data_free( void * arg ) {
rml_enkf_data_type * data = rml_enkf_data_safe_cast( arg );
matrix_free( data->previous_state );
if (data->global_prior)
matrix_free( data->global_prior );
rml_enkf_log_free( data->rml_log );
rml_enkf_config_free( data->config );
free( data );
}
//**********************************************
// Notation
//**********************************************
/*
* X1-X7, intermediate calculations in iterations. See D.Oliver algorithm
*
* Variable name in code <-> D.Oliver notation <-> Description
* -------------------------------------------------------------------------------------------------------------
* A <-> m_l <-> Ensemble matrix. Updated in-place by iterations.
* data->previous_state <-> m_(l-1) <-> "A" from the previous iteration. Backs up A in case the update is bad.
* data->global_prior <-> <-> Previously: "active_prior". Stores A from before iter0, i.e. the actual prior.
* Acopy <-> <-> Eliminated from code. Copy of A (at each iteration, before acceptance/rejection decision)
*
* Am <-> A_m <-> Am = Um*Wm^(-1)
* Csc <-> C_sc^(1/2) <-> State scalings. Note the square root.
* Dm (in init1__) <-> Delta m <-> Anomalies of prior wrt. its mean (row i scaled by 1/(Csc[i]*sqrt(N-1)))
* Dm (in initA__) <-> Csc * Delta m <-> Anomalies of A wrt. its mean (only scaled by 1/sqrt(N-1))
* Dk1 (in init2__) <-> Delta m <-> Anomailes of A (row i scaled by 1/(Csc[i]*sqrt(N-1)))
* Dk (in init2__) <-> C_sc^(-1) * (m - m_pr ) <-> Anomalies wrt. prior (as opposed to the mean; only scaled by Csc)
* dA1 (in initA__) <-> delta m_1 <-> Ensemble updates coming from data mismatch
* dA2 (in init2__) <-> delta m_2 <-> Ensemble updates coming from prior mismatch
*/
//**********************************************
// Actual Algorithm, called through updateA()
//**********************************************
// Just (pre)calculates data->Am = Um*Wm^(-1).
static void rml_enkf_init1__( rml_enkf_data_type * data) {
// Differentiate this routine from init2__, which actually calculates the prior mismatch update.
// This routine does not change any ensemble matrix.
// Um*Wm^(-1) are the scaled, truncated, right singular vectors of data->global_prior
matrix_type * prior = matrix_alloc_column_compressed_copy( data->global_prior , data->ens_mask);
int state_size = matrix_get_rows( prior );
int ens_size = matrix_get_columns( prior );
int nrmin = util_int_min( ens_size , state_size);
matrix_type * Dm = matrix_alloc_copy( prior );
matrix_type * Um = matrix_alloc( state_size , nrmin ); /* Left singular vectors. */
matrix_type * VmT = matrix_alloc( nrmin , ens_size ); /* Right singular vectors. */
double * Wm = util_calloc( nrmin , sizeof * Wm );
double nsc = 1/sqrt(ens_size - 1);
matrix_subtract_row_mean(Dm);
{
const double * Csc = data->Csc;
for (int i=0; i < state_size; i++){
double sc = nsc / (Csc[i]);
matrix_scale_row( Dm , i , sc);
}
}
// Um Wm VmT = Dm; nsign1 = num of non-zero singular values.
int nsign1 = enkf_linalg_svd_truncation(Dm , rml_enkf_config_get_truncation( data->config ) , -1 , DGESVD_MIN_RETURN , Wm , Um , VmT);
// Am = Um*Wm^(-1). I.e. scale *columns* of Um
enkf_linalg_rml_enkfAm(Um, Wm, nsign1);
data->Am = matrix_alloc_copy( Um );
matrix_free(Um);
matrix_free(VmT);
matrix_free(Dm);
matrix_free(prior);
free(Wm);
}
// Creates state scaling matrix
void rml_enkf_init_Csc(const rml_enkf_data_type * data ){
// This seems a strange choice of scaling matrix. Review?
matrix_type * prior = matrix_alloc_column_compressed_copy( data->global_prior , data->ens_mask );
{
int state_size = matrix_get_rows( prior );
int ens_size = matrix_get_columns( prior );
for (int row=0; row < state_size; row++) {
double sumrow = matrix_get_row_sum(prior , row);
double tmp = sumrow / ens_size;
if (abs(tmp)< 1)
data->Csc[row] = 0.05;
else
data->Csc[row] = 1.00;
}
matrix_free( prior );
}
}
// Calculates update from data mismatch (delta m_1). Also provides SVD for later use.
static void rml_enkf_initA__(rml_enkf_data_type * data, matrix_type * A, matrix_type * S, matrix_type * Cd, matrix_type * E, matrix_type * D, matrix_type * Udr, double * Wdr, matrix_type * VdTr) {
int ens_size = matrix_get_columns( S );
int state_size = matrix_get_rows( A );
double nsc = 1/sqrt(ens_size-1);
int nsign;
// Perform SVD of tmp, where: tmp = diag_sqrt(Cd^(-1)) * centered(S) / sqrt(N-1) = Ud * Wd * Vd(T)
{
int nrobs = matrix_get_rows( S );
matrix_type *tmp = matrix_alloc (nrobs, ens_size);
matrix_subtract_row_mean( S ); // Center S
matrix_inplace_diag_sqrt(Cd); // Assumes that Cd is diag!
matrix_matmul(tmp , Cd , S ); //
matrix_scale(tmp , nsc); //
nsign = enkf_linalg_svd_truncation(tmp , rml_enkf_config_get_truncation( data->config ) , -1 , DGESVD_MIN_RETURN , Wdr , Udr , VdTr);
matrix_free( tmp );
}
// Calc X3
{
matrix_type * X3 = matrix_alloc( ens_size, ens_size );
{
matrix_type * X1 = matrix_alloc( nsign, ens_size);
matrix_type * X2 = matrix_alloc( nsign, ens_size );
// See LM-EnRML algorithm in Oliver'2013 (Comp. Geo.) for meaning
enkf_linalg_rml_enkfX1(X1, Udr ,D ,Cd ); // X1 = Ud(T)*Cd(-1/2)*D -- D= -(dk-d0)
enkf_linalg_rml_enkfX2(X2, Wdr ,X1 ,data->lambda + 1 , nsign); // X2 = ((a*Ipd)+Wd^2)^-1 * X1
enkf_linalg_rml_enkfX3(X3, VdTr ,Wdr,X2, nsign); // X3 = Vd *Wd*X2
matrix_free(X2);
matrix_free(X1);
}
// Update A
{
matrix_type * dA1 = matrix_alloc( state_size , ens_size);
matrix_type * Dm = matrix_alloc_copy( A );
matrix_subtract_row_mean( Dm ); /* Remove the mean from the ensemble of model parameters*/
matrix_scale(Dm, nsc);
matrix_matmul(dA1, Dm , X3);
matrix_inplace_add(A,dA1); // dA
matrix_free(Dm);
matrix_free(dA1);
}
matrix_free(X3);
}
}
// Calculate prior mismatch update (delta m_2).
void rml_enkf_init2__( rml_enkf_data_type * data, matrix_type *A, double * Wdr, matrix_type * VdTr) {
// Distinguish from init1__ which only makes preparations, and is only called at iter=0
int state_size = matrix_get_rows( A );
int ens_size = matrix_get_columns( A );
double nsc = 1/sqrt(ens_size-1);
matrix_type *Am = matrix_alloc_copy(data->Am);
matrix_type *Apr = matrix_alloc_column_compressed_copy(data->global_prior , data->ens_mask );
// fprintf(stdout,"\n");
// fprintf(stdout,"A: %d x %d\n", matrix_get_rows(A), matrix_get_columns(A));
// fprintf(stdout,"prior : %d x %d\n", matrix_get_rows(data->global_prior), matrix_get_columns(data->global_prior));
// fprintf(stdout,"state : %d x %d\n", matrix_get_rows(data->previous_state), matrix_get_columns(data->previous_state));
// fprintf(stdout,"Apr : %d x %d\n", matrix_get_rows(Apr), matrix_get_columns(Apr));
// fprintf(stdout,"Am : %d x %d\n", matrix_get_rows(Am), matrix_get_columns(Am));
// Example:
// A : 27760 x 10
// prior : 27760 x 10
// state : 27760 x 50
// prior0 : 27760 x 50
// Apr : 27760 x 10
// Am : 27760 x 1
int nsign1 = matrix_get_columns(data->Am);
matrix_type * X4 = matrix_alloc(nsign1,ens_size);
matrix_type * X5 = matrix_alloc(state_size,ens_size);
matrix_type * X6 = matrix_alloc(ens_size,ens_size);
matrix_type * X7 = matrix_alloc(ens_size,ens_size);
matrix_type * dA2 = matrix_alloc(state_size , ens_size);
matrix_type * Dk1 = matrix_alloc_copy( A );
// Dk = Csc^(-1) * (A - Aprior)
// X4 = Am' * Dk
{
matrix_type * Dk = matrix_alloc_copy( A );
matrix_inplace_sub( Dk , Apr );
rml_enkf_common_scaleA(Dk , data->Csc , true);
matrix_dgemm(X4 , Am , Dk , true, false, 1.0, 0.0);
matrix_free(Dk);
}
// X5 = Am * X4
matrix_matmul(X5 , Am , X4);
// Dk1 = Csc^(-1)/sqrt(N-1) * A*(I - 1/N*ones(m,N))
matrix_subtract_row_mean(Dk1); // Dk1 = Dk1 * (I - 1/N*ones(m,N))
rml_enkf_common_scaleA(Dk1 , data->Csc , true); // Dk1 = Csc^(-1) * Dk1
matrix_scale(Dk1,nsc); // Dk1 = Dk1 / sqrt(N-1)
// X6 = Dk1' * X5
matrix_dgemm(X6, Dk1, X5, true, false, 1.0, 0.0);
// X7
enkf_linalg_rml_enkfX7(X7, VdTr , Wdr , data->lambda + 1, X6);
// delta m_2
rml_enkf_common_scaleA(Dk1 , data->Csc , false);
matrix_matmul(dA2 , Dk1 , X7);
matrix_inplace_sub(A, dA2);
matrix_free(Am);
matrix_free(Apr);
matrix_free(X4);
matrix_free(X5);
matrix_free(X6);
matrix_free(X7);
matrix_free(dA2);
matrix_free(Dk1);
}
// Initialize state and prior from A. Initialize lambda0, lambda. Call initA__, init1__
static void rml_enkf_updateA_iter0(rml_enkf_data_type * data, matrix_type * A, matrix_type * S, matrix_type * R, matrix_type * dObs, matrix_type * E, matrix_type * D, matrix_type * Cd) {
int ens_size = matrix_get_columns( S );
int nrobs = matrix_get_rows( S );
int nrmin = util_int_min( ens_size , nrobs);
int state_size = matrix_get_rows( A );
matrix_type * Skm = matrix_alloc(ens_size, ens_size); // Mismatch
matrix_type * Ud = matrix_alloc( nrobs , nrmin ); /* Left singular vectors. */
matrix_type * VdT = matrix_alloc( nrmin , ens_size ); /* Right singular vectors. */
double * Wd = util_calloc( nrmin , sizeof * Wd );
data->Csc = util_calloc(state_size , sizeof * data->Csc);
data->Sk = enkf_linalg_data_mismatch(D,Cd,Skm);
data->Std = matrix_diag_std(Skm,data->Sk);
{
double lambda0 = rml_enkf_config_get_lambda0( data->config );
if (lambda0 < 0)
data->lambda = pow(10 , floor(log10(data->Sk/(2*nrobs))) );
else
data->lambda = lambda0;
}
// state = A
rml_enkf_common_store_state( data->previous_state , A , data->ens_mask );
// prior = A
data->global_prior = matrix_alloc_copy( data->previous_state );
// Update dependant on data mismatch
rml_enkf_initA__(data , A, S , Cd , E , D , Ud , Wd , VdT);
// Update dependant on prior mismatch. This should be zero (coz iter0).
// Therefore the purpose of init1__ is just to prepare some matrices.
if (rml_enkf_config_get_use_prior(data->config)) {
rml_enkf_init_Csc( data );
rml_enkf_init1__( data );
}
rml_enkf_write_iter_info(data, data->Sk , data->Sk, data->Std);
matrix_free( Skm );
matrix_free( Ud );
matrix_free( VdT );
free( Wd );
}
void rml_enkf_updateA(void * module_data, matrix_type * A, matrix_type * S, matrix_type * R, matrix_type * dObs, matrix_type * E, matrix_type * D, const module_info_type* module_info) {
// A : ensemble matrix
// R : (Inv?) Obs error cov.
// S : measured ensemble
// dObs: observed data
// E : perturbations for obs
// D = dObs + E - S : Innovations (wrt pert. obs)
// module_info: Information on parameters/data for internal logging
double Sk_new; // Mismatch
double Std_new; // Std dev(Mismatch)
rml_enkf_data_type * data = rml_enkf_data_safe_cast( module_data );
int nrobs = matrix_get_rows( S ); // Num obs
int ens_size = matrix_get_columns( S ); // N
double nsc = 1/sqrt(ens_size-1); // Scale factor
matrix_type * Cd = matrix_alloc( nrobs, nrobs ); // Cov(E), where E = measurement perturbations?
// Empirical error covar. R is left unused. Investigate?
enkf_linalg_Covariance(Cd ,E ,nsc, nrobs); // Cd = SampCov(E) (including (N-1) normalization)
matrix_inv(Cd); // In-place inversion
rml_enkf_log_open(data->rml_log , data->iteration_nr);
fprintf(stdout,"\nIter %d --> %d", data->iteration_nr, data->iteration_nr + 1);
if (data->iteration_nr == 0) {
// IF ITERATION 0
rml_enkf_updateA_iter0(data , A , S , R , dObs , E , D , Cd);
data->iteration_nr++;
} else {
// IF ITERATION 1, 2, ...
int nrmin = util_int_min( ens_size , nrobs); // Min(p,N)
matrix_type * Ud = matrix_alloc( nrobs , nrmin ); // Left singular vectors. */
matrix_type * VdT = matrix_alloc( nrmin , ens_size ); // Right singular vectors. */
double * Wd = util_calloc( nrmin , sizeof * Wd ); // Singular values, vector
matrix_type * Skm = matrix_alloc(ens_size,ens_size); // Mismatch
Sk_new = enkf_linalg_data_mismatch(D,Cd,Skm); // Skm = D'*inv(Cd)*D; Sk_new = trace(Skm)/N
Std_new = matrix_diag_std(Skm,Sk_new); // Standard deviation of mismatches.
// Lambda = Normalized data mismatch (rounded)
if (rml_enkf_config_get_lambda_recalculate( data->config ))
data->lambda = pow(10 , floor(log10(Sk_new / (2*nrobs))) );
// Accept/Reject update? Lambda calculation.
{
bool mismatch_reduced = false;
bool std_reduced = false;
if (Sk_new < data->Sk)
mismatch_reduced = true;
if (Std_new <= data->Std)
std_reduced = true;
rml_enkf_write_iter_info(data, data->Sk , Sk_new, Std_new);
if (mismatch_reduced) {
/*
Stop check: if ( (1- (Sk_new/data->Sk)) < .0001) // check convergence ** model change norm has to be added in this!!
*/
// Reduce Lambda
if (std_reduced)
data->lambda = data->lambda * rml_enkf_config_get_lambda_decrease_factor( data->config );
rml_enkf_common_store_state(data->previous_state , A , data->ens_mask );
data->Sk = Sk_new;
data->Std=Std_new;
data->iteration_nr++;
} else {
// Increase lambda
data->lambda = data->lambda * rml_enkf_config_get_lambda_increase_factor( data->config );
// A = data->previous_state
rml_enkf_common_recover_state( data->previous_state , A , data->ens_mask );
}
}
// Update dependant on data mismatch (delta m_1)
rml_enkf_initA__(data , A , S , Cd , E , D , Ud , Wd , VdT);
// Update dependant on prior mismatch (delta m_2)
if (rml_enkf_config_get_use_prior(data->config)) {
rml_enkf_init_Csc( data );
rml_enkf_init2__(data , A , Wd , VdT);
}
// Free
matrix_free(Skm);
matrix_free( Ud );
matrix_free( VdT );
free( Wd );
}
{
double lambda_min = rml_enkf_config_get_lambda_min( data->config );
if (data->lambda < lambda_min)
data->lambda = lambda_min;
}
rml_enkf_log_close( data->rml_log );
matrix_free(Cd);
}
void rml_enkf_init_update(void * arg, const bool_vector_type * ens_mask, const matrix_type * S, const matrix_type * R, const matrix_type * dObs, const matrix_type * E, const matrix_type * D ) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
if (module_data->ens_mask)
bool_vector_free( module_data->ens_mask );
module_data->ens_mask = bool_vector_alloc_copy( ens_mask );
}
//**********************************************
// Set / Get basic types
//**********************************************
bool rml_enkf_set_int( void * arg , const char * var_name , int value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_NCOMP_KEY_) == 0)
rml_enkf_config_set_subspace_dimension(module_data->config , value);
else if (strcmp( var_name , ITER_KEY) == 0)
rml_enkf_set_iteration_nr( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
int rml_enkf_get_int( const void * arg, const char * var_name) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ITER_KEY) == 0)
return module_data->iteration_nr;
else
return -1;
}
}
bool rml_enkf_set_bool( void * arg , const char * var_name , bool value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , USE_PRIOR_KEY) == 0)
rml_enkf_config_set_use_prior( module_data->config , value);
else if (strcmp( var_name , CLEAR_LOG_KEY) == 0)
rml_enkf_log_set_clear_log( module_data->rml_log , value );
else if (strcmp( var_name , LAMBDA_RECALCULATE_KEY) == 0)
rml_enkf_config_set_lambda_recalculate( module_data->config , value );
else
name_recognized = false;
return name_recognized;
}
}
bool rml_enkf_get_bool( const void * arg, const char * var_name) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , USE_PRIOR_KEY) == 0)
return rml_enkf_config_get_use_prior( module_data->config );
else if (strcmp(var_name , CLEAR_LOG_KEY) == 0)
return rml_enkf_log_get_clear_log( module_data->rml_log );
else if (strcmp(var_name , LAMBDA_RECALCULATE_KEY) == 0)
return rml_enkf_config_get_lambda_recalculate( module_data->config );
else
return false;
}
}
bool rml_enkf_set_double( void * arg , const char * var_name , double value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_TRUNCATION_KEY_) == 0)
rml_enkf_config_set_truncation( module_data->config , value );
else if (strcmp( var_name , LAMBDA_INCREASE_FACTOR_KEY) == 0)
rml_enkf_config_set_lambda_increase_factor( module_data->config , value );
else if (strcmp( var_name , LAMBDA_REDUCE_FACTOR_KEY) == 0)
rml_enkf_config_set_lambda_decrease_factor( module_data->config , value );
else if (strcmp( var_name , LAMBDA0_KEY) == 0)
rml_enkf_config_set_lambda0( module_data->config , value );
else if (strcmp( var_name , LAMBDA_MIN_KEY) == 0)
rml_enkf_config_set_lambda_min( module_data->config , value );
else
name_recognized = false;
return name_recognized;
}
}
double rml_enkf_get_double( const void * arg, const char * var_name) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , LAMBDA_REDUCE_FACTOR_KEY) == 0)
return rml_enkf_config_get_lambda_decrease_factor(module_data->config);
if (strcmp(var_name , LAMBDA_INCREASE_FACTOR_KEY) == 0)
return rml_enkf_config_get_lambda_increase_factor(module_data->config);
if (strcmp(var_name , LAMBDA0_KEY) == 0)
return rml_enkf_config_get_lambda0(module_data->config);
if (strcmp(var_name , LAMBDA_MIN_KEY) == 0)
return rml_enkf_config_get_lambda_min(module_data->config);
if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return rml_enkf_config_get_truncation( module_data->config );
return -1;
}
}
bool rml_enkf_set_string( void * arg , const char * var_name , const char * value) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , LOG_FILE_KEY) == 0)
rml_enkf_log_set_log_file( module_data->rml_log , value );
else
name_recognized = false;
return name_recognized;
}
}
long rml_enkf_get_options( void * arg , long flag ) {
rml_enkf_data_type * module_data = rml_enkf_data_safe_cast( arg );
{
return rml_enkf_config_get_option_flags( module_data->config );
}
}
bool rml_enkf_has_var( const void * arg, const char * var_name) {
{
if (strcmp(var_name , ITER_KEY) == 0)
return true;
else if (strcmp(var_name , USE_PRIOR_KEY) == 0)
return true;
else if (strcmp(var_name , LAMBDA_INCREASE_FACTOR_KEY) == 0)
return true;
else if (strcmp(var_name , LAMBDA_REDUCE_FACTOR_KEY) == 0)
return true;
else if (strcmp(var_name , LAMBDA0_KEY) == 0)
return true;
else if (strcmp(var_name , LAMBDA_MIN_KEY) == 0)
return true;
else if (strcmp(var_name , LAMBDA_RECALCULATE_KEY) == 0)
return true;
else if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return true;
else if (strcmp(var_name , LOG_FILE_KEY) == 0)
return true;
else if (strcmp(var_name , CLEAR_LOG_KEY) == 0)
return true;
else
return false;
}
}
void * rml_enkf_get_ptr( const void * arg , const char * var_name ) {
const rml_enkf_data_type * module_data = rml_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , LOG_FILE_KEY) == 0)
return (void *) rml_enkf_log_get_log_file( module_data->rml_log );
else
return NULL;
}
}
//**********************************************
// Symbol table
//**********************************************
#ifdef INTERNAL_LINK
#define LINK_NAME RML_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "RML_ENKF",
.alloc = rml_enkf_data_alloc,
.freef = rml_enkf_data_free,
.set_int = rml_enkf_set_int ,
.set_double = rml_enkf_set_double ,
.set_bool = rml_enkf_set_bool,
.set_string = rml_enkf_set_string,
.get_options = rml_enkf_get_options ,
.initX = NULL,
.updateA = rml_enkf_updateA ,
.init_update = rml_enkf_init_update ,
.complete_update = NULL,
.has_var = rml_enkf_has_var,
.get_int = rml_enkf_get_int,
.get_double = rml_enkf_get_double,
.get_bool = rml_enkf_get_bool,
.get_ptr = rml_enkf_get_ptr,
};

View File

@ -1,91 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'rml_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ert/util/util.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
#include <rml_enkf_common.h>
// Explanation
// zzz_enkf_common_store_state( state , A ,ens_mask) assigns A to state. RESIZES state to rows(A)-by-LEN(ens_mask)
// zzz_enkf_common_recover_state(state , A ,ens_mask) assigns state to A. RESIZES A to rows(state)-by-SUM(ens_mask)
void rml_enkf_common_store_state( matrix_type * state , const matrix_type * A , const bool_vector_type * ens_mask ) {
matrix_resize( state , matrix_get_rows( A ) , bool_vector_size( ens_mask ) , false);
{
const int ens_size = bool_vector_size( ens_mask );
int active_index = 0;
for (int iens = 0; iens < ens_size; iens++) {
if (bool_vector_iget( ens_mask , iens )) {
matrix_copy_column( state , A , iens , active_index );
active_index++;
} else
matrix_set_const_column( state , iens , 0);
}
}
}
void rml_enkf_common_recover_state( const matrix_type * state , matrix_type * A , const bool_vector_type * ens_mask ) {
const int ens_size = bool_vector_size( ens_mask );
const int active_size = bool_vector_count_equal( ens_mask , true );
const int rows = matrix_get_rows( state );
matrix_resize( A , rows , active_size , false );
{
int active_index = 0;
for (int iens = 0; iens < ens_size; iens++) {
if (bool_vector_iget( ens_mask , iens )) {
matrix_copy_column( A , state , active_index , iens );
active_index++;
}
}
}
}
// Scale rows by the entries in the vector Csc
void rml_enkf_common_scaleA(matrix_type *A , const double * Csc, bool invert ){
int nrows = matrix_get_rows(A);
if (invert) {
for (int i=0; i< nrows ; i++) {
double sc= 1/Csc[i];
matrix_scale_row(A, i, sc);
}
} else {
for (int i=0; i< nrows ; i++) {
double sc= Csc[i];
matrix_scale_row(A, i, sc);
}
}
}

View File

@ -1,15 +0,0 @@
#ifndef ERT_RML_ENKF_COMMON_H
#define ERT_RML_ENKF_COMMON_H
#include <stdbool.h>
#include <ert/util/matrix.h>
#include <ert/util/rng.h>
#include <ert/util/bool_vector.h>
void rml_enkf_common_store_state( matrix_type * state , const matrix_type * A , const bool_vector_type * ens_mask );
void rml_enkf_common_recover_state( const matrix_type * state , matrix_type * A , const bool_vector_type * ens_mask );
void rml_enkf_common_scaleA(matrix_type *A , const double * Csc, bool invert );
#endif

View File

@ -1,168 +0,0 @@
/*
Copyright (C) 2015 Statoil ASA, Norway.
The file 'rml_enkf_config.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/std_enkf.h>
#include <ert/analysis/analysis_module.h>
#include <rml_enkf_config.h>
#define INVALID_SUBSPACE_DIMENSION -1
#define INVALID_TRUNCATION -1
#define DEFAULT_SUBSPACE_DIMENSION INVALID_SUBSPACE_DIMENSION
#define DEFAULT_USE_PRIOR true
#define DEFAULT_LAMBDA_INCREASE_FACTOR 4
#define DEFAULT_LAMBDA_REDUCE_FACTOR 0.1
#define DEFAULT_LAMBDA0 -1
#define DEFAULT_LAMBDA_MIN 0.01
#define DEFAULT_LAMBDA_RECALCULATE false
#define RML_ENKF_CONFIG_TYPE_ID 61400061
struct rml_enkf_config_struct {
UTIL_TYPE_ID_DECLARATION;
double truncation; // Controlled by config key: ENKF_TRUNCATION_KEY
int subspace_dimension; // Controlled by config key: ENKF_NCOMP_KEY (-1: use Truncation instead)
long option_flags;
bool use_prior; // Use exact/approximate scheme? Approximate scheme drops the "prior" term in the LM step.
double lambda0;
double lambda_min;
double lambda_decrease_factor;
double lambda_increase_factor;
bool lambda_recalculate;
};
rml_enkf_config_type * rml_enkf_config_alloc() {
rml_enkf_config_type * config = util_malloc( sizeof * config );
UTIL_TYPE_ID_INIT( config , RML_ENKF_CONFIG_TYPE_ID );
rml_enkf_config_set_truncation( config , DEFAULT_ENKF_TRUNCATION_);
rml_enkf_config_set_subspace_dimension( config , DEFAULT_SUBSPACE_DIMENSION);
rml_enkf_config_set_use_prior( config , DEFAULT_USE_PRIOR );
rml_enkf_config_set_option_flags( config , ANALYSIS_NEED_ED + ANALYSIS_UPDATE_A + ANALYSIS_ITERABLE + ANALYSIS_SCALE_DATA);
rml_enkf_config_set_lambda_min( config , DEFAULT_LAMBDA_MIN );
rml_enkf_config_set_lambda0( config , DEFAULT_LAMBDA0 );
rml_enkf_config_set_lambda_decrease_factor( config , DEFAULT_LAMBDA_REDUCE_FACTOR );
rml_enkf_config_set_lambda_increase_factor( config , DEFAULT_LAMBDA_INCREASE_FACTOR );
rml_enkf_config_set_lambda_recalculate( config , DEFAULT_LAMBDA_RECALCULATE );
return config;
}
bool rml_enkf_config_get_use_prior( const rml_enkf_config_type * config ) {
return config->use_prior;
}
void rml_enkf_config_set_use_prior( rml_enkf_config_type * config , bool use_prior) {
config->use_prior = use_prior;
}
double rml_enkf_config_get_truncation( rml_enkf_config_type * config ) {
return config->truncation;
}
void rml_enkf_config_set_truncation( rml_enkf_config_type * config , double truncation) {
config->truncation = truncation;
if (truncation > 0.0)
config->subspace_dimension = INVALID_SUBSPACE_DIMENSION;
}
int rml_enkf_config_get_subspace_dimension( rml_enkf_config_type * config ) {
return config->subspace_dimension;
}
void rml_enkf_config_set_subspace_dimension( rml_enkf_config_type * config , int subspace_dimension) {
config->subspace_dimension = subspace_dimension;
if (subspace_dimension > 0)
config->truncation = INVALID_TRUNCATION;
}
void rml_enkf_config_set_option_flags( rml_enkf_config_type * config , long flags) {
config->option_flags = flags;
}
long rml_enkf_config_get_option_flags( const rml_enkf_config_type * config ) {
return config->option_flags;
}
double rml_enkf_config_get_lambda0( rml_enkf_config_type * config ) {
return config->lambda0;
}
void rml_enkf_config_set_lambda0( rml_enkf_config_type * config , double lambda0) {
config->lambda0 = lambda0;
}
double rml_enkf_config_get_lambda_min( rml_enkf_config_type * config ) {
return config->lambda_min;
}
void rml_enkf_config_set_lambda_min( rml_enkf_config_type * config , double lambda_min) {
config->lambda_min = lambda_min;
}
double rml_enkf_config_get_lambda_increase_factor( rml_enkf_config_type * config ) {
return config->lambda_increase_factor;
}
void rml_enkf_config_set_lambda_increase_factor( rml_enkf_config_type * config , double lambda_increase_factor) {
config->lambda_increase_factor = lambda_increase_factor;
}
double rml_enkf_config_get_lambda_decrease_factor( rml_enkf_config_type * config ) {
return config->lambda_decrease_factor;
}
void rml_enkf_config_set_lambda_decrease_factor( rml_enkf_config_type * config , double lambda_decrease_factor) {
config->lambda_decrease_factor = lambda_decrease_factor;
}
bool rml_enkf_config_get_lambda_recalculate( const rml_enkf_config_type * config ) {
return config->lambda_recalculate;
}
void rml_enkf_config_set_lambda_recalculate( rml_enkf_config_type * config , bool lambda_recalculate) {
config->lambda_recalculate = lambda_recalculate;
}
void rml_enkf_config_free(rml_enkf_config_type * config) {
free( config );
}

View File

@ -1,64 +0,0 @@
/*
Copyright (C) 2015 Statoil ASA, Norway.
The file 'rml_enkf_config.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef RML_ENKF_CONFIG_H
#define RML_ENKF_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rml_enkf_config_struct rml_enkf_config_type;
rml_enkf_config_type * rml_enkf_config_alloc();
void rml_enkf_config_free(rml_enkf_config_type * config);
int rml_enkf_config_get_subspace_dimension( rml_enkf_config_type * config );
void rml_enkf_config_set_subspace_dimension( rml_enkf_config_type * config , int subspace_dimension);
double rml_enkf_config_get_truncation( rml_enkf_config_type * config );
void rml_enkf_config_set_truncation( rml_enkf_config_type * config , double truncation);
bool rml_enkf_config_get_use_prior( const rml_enkf_config_type * config );
void rml_enkf_config_set_use_prior( rml_enkf_config_type * config , bool use_prior);
void rml_enkf_config_set_option_flags( rml_enkf_config_type * config , long flags);
long rml_enkf_config_get_option_flags( const rml_enkf_config_type * config );
double rml_enkf_config_get_lambda0( rml_enkf_config_type * config );
void rml_enkf_config_set_lambda0( rml_enkf_config_type * config , double lambda0);
double rml_enkf_config_get_lambda_min( rml_enkf_config_type * config );
void rml_enkf_config_set_lambda_min( rml_enkf_config_type * config , double lambda_min);
double rml_enkf_config_get_lambda_increase_factor( rml_enkf_config_type * config );
void rml_enkf_config_set_lambda_increase_factor( rml_enkf_config_type * config , double lambda_increase_factor);
double rml_enkf_config_get_lambda_decrease_factor( rml_enkf_config_type * config );
void rml_enkf_config_set_lambda_decrease_factor( rml_enkf_config_type * config , double lambda_decrease_factor);
bool rml_enkf_config_get_lambda_recalculate( const rml_enkf_config_type * config );
void rml_enkf_config_set_lambda_recalculate( rml_enkf_config_type * config , bool lambda_recalculate);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,110 +0,0 @@
/*
Copyright (C) 2015 Statoil ASA, Norway.
The file 'rml_enkf_log.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ert/util/util.h>
#include <rml_enkf_log.h>
#define DEFAULT_LOG_FILE "rml_enkf.out"
#define DEFAULT_CLEAR_LOG true
struct rml_enkf_log_struct {
bool clear_log;
char * log_file;
FILE * log_stream;
};
rml_enkf_log_type * rml_enkf_log_alloc() {
rml_enkf_log_type * rml_log = util_malloc( sizeof * rml_log );
rml_log->log_file = NULL;
rml_log->log_stream = NULL;
rml_enkf_log_set_clear_log( rml_log , DEFAULT_CLEAR_LOG );
rml_enkf_log_set_log_file( rml_log, DEFAULT_LOG_FILE );
return rml_log;
}
bool rml_enkf_log_get_clear_log( const rml_enkf_log_type * data ) {
return data->clear_log;
}
void rml_enkf_log_set_clear_log( rml_enkf_log_type * data , bool clear_log) {
data->clear_log = clear_log;
}
void rml_enkf_log_set_log_file( rml_enkf_log_type * data , const char * log_file ) {
data->log_file = util_realloc_string_copy( data->log_file , log_file );
}
const char * rml_enkf_log_get_log_file( const rml_enkf_log_type * data) {
return data->log_file;
}
void rml_enkf_log_free(rml_enkf_log_type * rml_log) {
rml_enkf_log_close( rml_log );
util_safe_free( rml_log->log_file );
free( rml_log );
}
void rml_enkf_log_open( rml_enkf_log_type * rml_log , int iteration_nr ) {
if (rml_log->log_file) {
if ( iteration_nr == 0) {
if (rml_log->clear_log)
rml_log->log_stream = util_mkdir_fopen( rml_log->log_file , "w");
else
rml_log->log_stream = util_mkdir_fopen( rml_log->log_file , "a");
} else
rml_log->log_stream = util_fopen( rml_log->log_file , "a");
}
}
bool rml_enkf_log_is_open( const rml_enkf_log_type * rml_log ) {
if (rml_log->log_stream)
return true;
else
return false;
}
void rml_enkf_log_close( rml_enkf_log_type * rml_log ) {
if (rml_log->log_stream)
fclose( rml_log->log_stream );
rml_log->log_stream = NULL;
}
void rml_enkf_log_line( rml_enkf_log_type * rml_log , const char * fmt , ...) {
if (rml_log->log_stream) {
va_list ap;
va_start(ap , fmt);
vfprintf( rml_log->log_stream , fmt , ap );
va_end( ap );
}
}

View File

@ -1,45 +0,0 @@
/*
Copyright (C) 2015 Statoil ASA, Norway.
The file 'rml_enkf_log.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef RML_ENKF_LOG_H
#define RML_ENKF_LOG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
typedef struct rml_enkf_log_struct rml_enkf_log_type;
rml_enkf_log_type * rml_enkf_log_alloc();
void rml_enkf_log_free(rml_enkf_log_type * rml_log);
bool rml_enkf_log_get_clear_log( const rml_enkf_log_type * data );
void rml_enkf_log_set_clear_log( rml_enkf_log_type * data , bool clear_log);
void rml_enkf_log_set_log_file( rml_enkf_log_type * data , const char * log_file );
const char * rml_enkf_log_get_log_file( const rml_enkf_log_type * data);
void rml_enkf_log_open( rml_enkf_log_type * rml_log , int iteration_nr );
void rml_enkf_log_close( rml_enkf_log_type * rml_log );
void rml_enkf_log_line( rml_enkf_log_type * rml_log , const char * fmt , ...);
bool rml_enkf_log_is_open( const rml_enkf_log_type * rml_log );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,245 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
This file is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/std_enkf.h>
#define PREFIX_KEY "PREFIX"
#define DEFAULT_PREFIX "debug"
/*
A random 'magic' integer id which is used for run-time type checking
of the input data.
*/
#define STD_ENKF_DEBUG_TYPE_ID 269923
typedef struct std_enkf_debug_data_struct std_enkf_debug_data_type;
struct std_enkf_debug_data_struct {
UTIL_TYPE_ID_DECLARATION;
std_enkf_data_type * std_data;
char * prefix;
int update_count;
};
static UTIL_SAFE_CAST_FUNCTION_CONST( std_enkf_debug_data , STD_ENKF_DEBUG_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION( std_enkf_debug_data , STD_ENKF_DEBUG_TYPE_ID )
void std_enkf_debug_data_set_prefix( std_enkf_debug_data_type * data , const char * prefix ) {
data->prefix = util_realloc_string_copy( data->prefix , prefix );
}
void * std_enkf_debug_data_alloc( rng_type * rng) {
std_enkf_debug_data_type * data = util_malloc( sizeof * data );
UTIL_TYPE_ID_INIT( data , STD_ENKF_DEBUG_TYPE_ID );
data->std_data = std_enkf_data_alloc( rng );
data->update_count = 0;
data->prefix = NULL;
std_enkf_debug_data_set_prefix( data , DEFAULT_PREFIX );
return data;
}
void std_enkf_debug_data_free( void * arg ) {
std_enkf_debug_data_type * data = std_enkf_debug_data_safe_cast( arg );
std_enkf_data_free( data->std_data );
free( data );
}
void std_enkf_debug_save_matrix( const matrix_type * m , const char * path , const char * file, bool transpose) {
char * filename = util_alloc_filename( path , file , NULL );
if (transpose) {
matrix_type * mt = matrix_alloc_transpose( m );
matrix_dump_csv(mt,filename);
matrix_free( mt );
} else
matrix_dump_csv(m , filename);
free( filename );
}
void std_enkf_debug_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D) {
std_enkf_debug_data_type * data = std_enkf_debug_data_safe_cast( module_data );
char * debug_path = util_alloc_sprintf( "%s/%d" , data->prefix , data->update_count );
std_enkf_data_type * std_data = data->std_data;
util_make_path( debug_path );
std_enkf_debug_save_matrix( A , debug_path , "prior_ert.csv" , true);
std_enkf_debug_save_matrix( S , debug_path , "S.csv" , true);
std_enkf_debug_save_matrix( S , debug_path , "simResponses.csv" , true);
std_enkf_debug_save_matrix( E , debug_path , "E.csv" , true);
std_enkf_debug_save_matrix( E , debug_path , "measurementErrors.csv" , true);
std_enkf_debug_save_matrix( R , debug_path , "R.csv" , true);
std_enkf_debug_save_matrix( D , debug_path , "D.csv" , true);
{
matrix_type * value = matrix_alloc_sub_copy( dObs , 0 , 0 , matrix_get_rows( dObs ) , 1 );
matrix_type * std = matrix_alloc_sub_copy( dObs , 0 , 1 , matrix_get_rows( dObs ) , 1 );
std_enkf_debug_save_matrix( value , debug_path , "observations.csv", true);
std_enkf_debug_save_matrix( std , debug_path , "observations_std.csv", true);
matrix_free( value );
matrix_free( std );
}
std_enkf_initX( std_data , X , A , S , R , dObs , E , D );
{
matrix_type * posterior = matrix_alloc_matmul( A , X );
std_enkf_debug_save_matrix( posterior , debug_path , "posterior_ert.csv" , true);
matrix_free( posterior );
}
data->update_count++;
}
bool std_enkf_debug_set_double( void * arg , const char * var_name , double value) {
std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast( arg );
return std_enkf_set_double( module_data->std_data , var_name , value );
}
bool std_enkf_debug_set_int( void * arg , const char * var_name , int value) {
std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast( arg );
return std_enkf_set_int( module_data->std_data , var_name , value );
}
bool std_enkf_debug_set_bool( void * arg , const char * var_name , bool value) {
std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast( arg );
return std_enkf_set_bool( module_data->std_data , var_name , value );
}
bool std_enkf_debug_set_string( void * arg , const char * var_name , const char * value) {
std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast( arg );
if (strcmp(var_name, PREFIX_KEY) == 0) {
std_enkf_debug_data_set_prefix( module_data , value );
return true;
} else
return false;
}
long std_enkf_debug_get_options( void * arg , long flag ) {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
long options = std_enkf_get_options( module_data->std_data , flag );
options |= ANALYSIS_USE_A;
return options;
}
bool std_enkf_debug_has_var( const void * arg, const char * var_name) {
if (strcmp(var_name , PREFIX_KEY) == 0)
return true;
else {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
return std_enkf_has_var( module_data->std_data , var_name );
}
}
double std_enkf_debug_get_double( const void * arg, const char * var_name) {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
return std_enkf_get_double( module_data->std_data , var_name );
}
int std_enkf_debug_get_int( const void * arg, const char * var_name) {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
return std_enkf_get_int( module_data->std_data , var_name );
}
bool std_enkf_debug_get_bool( const void * arg, const char * var_name) {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
return std_enkf_get_bool( module_data->std_data , var_name );
}
void * std_enkf_debug_get_ptr( const void * arg, const char * var_name) {
const std_enkf_debug_data_type * module_data = std_enkf_debug_data_safe_cast_const( arg );
if (strcmp( var_name , PREFIX_KEY) == 0)
return (void *) module_data->prefix;
else
return NULL;
}
#ifdef INTERNAL_LINK
#define LINK_NAME STD_ENKF_DEBUG
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "STD_ENKF_DEBUG_DEBUG",
.alloc = std_enkf_debug_data_alloc,
.freef = std_enkf_debug_data_free,
.set_int = std_enkf_debug_set_int ,
.set_double = std_enkf_debug_set_double ,
.set_bool = std_enkf_debug_set_bool,
.set_string = std_enkf_debug_set_string,
.get_options = std_enkf_debug_get_options ,
.initX = std_enkf_debug_initX ,
.updateA = NULL,
.init_update = NULL,
.complete_update = NULL,
.has_var = std_enkf_debug_has_var,
.get_int = std_enkf_debug_get_int,
.get_double = std_enkf_debug_get_double,
.get_bool = std_enkf_debug_get_bool,
.get_ptr = std_enkf_debug_get_ptr
};

View File

@ -1,5 +0,0 @@
add_executable(analysis_rml_enkf_common analysis_rml_enkf_common.c ../rml_enkf_common.c)
target_link_libraries( analysis_rml_enkf_common analysis util test_util )
add_test( analysis_rml_enkf_common ${EXECUTABLE_OUTPUT_PATH}/analysis_rml_enkf_common )

View File

@ -1,133 +0,0 @@
/*
Copyright (C) 2014 Statoil ASA, Norway.
The file 'analysis_rml_common.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <ert/util/test_util.h>
#include <ert/util/rng.h>
#include <ert/util/mzran.h>
#include <ert/util/matrix.h>
#include <ert/util/bool_vector.h>
#include <rml_enkf_common.h>
void test_store_recover_state() {
rng_type * rng = rng_alloc( MZRAN , INIT_DEFAULT );
int ens_size = 10;
int active_size = 8;
int rows = 100;
matrix_type * state = matrix_alloc(1,1);
bool_vector_type * ens_mask = bool_vector_alloc(ens_size , false);
matrix_type * A = matrix_alloc( rows , active_size);
matrix_type * A2 = matrix_alloc( rows, active_size );
matrix_type * A3 = matrix_alloc( 1,1 );
for (int i=0; i < active_size; i++)
bool_vector_iset( ens_mask , i + 1 , true );
matrix_random_init(A , rng);
rml_enkf_common_store_state( state , A , ens_mask );
test_assert_int_equal( matrix_get_rows( state ) , rows );
test_assert_int_equal( matrix_get_columns( state ) , ens_size );
{
int g;
int a = 0;
for (g=0; g < ens_size; g++) {
if (bool_vector_iget( ens_mask , g )) {
test_assert_true( matrix_columns_equal( state , g , A , a ));
a++;
}
}
}
rml_enkf_common_recover_state( state , A2 , ens_mask);
rml_enkf_common_recover_state( state , A3 , ens_mask);
test_assert_true( matrix_equal( A , A2 ));
test_assert_true( matrix_equal( A , A3 ));
bool_vector_free( ens_mask );
matrix_free( state );
matrix_free( A );
}
void test_scaleA() {
const int N = 10;
matrix_type * m1 = matrix_alloc(N , N);
matrix_type * m2 = matrix_alloc(N , N);
double * csc = util_calloc( N , sizeof * csc );
rng_type * rng = rng_alloc( MZRAN , INIT_DEFAULT );
matrix_random_init( m1 , rng );
matrix_assign(m2 , m1);
test_assert_true( matrix_equal(m1 , m2));
{
for (int i=0; i < N; i++)
csc[i] = (i + 2);
}
rml_enkf_common_scaleA( m1 , csc , false );
{
int row,col;
for (row = 0; row < N; row++) {
for (col=0; col < N; col++) {
double v1 = matrix_iget(m1 , row , col);
double v2 = matrix_iget(m2 , row , col);
test_assert_double_equal( v1 , v2 * csc[row] );
}
}
}
rml_enkf_common_scaleA( m2 , csc , false );
test_assert_true( matrix_equal(m1 , m2));
rml_enkf_common_scaleA( m2 , csc , true );
{
int row,col;
for (row = 0; row < N; row++) {
for (col=0; col < N; col++) {
double v1 = matrix_iget(m1 , row , col);
double v2 = matrix_iget(m2 , row , col);
test_assert_double_equal( v1 , v2 * csc[row] );
}
}
}
rml_enkf_common_scaleA( m1 , csc , true );
test_assert_true( matrix_equal(m1 , m2));
rng_free( rng );
matrix_free(m1);
matrix_free(m2);
free( csc );
}
int main(int argc , char ** argv) {
test_store_recover_state();
test_scaleA();
exit(0);
}

View File

@ -1,8 +0,0 @@
set (destination ${CMAKE_INSTALL_PREFIX}/bin)
install(PROGRAMS ert_module DESTINATION ${destination})
if (INSTALL_GROUP)
install(CODE "EXECUTE_PROCESS(COMMAND chgrp ${INSTALL_GROUP} ${destination}/ert_module)")
install(CODE "EXECUTE_PROCESS(COMMAND chmod g+w ${destination}/ert_module)")
endif()

View File

@ -1,239 +0,0 @@
#!/usr/bin/env python
import sys
import os
import os.path
from optparse import OptionParser
ert_root = os.path.realpath( os.path.join(os.path.dirname( os.path.realpath( os.path.abspath( __file__))) , "../") )
#-----------------------------------------------------------------
default_lib_list = ["analysis" , "ert_util"]
default_define_list = ["HAVE_PTHREAD" , "COMPILER_GCC"]
CFLAGS = "-std=gnu99 -O2 -Wall -fpic -g"
LDFLAGS_list = ["-shared"]
CC = "gcc"
LD = CC
#-----------------------------------------------------------------
c_file = 0
header_file = 1
object_file = 2
other = 3
file_types = {".o" : object_file ,
".h" : header_file ,
".c" : c_file }
def base_name(file):
(name,ext) = os.path.split( file )
return name
def file_type( file ):
name,ext = os.path.splitext( file )
return file_types.get( ext , other )
def object_file_name( file ):
(name,ext) = os.path.splitext( file )
return "%s.o" % name
def make_LDFLAGS( use_rpath , lib_path_list):
if use_rpath:
LDFLAGS_list.append("-Wl,--enable-new-dtags")
for path in lib_path_list:
LDFLAGS_list.append("-Wl,-rpath,%s" % path)
LDFLAGS_list.append("-Wl,-soname,")
return " ".join(LDFLAGS_list)
def make_XFLAG( X , def_list ):
FLAG = ""
for d in def_list:
FLAG += "-%s%s " % (X , d)
return FLAG
def compile_file( file , IFLAG , DFLAG , verbose):
target = object_file_name( file )
if os.path.exists( target ):
os.unlink( target )
cmd = "%s %s %s %s -c %s -o %s" % (CC , CFLAGS , IFLAG , DFLAG , file , target)
if verbose:
print "Compiling: %s" % cmd
os.system( cmd )
if os.path.exists( target ):
return target
else:
sys.exit("Compile cmd:%s failed" % cmd)
def link( soname , filename , object_list , LDFLAGS , LFLAG , lFLAG , verbose):
object_string = ""
for obj in object_list:
object_string += "%s " % obj
cmd = "%s %s%s -o %s %s %s %s" % ( LD , LDFLAGS , soname , filename , object_string , LFLAG , lFLAG)
if verbose:
print "Linking : %s" % cmd
if os.path.exists( filename ):
os.unlink( filename )
os.system(cmd)
if os.path.exists( filename ):
return True
else:
return False
usage = """
The ert_module script is a small convenience script to
compile C source code into an analysis module which can
be loaded by ert. The script is controlled by commandline
arguments:
1. The first argument should be the name of the module
you are creating, an extension .so will be appended.
2. List the source files you want to include, the
files should have extension .c. In addition you can
include object files which have been compiled by
other means, the object files should have
extension .o
3. Optionally you can pass -I and -D options which are
passed to the compiler; and -l and -L options which
are passed to the linker.
Example:
ert_module my_module my_src1.c my_src2.c f90_object1.o f90_object2.o -I/path -DFAST=Yes -L/path/to/lib -lfm -lz
Will create a module 'my_module' based on the src files my_src1.c
and my_src2.c; in addition the object files f90_object1.o and
f90_object2.o will be included in the final module.
-----------------------------------------------------------------
To compile the module code you will typically need the include files
and libraries from an existing ert installation. By default the
ert_module script will locate the ert installation based on the
location of the script, but you can pass the option:
--ert-root=/path/where/ert/is/installed
The --ert-root option should point to a directory containing the
lib64/ and include/ directories of a binary etr distribution. In
addition to --ert-root you can use the normal -L/path/to/lib option to
send in additional link path arguments.
By default the path to shared libraries will not be embedded in the
resulting module, but by passing the option --use-rpath you can tell
the script to embed these paths in the final shared object.
-----------------------------------------------------------------
Options summary:
-L/path/to/lib: Include the path /path/to/lib in the linker path
-llib1 : Link with the library lib1
-I/include : Include the path /include in the compiler include path.
--ert-root=/path/to/ert : Use this is as root for ert headers
and libraries. [Default: inferred from location of script]
--use-rpath : Embed library paths in shared objects. Default off.
--exclude-ert: Do not use any ert default libraries or headers
Default flags:
Compile: %s %s %s
Link: %s %s %s
""" % (CC,
make_XFLAG( "I" , ["./" , "%s/include" % ert_root]) ,
make_XFLAG( "D" , default_define_list) ,
LD ,
make_XFLAG("L" , ["%s/lib64" % ert_root]) ,
make_XFLAG("l" , default_lib_list))
parser = OptionParser( usage )
parser.add_option("--ert-root" , dest="ert_root" , action="store")
parser.add_option("-I" , dest = "include_path_list", action = "append" , default = [])
parser.add_option("-D" , dest = "define_list" , action = "append" , default = [])
parser.add_option("-L" , dest = "lib_path_list" , action = "append" , default = [])
parser.add_option("-l" , dest = "lib_list" , action = "append" , default = [])
parser.add_option("--exclude-ert" , dest = "exclude_ert" , action="store_true" , default = False)
parser.add_option("--use-rpath" , dest="use_rpath" , action="store_true" , default = False)
parser.add_option("--silent" , dest="silent" , action="store_true" , default = False)
(options , args) = parser.parse_args()
if len(args) == 0:
sys.exit( usage )
if options.ert_root:
ert_root = options.ert_root
if options.exclude_ert:
default_include_path_list = ["./"]
default_lib_path_list = []
default_lib_list = []
else:
default_include_path_list = ["./" , "%s/include" % ert_root]
default_lib_path_list = ["%s/lib64" % ert_root]
default_lib_list = default_lib_list
# What is supplied as commandline options should take presedence, this
# implies that it should be first OR last on the commandline.
include_path_list = options.include_path_list + default_include_path_list
define_list = default_define_list + options.define_list
lib_list = options.lib_list + default_lib_list
lib_path_list = options.lib_path_list + default_lib_path_list
verbose = not options.silent
LDFLAGS = make_LDFLAGS( options.use_rpath , lib_path_list)
input_name = args[0]
(path , tmp ) = os.path.split( input_name )
(module , ext) = os.path.splitext( tmp )
soname = "%s.so" % module
if path:
filename = "%s/%s.so" % (path , module)
if not os.path.exists( path ):
os.makedirs( path )
else:
filename = "%s.so" % module
#-----------------------------------------------------------------
IFLAG = make_XFLAG( "I" , include_path_list )
DFLAG = make_XFLAG( "D" , define_list )
LFLAG = make_XFLAG( "L" , lib_path_list )
lFLAG = make_XFLAG( "l" , lib_list )
object_list = []
for arg in args[1:]:
if file_type( arg ) == c_file:
object_list.append( compile_file( arg , IFLAG , DFLAG , verbose) )
elif file_type( arg ) == object_file:
object_list.append( arg )
else:
print "** Warning: ignoring file:%s" % arg
if link( soname , filename , object_list , LDFLAGS , LFLAG , lFLAG , verbose):
sys.exit()
else:
sys.exit("Creating library failed")

View File

@ -1,33 +0,0 @@
# Common libanalysis library
set( source_files analysis_module.c enkf_linalg.c std_enkf.c sqrt_enkf.c cv_enkf.c bootstrap_enkf.c null_enkf.c fwd_step_enkf.c fwd_step_log.c module_data_block.c module_data_block_vector.c module_obs_block.c module_obs_block_vector.c module_info.c)
set( header_files analysis_module.h enkf_linalg.h analysis_table.h std_enkf.h fwd_step_enkf.h fwd_step_log.h module_data_block.h module_data_block_vector.h module_obs_block.h module_obs_block_vector.h module_info.h)
add_library( analysis SHARED ${source_files} )
set_target_properties( analysis PROPERTIES COMPILE_DEFINITIONS INTERNAL_LINK)
set_target_properties( analysis PROPERTIES VERSION ${ERT_VERSION_MAJOR}.${ERT_VERSION_MINOR} SOVERSION ${ERT_VERSION_MAJOR} )
target_link_libraries( analysis ert_util )
target_link_libraries( analysis dl )
if (USE_RUNPATH)
add_runpath( analysis )
endif()
#-----------------------------------------------------------------
if (ERT_USE_OPENMP)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenMP_SHARED_LINKER_FLAGS}")
endif()
if (INSTALL_ERT)
install(TARGETS analysis DESTINATION ${CMAKE_INSTALL_LIBDIR})
#install(TARGETS rml_enkf DESTINATION ${CMAKE_INSTALL_LIBDIR})
foreach(header ${header_files})
install(FILES ../include/ert/analysis/${header} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ert/analysis)
endforeach()
endif()

View File

@ -1,463 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'analysis_module.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <dlfcn.h>
#include <ert/util/matrix.h>
#include <ert/util/util.h>
#include <ert/util/rng.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#define ANALYSIS_MODULE_TYPE_ID 6610123
struct analysis_module_struct {
UTIL_TYPE_ID_DECLARATION;
void * lib_handle;
void * module_data;
char * symbol_table;
char * lib_name;
analysis_free_ftype * freef;
analysis_alloc_ftype * alloc;
analysis_initX_ftype * initX;
analysis_updateA_ftype * updateA;
analysis_init_update_ftype * init_update;
analysis_complete_update_ftype * complete_update;
analysis_get_options_ftype * get_options;
analysis_set_int_ftype * set_int;
analysis_set_double_ftype * set_double;
analysis_set_bool_ftype * set_bool;
analysis_set_string_ftype * set_string;
analysis_has_var_ftype * has_var;
analysis_get_int_ftype * get_int;
analysis_get_double_ftype * get_double;
analysis_get_bool_ftype * get_bool;
analysis_get_ptr_ftype * get_ptr;
bool internal;
char * user_name; /* String used to identify this module for the user; not used in
the linking process. */
};
static analysis_module_type * analysis_module_alloc_empty( const char * symbol_table , const char * lib_name) {
analysis_module_type * module = util_malloc( sizeof * module );
UTIL_TYPE_ID_INIT( module , ANALYSIS_MODULE_TYPE_ID );
module->lib_handle = NULL;
module->initX = NULL;
module->updateA = NULL;
module->set_int = NULL;
module->set_bool = NULL;
module->set_double = NULL;
module->set_string = NULL;
module->module_data = NULL;
module->init_update = NULL;
module->complete_update = NULL;
module->has_var = NULL;
module->get_int = NULL;
module->get_double = NULL;
module->get_bool = NULL;
module->get_ptr = NULL;
module->alloc = NULL;
module->user_name = NULL;
module->symbol_table = util_alloc_string_copy( symbol_table );
module->lib_name = util_alloc_string_copy( lib_name );
return module;
}
static bool analysis_module_internal_check( analysis_module_type * module ) {
if (!module->user_name)
fprintf(stderr,"Invalid module loaded from lib:%s / symbol_table:%s - name not set\n", module->lib_name , module->symbol_table);
return true;
}
static analysis_module_type * analysis_module_alloc__( rng_type * rng ,
const analysis_table_type * table ,
const char * symbol_table ,
const char * lib_name ,
void * lib_handle ) {
analysis_module_type * module = analysis_module_alloc_empty( symbol_table , lib_name );
module->lib_handle = lib_handle;
module->initX = table->initX;
module->updateA = table->updateA;
module->init_update = table->init_update;
module->complete_update = table->complete_update;
module->set_int = table->set_int;
module->set_double = table->set_double;
module->set_string = table->set_string;
module->set_bool = table->set_bool;
module->alloc = table->alloc;
module->freef = table->freef;
module->get_options = table->get_options;
module->has_var = table->has_var;
module->get_int = table->get_int;
module->get_double = table->get_double;
module->get_bool = table->get_bool;
module->get_ptr = table->get_ptr;
analysis_module_set_name( module , table->name );
if (module->alloc)
module->module_data = module->alloc( rng );
if (!analysis_module_internal_check( module )) {
fprintf(stderr,"** Warning loading module: %s failed - internal inconsistency\n", module->user_name);
analysis_module_free( module );
module = NULL;
}
return module;
}
static analysis_module_type * analysis_module_alloc( rng_type * rng ,
const char * libname ,
const char * table_name ,
bool verbose,
analysis_module_load_status_enum * load_status) {
analysis_module_type * module = NULL;
void * lib_handle = dlopen( libname , RTLD_NOW );
if (lib_handle != NULL) {
analysis_table_type * analysis_table = (analysis_table_type *) dlsym( lib_handle , table_name );
if (analysis_table != NULL) {
*load_status = LOAD_OK;
module = analysis_module_alloc__( rng , analysis_table , table_name , libname , lib_handle );
} else {
*load_status = LOAD_SYMBOL_TABLE_NOT_FOUND;
if (verbose)
fprintf(stderr , "Failed to load symbol table:%s Error:%s \n",table_name , dlerror());
}
if (module == NULL)
dlclose( lib_handle );
} else {
*load_status = DLOPEN_FAILURE;
if (verbose)
fprintf(stderr , "Failed to load library:%s Error:%s \n",libname , dlerror());
}
if (module != NULL) {
if (libname == NULL)
module->internal = true;
else
module->internal = false;
}
return module;
}
analysis_module_type * analysis_module_alloc_internal__( rng_type * rng , const char * symbol_table , bool verbose , analysis_module_load_status_enum * load_status) {
return analysis_module_alloc( rng , NULL , symbol_table , verbose , load_status);
}
analysis_module_type * analysis_module_alloc_internal( rng_type * rng , const char * symbol_table ) {
analysis_module_load_status_enum load_status;
return analysis_module_alloc_internal__( rng , symbol_table , true , &load_status);
}
analysis_module_type * analysis_module_alloc_external__(rng_type * rng , const char * lib_name , bool verbose , analysis_module_load_status_enum * load_status) {
return analysis_module_alloc( rng , lib_name , EXTERNAL_MODULE_NAME , verbose , load_status);
}
analysis_module_type * analysis_module_alloc_external( rng_type * rng , const char * lib_name) {
analysis_module_load_status_enum load_status;
return analysis_module_alloc_external__( rng , lib_name , true , &load_status);
}
/*****************************************************************/
const char * analysis_module_get_name( const analysis_module_type * module ) {
return module->user_name;
}
void analysis_module_set_name( analysis_module_type * module , const char * name) {
module->user_name = util_realloc_string_copy( module->user_name , name );
}
const char * analysis_module_get_table_name( const analysis_module_type * module) {
return module->symbol_table;
}
const char * analysis_module_get_lib_name( const analysis_module_type * module) {
return module->lib_name;
}
bool analysis_module_internal( const analysis_module_type * module ) {
return module->internal;
}
/*****************************************************************/
static UTIL_SAFE_CAST_FUNCTION( analysis_module , ANALYSIS_MODULE_TYPE_ID )
UTIL_IS_INSTANCE_FUNCTION( analysis_module , ANALYSIS_MODULE_TYPE_ID )
void analysis_module_free( analysis_module_type * module ) {
if (module->freef != NULL)
module->freef( module->module_data );
util_safe_free( module->lib_name );
free( module->user_name );
free( module->symbol_table );
dlclose( module->lib_handle );
free( module );
}
void analysis_module_free__( void * arg) {
analysis_module_type * module = analysis_module_safe_cast( arg );
analysis_module_free( module );
}
/*****************************************************************/
/* Update functions */
void analysis_module_initX(analysis_module_type * module ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ) {
module->initX(module->module_data , X , A , S , R , dObs , E , D );
}
void analysis_module_updateA(analysis_module_type * module ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info) {
module->updateA(module->module_data , A , S , R , dObs , E , D, module_info);
}
void analysis_module_init_update( analysis_module_type * module ,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D ) {
if (module->init_update != NULL)
module->init_update( module->module_data , ens_mask , S , R , dObs , E , D);
}
void analysis_module_complete_update( analysis_module_type * module ) {
if (module->complete_update != NULL)
module->complete_update( module->module_data );
}
/*****************************************************************/
static bool analysis_module_set_int(analysis_module_type * module , const char * flag , int value) {
if (module->set_int != NULL)
return module->set_int( module->module_data , flag , value );
else
return false;
}
static bool analysis_module_set_double(analysis_module_type * module , const char * var , double value) {
if (module->set_double != NULL)
return module->set_double( module->module_data , var , value );
else
return false;
}
static bool analysis_module_set_bool(analysis_module_type * module , const char * var , bool value) {
if (module->set_bool != NULL)
return module->set_bool( module->module_data , var , value );
else
return false;
}
static bool analysis_module_set_string(analysis_module_type * module , const char * var , const char * value) {
if (module->set_string != NULL)
return module->set_string( module->module_data , var , value );
else
return false;
}
/*
The input value typically comes from the configuration system and
is in terms of a string, irrespective of the fundamental type of
the underlying parameter. The algorithm for setting the parameter
tries datatypes as follows: integer - double - string.
For the numeric datatypes the algorithm is two step:
1. Try the conversion string -> numeric.
2. Try calling the analysis_module_set_xxx() function.
Observe that this implies that the same variable name can NOT be
used for different variable types.
*/
bool analysis_module_set_var( analysis_module_type * module , const char * var_name , const char * string_value ) {
bool set_ok = false;
{
int int_value;
if (util_sscanf_int( string_value , &int_value ))
set_ok = analysis_module_set_int( module , var_name , int_value );
if (set_ok)
return true;
}
{
double double_value;
if (util_sscanf_double( string_value , &double_value ))
set_ok = analysis_module_set_double( module , var_name , double_value );
if (set_ok)
return true;
}
{
bool bool_value;
if (util_sscanf_bool( string_value , &bool_value))
set_ok = analysis_module_set_bool( module , var_name , bool_value );
if (set_ok)
return true;
}
set_ok = analysis_module_set_string( module , var_name , string_value );
if (!set_ok)
fprintf(stderr,"** Warning: failed to set %s=%s for analysis module:%s\n", var_name , string_value , module->user_name);
return set_ok;
}
bool analysis_module_check_option( const analysis_module_type * module , long flag) {
if ((flag & module->get_options( module->module_data , flag )) == flag)
return true;
else
return false;
}
bool analysis_module_has_var( const analysis_module_type * module , const char * var) {
if (module->has_var)
return module->has_var( module->module_data , var );
else
return false;
}
int analysis_module_get_int( const analysis_module_type * module , const char * var) {
if (analysis_module_has_var( module , var )) {
if (module->get_int != NULL)
return module->get_int( module->module_data , var );
else
util_exit("%s: Tried to get integer variable:%s from module:%s - get_int() method not implemented for this module\n" , __func__ , var , module->user_name);
} else
util_exit("%s: Tried to get integer variable:%s from module:%s - module does not support this variable \n" , __func__ , var , module->user_name);
return 0;
}
bool analysis_module_get_bool( const analysis_module_type * module , const char * var) {
if (analysis_module_has_var( module , var )) {
if (module->get_bool != NULL)
return module->get_bool( module->module_data , var );
else
util_exit("%s: Tried to get bool variable:%s from module:%s - get_int() method not implemented for this module\n" , __func__ , var , module->user_name);
} else
util_exit("%s: Tried to get bool variable:%s from module:%s - module does not support this variable \n" , __func__ , var , module->user_name);
return false;
}
double analysis_module_get_double( const analysis_module_type * module , const char * var) {
if (analysis_module_has_var( module , var )) {
if (module->get_double != NULL)
return module->get_double( module->module_data , var );
else
util_exit("%s: Tried to get double variable:%s from module:%s - get_double() method not implemented for this module\n" , __func__ , var , module->user_name);
} else
util_exit("%s: Tried to get double variable:%s from module:%s - module does not support this variable \n" , __func__ , var , module->user_name);
return 0;
}
void * analysis_module_get_ptr( const analysis_module_type * module , const char * var) {
if (analysis_module_has_var( module , var )) {
if (module->get_double != NULL)
return module->get_ptr( module->module_data , var );
else
util_exit("%s: Tried to get pointer variable:%s from module:%s - get_ptr() method not implemented for this module\n" , __func__ , var , module->user_name);
} else
util_exit("%s: Tried to get pointer variable:%s from module:%s - module does not support this variable \n" , __func__ , var , module->user_name);
return NULL;
}
/*****************************************************************/
const char * analysis_module_flag_enum_iget( int index, int * value) {
return util_enum_iget( index , ANALYSIS_MODULE_FLAG_ENUM_SIZE , (const util_enum_element_type []) { ANALYSIS_MODULE_FLAG_ENUM_DEFS }, value);
}

View File

@ -1,300 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'bootstrap_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ert/util/int_vector.h>
#include <ert/util/util.h>
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/analysis/std_enkf.h>
#include <ert/analysis/cv_enkf.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/enkf_linalg.h>
#define BOOTSTRAP_ENKF_TYPE_ID 741223
#define INVALID_SUBSPACE_DIMENSION -1
#define INVALID_TRUNCATION -1
#define DEFAULT_TRUNCATION 0.95
#define DEFAULT_NCOMP INVALID_SUBSPACE_DIMENSION
#define DEFAULT_DO_CV false
#define DEFAULT_NFOLDS 10
#define NFOLDS_KEY "BOOTSTRAP_NFOLDS"
typedef struct {
UTIL_TYPE_ID_DECLARATION;
std_enkf_data_type * std_enkf_data;
cv_enkf_data_type * cv_enkf_data;
rng_type * rng;
long option_flags;
bool doCV;
} bootstrap_enkf_data_type;
static UTIL_SAFE_CAST_FUNCTION( bootstrap_enkf_data , BOOTSTRAP_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION_CONST( bootstrap_enkf_data , BOOTSTRAP_ENKF_TYPE_ID )
void bootstrap_enkf_set_doCV( bootstrap_enkf_data_type * data , bool doCV) {
data->doCV = doCV;
}
void bootstrap_enkf_set_truncation( bootstrap_enkf_data_type * boot_data , double truncation ) {
std_enkf_set_truncation( boot_data->std_enkf_data , truncation );
cv_enkf_set_truncation( boot_data->cv_enkf_data , truncation );
}
void bootstrap_enkf_set_subspace_dimension( bootstrap_enkf_data_type * boot_data , int ncomp) {
std_enkf_set_subspace_dimension( boot_data->std_enkf_data , ncomp );
cv_enkf_set_subspace_dimension( boot_data->cv_enkf_data , ncomp );
}
void * bootstrap_enkf_data_alloc( rng_type * rng ) {
bootstrap_enkf_data_type * boot_data = util_malloc( sizeof * boot_data );
UTIL_TYPE_ID_INIT( boot_data , BOOTSTRAP_ENKF_TYPE_ID );
boot_data->std_enkf_data = std_enkf_data_alloc( NULL );
boot_data->cv_enkf_data = cv_enkf_data_alloc( rng );
boot_data->rng = rng;
bootstrap_enkf_set_truncation( boot_data , DEFAULT_TRUNCATION );
bootstrap_enkf_set_subspace_dimension( boot_data , DEFAULT_NCOMP );
bootstrap_enkf_set_doCV( boot_data , DEFAULT_DO_CV);
boot_data->option_flags = ANALYSIS_NEED_ED + ANALYSIS_UPDATE_A + ANALYSIS_SCALE_DATA;
return boot_data;
}
void bootstrap_enkf_data_free( void * arg ) {
bootstrap_enkf_data_type * boot_data = bootstrap_enkf_data_safe_cast( arg );
{
std_enkf_data_free( boot_data->std_enkf_data );
cv_enkf_data_free( boot_data->cv_enkf_data );
}
free( boot_data );
}
static int ** alloc_iens_resample( rng_type * rng , int ens_size ) {
int ** iens_resample;
int iens;
iens_resample = util_calloc( ens_size , sizeof * iens_resample );
for (iens = 0; iens < ens_size; iens++)
iens_resample[iens] = util_calloc( ens_size , sizeof( ** iens_resample ) );
{
int i,j;
for (i=0; i < ens_size; i++)
for (j=0; j < ens_size; j++)
iens_resample[i][j] = rng_get_int( rng , ens_size );
}
return iens_resample;
}
static void free_iens_resample( int ** iens_resample, int ens_size ) {
for (int i=0; i < ens_size; i++)
free( iens_resample[i] );
free( iens_resample );
}
void bootstrap_enkf_updateA(void * module_data ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info) {
bootstrap_enkf_data_type * bootstrap_data = bootstrap_enkf_data_safe_cast( module_data );
{
const int num_cpu_threads = 4;
int ens_size = matrix_get_columns( A );
matrix_type * X = matrix_alloc( ens_size , ens_size );
matrix_type * A0 = matrix_alloc_copy( A );
matrix_type * S_resampled = matrix_alloc_copy( S );
matrix_type * A_resampled = matrix_alloc( matrix_get_rows(A0) , matrix_get_columns( A0 ));
int ** iens_resample = alloc_iens_resample( bootstrap_data->rng , ens_size );
{
int ensemble_members_loop;
for ( ensemble_members_loop = 0; ensemble_members_loop < ens_size; ensemble_members_loop++) {
int unique_bootstrap_components;
int ensemble_counter;
/* Resample A and meas_data. Here we are careful to resample the working copy.*/
{
{
int_vector_type * bootstrap_components = int_vector_alloc( ens_size , 0);
for (ensemble_counter = 0; ensemble_counter < ens_size; ensemble_counter++) {
int random_column = iens_resample[ ensemble_members_loop][ensemble_counter];
int_vector_iset( bootstrap_components , ensemble_counter , random_column );
matrix_copy_column( A_resampled , A0 , ensemble_counter , random_column );
matrix_copy_column( S_resampled , S , ensemble_counter , random_column );
}
int_vector_select_unique( bootstrap_components );
unique_bootstrap_components = int_vector_size( bootstrap_components );
int_vector_free( bootstrap_components );
}
if (bootstrap_data->doCV) {
const bool_vector_type * ens_mask = NULL;
cv_enkf_init_update( bootstrap_data->cv_enkf_data , ens_mask , S_resampled , R , dObs , E , D);
cv_enkf_initX( bootstrap_data->cv_enkf_data , X , A_resampled , S_resampled , R , dObs , E , D);
} else
std_enkf_initX(bootstrap_data->std_enkf_data , X , NULL , S_resampled,R, dObs, E,D );
matrix_inplace_matmul_mt1( A_resampled , X , num_cpu_threads );
matrix_inplace_add( A_resampled , A0 );
matrix_copy_column( A , A_resampled, ensemble_members_loop, ensemble_members_loop);
}
}
}
free_iens_resample( iens_resample , ens_size);
matrix_free( X );
matrix_free( S_resampled );
matrix_free( A_resampled );
matrix_free( A0 );
}
}
long bootstrap_enkf_get_options( void * arg , long flag) {
bootstrap_enkf_data_type * bootstrap_data = bootstrap_enkf_data_safe_cast( arg );
{
return bootstrap_data->option_flags;
}
}
bool bootstrap_enkf_set_double( void * arg , const char * var_name , double value) {
bootstrap_enkf_data_type * bootstrap_data = bootstrap_enkf_data_safe_cast( arg );
{
if (std_enkf_set_double( bootstrap_data->std_enkf_data , var_name , value ))
return true;
else {
return false;
}
}
}
bool bootstrap_enkf_set_int( void * arg , const char * var_name , int value) {
bootstrap_enkf_data_type * bootstrap_data = bootstrap_enkf_data_safe_cast( arg );
{
if (std_enkf_set_int( bootstrap_data->std_enkf_data , var_name , value ))
return true;
else {
return false;
}
}
}
bool bootstrap_enkf_set_bool( void * arg , const char * var_name , bool value) {
bootstrap_enkf_data_type * bootstrap_data = bootstrap_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , "CV" ) == 0)
bootstrap_data->doCV = value;
else
name_recognized = false;
return name_recognized;
}
}
bool bootstrap_enkf_has_var( const void * arg, const char * var_name) {
const bootstrap_enkf_data_type * module_data = bootstrap_enkf_data_safe_cast_const( arg );
{
return std_enkf_has_var(module_data->std_enkf_data, var_name);
}
}
double bootstrap_enkf_get_double( const void * arg, const char * var_name) {
const bootstrap_enkf_data_type * module_data = bootstrap_enkf_data_safe_cast_const( arg );
{
return std_enkf_get_double( module_data->std_enkf_data , var_name);
}
}
int bootstrap_enkf_get_int( const void * arg, const char * var_name) {
const bootstrap_enkf_data_type * module_data = bootstrap_enkf_data_safe_cast_const( arg );
{
return std_enkf_get_int( module_data->std_enkf_data , var_name);
}
}
#ifdef INTERNAL_LINK
#define LINK_NAME BOOTSTRAP_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "BOOTSTRAP_ENKF",
.alloc = bootstrap_enkf_data_alloc,
.freef = bootstrap_enkf_data_free,
.set_int = bootstrap_enkf_set_int ,
.set_double = bootstrap_enkf_set_double ,
.set_bool = bootstrap_enkf_set_bool ,
.set_string = NULL ,
.get_options = bootstrap_enkf_get_options ,
.initX = NULL,
.updateA = bootstrap_enkf_updateA,
.init_update = NULL,
.complete_update = NULL,
.has_var = bootstrap_enkf_has_var,
.get_int = bootstrap_enkf_get_int,
.get_double = bootstrap_enkf_get_double,
.get_bool = NULL,
.get_ptr = NULL,
};

View File

@ -1,721 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'cv_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ert/util/util.h>
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/std_enkf.h>
#include <ert/analysis/cv_enkf.h>
#define CV_ENKF_TYPE_ID 765523
#define INVALID_SUBSPACE_DIMENSION -1
#define INVALID_TRUNCATION -1
#define DEFAULT_SUBSPACE_DIMENSION INVALID_SUBSPACE_DIMENSION
#define DEFAULT_NFOLDS 10
#define DEFAULT_PEN_PRESS false
#define NFOLDS_KEY "CV_NFOLDS"
#define CV_PEN_PRESS_KEY "CV_PEN_PRESS"
struct cv_enkf_data_struct {
UTIL_TYPE_ID_DECLARATION;
matrix_type * Z;
matrix_type * Rp;
matrix_type * Dp;
rng_type * rng;
double truncation;
int nfolds;
int subspace_dimension; // ENKF_NCOMP_KEY (-1: use Truncation instead)
long option_flags;
bool penalised_press;
};
static UTIL_SAFE_CAST_FUNCTION( cv_enkf_data , CV_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION_CONST( cv_enkf_data , CV_ENKF_TYPE_ID )
void cv_enkf_set_truncation( cv_enkf_data_type * data , double truncation ) {
data->truncation = truncation;
if (truncation > 0.0)
data->subspace_dimension = INVALID_SUBSPACE_DIMENSION;
}
void cv_enkf_set_subspace_dimension( cv_enkf_data_type * data , int subspace_dimension) {
data->subspace_dimension = subspace_dimension;
if (subspace_dimension > 0)
data->truncation = INVALID_TRUNCATION;
}
void cv_enkf_set_nfolds( cv_enkf_data_type * data , int nfolds ) {
data->nfolds = nfolds;
}
void cv_enkf_set_pen_press( cv_enkf_data_type * data , bool value ) {
data->penalised_press = value;
}
void * cv_enkf_data_alloc( rng_type * rng ) {
cv_enkf_data_type * data = util_malloc( sizeof * data);
UTIL_TYPE_ID_INIT( data , CV_ENKF_TYPE_ID );
data->Z = NULL;
data->Rp = NULL;
data->Dp = NULL;
data->rng = rng;
data->penalised_press = DEFAULT_PEN_PRESS;
data->option_flags = ANALYSIS_NEED_ED + ANALYSIS_USE_A + ANALYSIS_SCALE_DATA;
data->nfolds = DEFAULT_NFOLDS;
cv_enkf_set_truncation( data , DEFAULT_ENKF_TRUNCATION_ );
return data;
}
void cv_enkf_data_free( void * arg ) {
cv_enkf_data_type * cv_data = cv_enkf_data_safe_cast( arg );
{
matrix_safe_free( cv_data->Z );
matrix_safe_free( cv_data->Rp );
matrix_safe_free( cv_data->Dp );
}
free( cv_data );
}
void cv_enkf_init_update( void * arg ,
const bool_vector_type * ens_mask ,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D ) {
cv_enkf_data_type * cv_data = cv_enkf_data_safe_cast( arg );
{
int i, j;
const int nrobs = matrix_get_rows( S );
const int nrens = matrix_get_columns( S );
const int nrmin = util_int_min( nrobs , nrens );
cv_data->Z = matrix_alloc( nrmin , nrens );
cv_data->Rp = matrix_alloc( nrmin , nrmin );
cv_data->Dp = matrix_alloc( nrmin , nrens );
/*
Compute SVD(S)
*/
matrix_type * U0 = matrix_alloc( nrobs , nrmin ); /* Left singular vectors. */
matrix_type * V0T = matrix_alloc( nrmin , nrens ); /* Right singular vectors. */
double * inv_sig0 = util_calloc( nrmin , sizeof * inv_sig0 );
double * sig0 = inv_sig0;
printf("Computing svd using truncation %0.4f\n",cv_data->truncation);
enkf_linalg_svdS(S , cv_data->truncation , cv_data->subspace_dimension , DGESVD_MIN_RETURN , inv_sig0 , U0 , V0T);
/* Need to use the original non-inverted singular values. */
for(i = 0; i < nrmin; i++)
if ( inv_sig0[i] > 0 )
sig0[i] = 1.0 / inv_sig0[i];
/*
Compute the actual principal components, Z = sig0 * VOT
NOTE: Z contains potentially alot of redundant zeros, but
we do not care about this for now
*/
for(i = 0; i < nrmin; i++)
for(j = 0; j < nrens; j++)
matrix_iset( cv_data->Z , i , j , sig0[i] * matrix_iget( V0T , i , j ) );
/* Also compute Rp */
{
matrix_type * X0 = matrix_alloc( nrmin , matrix_get_rows( R ));
matrix_dgemm(X0 , U0 , R , true , false , 1.0 , 0.0); /* X0 = U0^T * R */
matrix_dgemm(cv_data->Rp , X0 , U0 , false , false , 1.0 , 0.0); /* Rp = X0 * U0 */
matrix_free(X0);
}
/*We also need to compute the reduced "Innovation matrix" Dp = U0' * D */
matrix_dgemm(cv_data->Dp , U0 , D , true , false , 1.0 , 0.0);
free(inv_sig0);
matrix_free(U0);
matrix_free(V0T);
/*
2: Diagonalize the S matrix; singular vectors etc. needed later in the local CV:
(V0T = transposed right singular vectors of S, Z = scaled principal components,
eig = scaled, inverted singular vectors, U0 = left singular vectors of S
eig = inv(I+Lambda1),(Eq.14.30, and 14.29, Evensen, 2007, respectively)
*/
}
}
/*Function that computes the PRESS for different subspace dimensions using
m-fold CV
INPUT :
A : State-Vector ensemble matrix
Z : Ensemble matrix of principal components
Rp : Reduced order Observation error matrix
indexTrain: index of training ensemble
indexTest: index of test ensemble
nTest : number of members in the training ensemble
nTrain . number of members in the test ensemble
foldIndex: integer specifying which "cv-fold" we are considering
OUTPUT:
cvErr : UPDATED MATRIX OF PRESS VALUES
*/
static void cv_enkf_get_cv_error_prin_comp( cv_enkf_data_type * cv_data ,
matrix_type * cvErr ,
const matrix_type * A ,
const int * indexTest,
const int * indexTrain ,
const int nTest ,
const int nTrain ,
const int foldIndex,
const int maxP) {
/*
We need to predict ATest(p), for p = 1,...,nens -1, based on the estimated regression model:
AHatTest(p) = A[:,indexTrain] * Z[1:p,indexTrain]'* inv( Z[1:p,indexTrain] * Z[1:p,indexTrain]' + (nens-1) * Rp[1:p,1:p] ) * Z[1:p,indexTest];
*/
const int nx = matrix_get_rows( A );
matrix_type * AHat = matrix_alloc(nx , nTest );
matrix_type * ATrain = matrix_alloc( nx , nTrain );
int p,i,j;
/* Copy elements*/
for (i = 0; i < nx; i++)
for (j = 0; j < nTrain; j++)
matrix_iset(ATrain , i , j , matrix_iget( A , i , indexTrain[j]));
for (p = 0; p < maxP; p++) {
matrix_type * ZpTrain = matrix_alloc( p + 1, nTrain );
matrix_type *SigDp = matrix_alloc( p + 1 , p + 1);
for (i = 0; i <= p ; i++)
for (j = 0; j < nTrain; j++)
matrix_iset(ZpTrain , i , j , matrix_iget(cv_data->Z , i , indexTrain[j]));
/* SigDp = ZpTrain * ZpTrain' */
matrix_dgemm( SigDp , ZpTrain , ZpTrain, false , true , 1.0, 0.0);
/* SigDp += (nTrain - 1) * Rp */
for(i = 0; i <= p; i++)
for( j = 0; j <= p; j++)
matrix_iadd( SigDp , i , j , (nTrain - 1) * matrix_iget(cv_data->Rp, i, j));
/* Invert the covariance matrix for the principal components */
{
int inv_ok = matrix_inv( SigDp );
if ( inv_ok != 0 )
util_abort("%s: inversion of covariance matrix for the principal components failed for subspace dimension p = %d\n - aborting \n",__func__,p+1);
}
{
matrix_type * W = matrix_alloc(p + 1 , nTest );
matrix_type * W2 = matrix_alloc(nTrain , nTest );
/* W = inv(SigDp) * ZTest */
for (i = 0; i <= p; i++) {
for (j = 0; j < nTest; j++) {
double ksum = 0.0;
for (int k = 0; k <= p; k++)
ksum += matrix_iget(SigDp , i , k) * matrix_iget(cv_data->Z , k , indexTest[j]);
matrix_iset(W , i , j , ksum);
}
}
/* W2 = ZpTrain' * W */
matrix_dgemm( W2 , ZpTrain , W , true , false , 1.0 , 0.0);
/* Estimate the state-vector */
matrix_matmul( AHat , ATrain , W2 );
matrix_free( W2 );
matrix_free( W );
}
/*Compute Press Statistic: */
{
double R2Sum = 0;
for (i = 0; i < nx; i++) {
for (j = 0; j < nTest; j++) {
double tmp = matrix_iget(A , i , indexTest[j]) - matrix_iget(AHat , i , j);
R2Sum += tmp * tmp;
}
}
matrix_iset( cvErr , p , foldIndex , R2Sum );
}
matrix_free( ZpTrain );
matrix_free( SigDp );
} /*end for p */
matrix_free( AHat );
matrix_free( ATrain );
}
int cv_enkf_get_optimal_numb_comp(cv_enkf_data_type * cv_data ,
const matrix_type * cvErr ,
const int maxP ) {
double * cvMean = util_calloc( maxP , sizeof * cvMean );
double * cvStd = util_calloc( maxP , sizeof * cvStd );
int optP;
{
for (int p = 0; p < maxP; p++ ){
double err_sum = 0;
for (int folds = 0; folds < cv_data->nfolds; folds++ )
err_sum += matrix_iget( cvErr , p, folds );
cvMean[p] = err_sum / cv_data->nfolds;
}
for ( int p = 0; p < maxP; p++){
double err_sum2 = 0;
for ( int folds = 0; folds < cv_data->nfolds; folds++)
err_sum2 += pow( matrix_iget( cvErr , p , folds ) - cvMean[p] , 2);
cvStd[p] = sqrt( err_sum2 / (cv_data->nfolds - 1) );
}
}
{
double minErr = cvMean[0];
int i;
optP = 1;
printf("PRESS:\n");
printf("%f\n",cvMean[0]);
for (i = 1; i < maxP; i++) {
printf("%f\n",cvMean[i]);
if ((cvMean[i] < minErr) && (cvMean[i] > 0.0)) {
minErr = cvMean[i];
optP = i+1;
}
}
if (cv_data->penalised_press) {
for ( i = 0; i < optP; i++){
if( cvMean[i] - cvStd[i] <= minErr ){
optP = i+1;
break;
}
}
}
}
free( cvStd );
free( cvMean );
return optP;
}
/* Function that performs cross-validation to find the optimal subspace dimension, */
static int get_optimal_principal_components( cv_enkf_data_type * cv_data ,
const matrix_type * A) {
const int nrens = matrix_get_columns( cv_data->Z );
const int nrmin = matrix_get_rows( cv_data->Z );
matrix_type * cvError;
int * randperms = util_calloc( nrens , sizeof * randperms);
int maxP = nrmin;
int optP;
/* We only want to search the non-zero eigenvalues */
for (int i = 0; i < nrmin; i++) {
if (matrix_iget(cv_data->Z,i,1) == 0.0) {
maxP = i;
break;
}
}
if (maxP > nrmin)
maxP = nrmin - 1; // <- Change by Joakim; using nrmin here will load to out
// bounds access oc cv_data->Z at line 460.
if ( nrens < cv_data->nfolds )
util_abort("%s: number of ensemble members %d need to be larger than the number of cv-folds - aborting \n",
__func__,
nrens,
cv_data->nfolds);
for (int i=0; i < nrens; i++)
randperms[i] = i;
rng_shuffle_int( cv_data->rng , randperms , nrens );
cvError = matrix_alloc( maxP , cv_data->nfolds );
{
int ntest, ntrain, k,j,i;
int * indexTest = util_calloc( nrens , sizeof * indexTest );
int * indexTrain = util_calloc( nrens , sizeof * indexTrain );
for (i = 0; i < cv_data->nfolds; i++) {
ntest = 0;
ntrain = 0;
k = i;
/*extract members for the training and test ensembles */
for (j = 0; j < nrens; j++) {
if (j == k) {
indexTest[ntest] = randperms[j];
k += cv_data->nfolds;
ntest++;
} else {
indexTrain[ntrain] = randperms[j];
ntrain++;
}
}
/*Perform CV for each subspace dimension p */
cv_enkf_get_cv_error_prin_comp( cv_data , cvError , A , indexTest , indexTrain, ntest, ntrain , i , maxP);
}
free( indexTest );
free( indexTrain );
}
/* find optimal truncation value for the cv-scheme */
optP = cv_enkf_get_optimal_numb_comp( cv_data , cvError , maxP);
matrix_free( cvError );
free( randperms );
return optP;
}
/*NB! HERE WE COUNT optP from 0,1,2,... */
static void getW_prin_comp(cv_enkf_data_type * cv_data , matrix_type *W , const int optP) {
int i, j;
double tmp2;
int nrens = matrix_get_columns( cv_data->Z );
/* Finally, compute W = Z(1:p,:)' * inv(Z(1:p,:) * Z(1:p,:)' + (n -1) * Rp) */
matrix_type *Zp = matrix_alloc( optP, nrens );
matrix_type *SigZp = matrix_alloc( optP ,optP);
// This loop will fail with i to large whcn accessing cv_data->Z
// if we do not limit maxP to nrmin - 1?
for (i = 0; i < optP ; i++)
for (j = 0; j < nrens; j++)
matrix_iset_safe(Zp , i , j , matrix_iget_safe(cv_data->Z , i ,j));
// Matrix copy_block should be used in stead of the double (i,j) loop;
// however that failed because the cv_data->Z matrix had one row too few?
// matrix_copy_block( Zp , 0 , 0 , optP , nrens , cv_data->Z , 0 , 0 );
/*Compute SigZp = Zp * Zp' */
matrix_dgemm( SigZp , Zp , Zp, false , true , 1.0, 0.0);
/*Add (ntrain-1) * Rp*/
for(i = 0; i < optP; i++) {
for( j = 0; j < optP; j++) {
tmp2 = matrix_iget(SigZp , i , j) + (nrens - 1) * matrix_iget(cv_data->Rp, i, j);
matrix_iset( SigZp , i , j , tmp2 );
}
}
/* Invert the covariance matrix for the principal components */
int inv_ok = matrix_inv( SigZp );
/*Check if the inversion went ok */
if ( inv_ok != 0 )
util_abort("%s: inversion of covariance matrix for the principal components failed for subspace dimension p = %d\n - aborting \n",__func__,optP);
/*Compute W = Zp' * inv(SigZp) */
matrix_dgemm( W , Zp , SigZp , true , false , 1.0 , 0.0);
matrix_free( Zp );
matrix_free( SigZp );
}
void cv_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D) {
cv_enkf_data_type * cv_data = cv_enkf_data_safe_cast( module_data );
printf("Running CV\n");
{
int optP;
int ens_size = matrix_get_columns( S );
/* Get the optimal number of principal components
where p is found minimizing the PRESS statistic */
{
matrix_type * workA = matrix_alloc_copy( A );
matrix_subtract_row_mean( workA );
optP = get_optimal_principal_components(cv_data , workA );
printf("Optimal subspace dimension found %d\n",optP);
matrix_free( workA );
}
{
matrix_type * W = matrix_alloc(ens_size , optP);
/* Compute W = Z(1:p,:)' * inv(Z(1:p,:) * Z(1:p,:)' + (ens_size-1) * Rp(1:p,1:p))*/
getW_prin_comp( cv_data , W , optP);
/*Compute the actual X5 matrix: */
/*Compute X5 = W * Dp (The hard way) */
for( int i = 0; i < ens_size; i++) {
for( int j = 0; j < ens_size; j++) {
double tmp = 0.0;
for( int k = 0; k < optP; k++)
tmp += matrix_iget( W , i , k) * matrix_iget( cv_data->Dp , k , j);
matrix_iset(X , i , j ,tmp);
}
matrix_iadd( X , i , i , 1.0); /* X5 = I + X5 */
}
matrix_free( W );
}
}
}
void cv_enkf_complete_update( void * arg ) {
cv_enkf_data_type * cv_data = cv_enkf_data_safe_cast( arg );
{
matrix_free( cv_data->Z );
matrix_free( cv_data->Rp );
matrix_free( cv_data->Dp );
cv_data->Z = NULL;
cv_data->Rp = NULL;
cv_data->Dp = NULL;
}
}
bool cv_enkf_set_double( void * arg , const char * var_name , double value) {
cv_enkf_data_type * module_data = cv_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_TRUNCATION_KEY_) == 0)
cv_enkf_set_truncation( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
bool cv_enkf_set_int( void * arg , const char * var_name , int value) {
cv_enkf_data_type * module_data = cv_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_NCOMP_KEY_) == 0)
cv_enkf_set_subspace_dimension( module_data , value );
else if (strcmp( var_name , NFOLDS_KEY) == 0)
cv_enkf_set_nfolds( module_data , value);
else
name_recognized = false;
return name_recognized;
}
}
bool cv_enkf_set_bool( void * arg , const char * var_name , bool value) {
cv_enkf_data_type * module_data = cv_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , CV_PEN_PRESS_KEY) == 0)
cv_enkf_set_pen_press( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
long cv_enkf_get_options( void * arg , long flag) {
cv_enkf_data_type * cv_data = cv_enkf_data_safe_cast( arg );
{
return cv_data->option_flags;
}
}
bool cv_enkf_has_var( const void * arg, const char * var_name) {
{
if (strcmp(var_name , ENKF_NCOMP_KEY_) == 0)
return true;
else if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return true;
else if (strcmp(var_name , NFOLDS_KEY) == 0)
return true;
else if (strcmp(var_name , CV_PEN_PRESS_KEY) == 0)
return true;
else
return false;
}
}
double cv_enkf_get_double( const void * arg, const char * var_name) {
const cv_enkf_data_type * module_data = cv_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return module_data->truncation;
else
return -1;
}
}
int cv_enkf_get_int( const void * arg, const char * var_name) {
const cv_enkf_data_type * module_data = cv_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_NCOMP_KEY_) == 0)
return module_data->subspace_dimension;
else if (strcmp(var_name , NFOLDS_KEY) == 0)
return module_data->nfolds;
else
return -1;
}
}
bool cv_enkf_get_bool( const void * arg, const char * var_name) {
const cv_enkf_data_type * module_data = cv_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , CV_PEN_PRESS_KEY) == 0)
return module_data->penalised_press;
else
return false;
}
}
#ifdef INTERNAL_LINK
#define LINK_NAME CV_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "CV_ENKF",
.alloc = cv_enkf_data_alloc,
.freef = cv_enkf_data_free,
.set_int = cv_enkf_set_int ,
.set_double = cv_enkf_set_double ,
.set_bool = cv_enkf_set_bool ,
.set_string = NULL ,
.get_options = cv_enkf_get_options ,
.initX = cv_enkf_initX ,
.updateA = NULL,
.init_update = cv_enkf_init_update ,
.complete_update = cv_enkf_complete_update ,
.has_var = cv_enkf_has_var,
.get_int = cv_enkf_get_int,
.get_double = cv_enkf_get_double,
.get_bool = cv_enkf_get_bool,
.get_ptr = NULL,
};

View File

@ -1,860 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_lapack.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/util.h>
#include <ert/analysis/enkf_linalg.h>
void enkf_linalg_genX3(matrix_type * X3 , const matrix_type * W , const matrix_type * D , const double * eig) {
const int nrobs = matrix_get_rows( D );
const int nrens = matrix_get_columns( D );
const int nrmin = util_int_min( nrobs , nrens );
int i,j;
matrix_type * X1 = matrix_alloc(nrmin , nrobs);
matrix_type * X2 = matrix_alloc(nrmin , nrens);
/* X1 = (I + Lambda1)^(-1) * W'*/
for (i=0; i < nrmin; i++)
for (j=0; j < nrobs; j++)
matrix_iset(X1 , i , j , eig[i] * matrix_iget(W , j , i));
matrix_matmul(X2 , X1 , D); /* X2 = X1 * D (Eq. 14.31) */
matrix_matmul(X3 , W , X2); /* X3 = W * X2 = X1 * X2 (Eq. 14.31) */
matrix_free( X1 );
matrix_free( X2 );
}
void enkf_linalg_genX2(matrix_type * X2 , const matrix_type * S , const matrix_type * W , const double * eig) {
const int nrens = matrix_get_columns( S );
const int idim = matrix_get_rows( X2 );
matrix_dgemm(X2 , W , S , true , false , 1.0 , 0.0);
{
int i,j;
for (j=0; j < nrens; j++)
for (i=0; i < idim; i++)
matrix_imul(X2 , i,j , sqrt(eig[i]));
}
}
/**
This function calculates the svd of the input matrix S. The number
of significant singular values to retain can either be forced to a
fixed number, or a cutoff on small singular values can be
used. This behaviour is regulated by the @ncomp and @truncation
parameters:
ncomp > 0 , truncation < 0: Use ncomp parameters.
ncomp < 0 , truncation > 0: Truncate at level 'truncation'.
The singular values are returned in the inv_sig0 vector; the values
we retain are inverted and the remaining elements in are explicitly
set to zero.
The left-hand singular vectors are returned in the matrix
U0. Depending on the value of the flag @store_V0T the right hand
singular vectors are stored in the V0T matrix, or just
discarded. If you do not intend to use the right hand vectors at
all, i.e. store_V0T == DGESVD_NONE, the V0T matrix will not be
accessed.
The input S matrix should have been shifted to zero mean prior to
calling this function.
*/
/*This function is similar to enkf_linalg_svdS but it returns the eigen values without its inverse and also give the matrices truncated U VT and Sig0*/
// Trunc.SVD(S) = U0 * Sig0 * V0T
int enkf_linalg_svd_truncation(const matrix_type * S ,
double truncation ,
int ncomp ,
dgesvd_vector_enum store_V0T ,
double * sig0,
matrix_type * U0 ,
matrix_type * V0T) {
int num_significant = -1;
int nrows = matrix_get_rows(S);
int ncolumns= matrix_get_columns(S);
if (((truncation > 0) && (ncomp < 0)) ||
((truncation < 0) && (ncomp > 0))) {
int num_singular_values = util_int_min( matrix_get_rows( S ) , matrix_get_columns( S ));
{
matrix_type * workS = matrix_alloc_copy( S );
matrix_dgesvd(DGESVD_MIN_RETURN , store_V0T , workS , sig0 , U0 , V0T);
matrix_free( workS );
}
int i;
if (ncomp > 0)
num_significant = ncomp;
else {
double total_sigma2 = 0;
for (i=0; i < num_singular_values; i++)
total_sigma2 += sig0[i];
/*
Determine the number of singular values by enforcing that
less than a fraction @truncation of the total variance be
accounted for.
*/
num_significant = 0;
{
double running_sigma2 = 0;
for (i=0; i < num_singular_values; i++) {
if (running_sigma2 / total_sigma2 < truncation) { /* Include one more singular value ? */
num_significant++;
running_sigma2 += sig0[i];
} else
break;
}
}
}
if (num_significant > 0) {
matrix_resize(U0 , nrows , num_significant , true);
matrix_resize(V0T , num_significant , ncolumns , true);
} else
util_abort("%s: zero significant singular values\n",__func__);
}
else
util_abort("%s: truncation:%g ncomp:%d - invalid ambigous input.\n",__func__ , truncation , ncomp );
return num_significant;
}
static int enkf_linalg_num_significant(int num_singular_values , const double * sig0 , double truncation ) {
int num_significant = 0;
double total_sigma2 = 0;
for (int i=0; i < num_singular_values; i++)
total_sigma2 += sig0[i] * sig0[i];
/*
Determine the number of singular values by enforcing that
less than a fraction @truncation of the total variance be
accounted for.
*/
{
double running_sigma2 = 0;
for (int i=0; i < num_singular_values; i++) {
if (running_sigma2 / total_sigma2 < truncation) { /* Include one more singular value ? */
num_significant++;
running_sigma2 += sig0[i] * sig0[i];
} else
break;
}
}
return num_significant;
}
int enkf_linalg_svdS(const matrix_type * S ,
double truncation ,
int ncomp ,
dgesvd_vector_enum store_V0T ,
double * inv_sig0,
matrix_type * U0 ,
matrix_type * V0T) {
double * sig0 = inv_sig0;
int num_significant = 0;
if (((truncation > 0) && (ncomp < 0)) ||
((truncation < 0) && (ncomp > 0))) {
int num_singular_values = util_int_min( matrix_get_rows( S ) , matrix_get_columns( S ));
{
matrix_type * workS = matrix_alloc_copy( S );
matrix_dgesvd(DGESVD_MIN_RETURN , store_V0T , workS , sig0 , U0 , V0T);
matrix_free( workS );
}
if (ncomp > 0)
num_significant = ncomp;
else
num_significant = enkf_linalg_num_significant( num_singular_values , sig0 , truncation );
{
int i;
/* Inverting the significant singular values */
for (i = 0; i < num_significant; i++)
inv_sig0[i] = 1.0 / sig0[i];
/* Explicitly setting the insignificant singular values to zero. */
for (i=num_significant; i < num_singular_values; i++)
inv_sig0[i] = 0;
}
} else
util_abort("%s: truncation:%g ncomp:%d - invalid ambigous input.\n",__func__ , truncation , ncomp );
return num_significant;
}
int enkf_linalg_num_PC(const matrix_type * S , double truncation ) {
int num_singular_values = util_int_min( matrix_get_rows( S ) , matrix_get_columns( S ));
int num_significant;
double * sig0 = util_calloc( num_singular_values , sizeof * sig0);
{
matrix_type * workS = matrix_alloc_copy( S );
matrix_dgesvd(DGESVD_NONE , DGESVD_NONE , workS , sig0 , NULL , NULL);
matrix_free( workS );
}
num_significant = enkf_linalg_num_significant( num_singular_values , sig0 , truncation );
free( sig0 );
return num_significant;
}
/*
****************************************************************************************************
Routine computes X1 and eig corresponding to Eqs 14.54-14.55
Geir Evensen
*/
void enkf_linalg_lowrankE(const matrix_type * S , /* (nrobs x nrens) */
const matrix_type * E , /* (nrobs x nrens) */
matrix_type * W , /* (nrobs x nrmin) Corresponding to X1 from Eqs. 14.54-14.55 */
double * eig , /* (nrmin) Corresponding to 1 / (1 + Lambda1^2) (14.54) */
double truncation ,
int ncomp) {
const int nrobs = matrix_get_rows( S );
const int nrens = matrix_get_columns( S );
const int nrmin = util_int_min( nrobs , nrens );
matrix_type * U0 = matrix_alloc( nrobs , nrmin );
double * inv_sig0 = util_calloc( nrmin , sizeof * inv_sig0);
matrix_type * X0 = matrix_alloc( nrmin , nrens );
matrix_type * U1 = matrix_alloc( nrmin , nrmin );
double * sig1 = util_calloc( nrmin , sizeof * sig1);
int i ,j;
/* Compute SVD of S=HA` -> U0, invsig0=sig0^(-1) */
enkf_linalg_svdS(S , truncation , ncomp , DGESVD_NONE , inv_sig0, U0 , NULL);
/* X0(nrmin x nrens) = Sigma0^(+) * U0'* E (14.51) */
matrix_dgemm(X0 , U0 , E , true , false , 1.0 , 0.0); /* X0 = U0^T * E (14.51) */
/* Multiply X0 with sig0^(-1) from left X0 = S^(-1) * X0 */
for (j=0; j < matrix_get_columns( X0 ) ; j++)
for (i=0; i < matrix_get_rows( X0 ); i++)
matrix_imul(X0 , i , j , inv_sig0[j]);
/* Compute SVD of X0-> U1*eig*V1 14.52 */
matrix_dgesvd(DGESVD_MIN_RETURN , DGESVD_NONE, X0 , sig1, U1 , NULL);
/* Lambda1 = 1/(I + Lambda^2) in 14.56 */
for (i=0; i < nrmin; i++)
eig[i] = 1.0 / (1.0 + sig1[i]*sig1[i]);
/* Compute sig0^+ U1 (14:55) */
for (j=0; j < nrmin; j++)
for (i=0; i < nrmin; i++)
matrix_imul(U1 , i , j , inv_sig0[i]);
/* Compute X1 = W = U0 * (U1=sig0^+ U1) = U0 * Sigma0^(+') * U1 (14:55) */
matrix_matmul(W , U0 , U1);
matrix_free( X0 );
matrix_free( U0 );
util_safe_free( inv_sig0 );
matrix_free( U1 );
util_safe_free( sig1 );
}
void enkf_linalg_Cee(matrix_type * B, int nrens , const matrix_type * R , const matrix_type * U0 , const double * inv_sig0) {
const int nrmin = matrix_get_rows( B );
{
matrix_type * X0 = matrix_alloc( nrmin , matrix_get_rows( R ));
matrix_dgemm(X0 , U0 , R , true , false , 1.0 , 0.0); /* X0 = U0^T * R */
matrix_dgemm(B , X0 , U0 , false , false , 1.0 , 0.0); /* B = X0 * U0 */
matrix_free( X0 );
}
{
int i ,j;
/* Funny code ??
Multiply B with S^(-1)from left and right
BHat = S^(-1) * B * S^(-1)
*/
for (j=0; j < matrix_get_columns( B ) ; j++)
for (i=0; i < matrix_get_rows( B ); i++)
matrix_imul(B , i , j , inv_sig0[i]);
for (j=0; j < matrix_get_columns( B ) ; j++)
for (i=0; i < matrix_get_rows( B ); i++)
matrix_imul(B , i , j , inv_sig0[j]);
}
matrix_scale(B , nrens - 1.0);
}
void enkf_linalg_lowrankCinv__(const matrix_type * S ,
const matrix_type * R ,
matrix_type * V0T ,
matrix_type * Z,
double * eig ,
matrix_type * U0,
double truncation,
int ncomp) {
const int nrobs = matrix_get_rows( S );
const int nrens = matrix_get_columns( S );
const int nrmin = util_int_min( nrobs , nrens );
double * inv_sig0 = util_calloc( nrmin , sizeof * inv_sig0);
if (V0T != NULL)
enkf_linalg_svdS(S , truncation , ncomp , DGESVD_MIN_RETURN , inv_sig0 , U0 , V0T );
else
enkf_linalg_svdS(S , truncation , ncomp , DGESVD_NONE , inv_sig0, U0 , NULL);
{
matrix_type * B = matrix_alloc( nrmin , nrmin );
enkf_linalg_Cee( B , nrens , R , U0 , inv_sig0); /* B = Xo = (N-1) * Sigma0^(+) * U0'* Cee * U0 * Sigma0^(+') (14.26)*/
matrix_dgesvd(DGESVD_MIN_RETURN , DGESVD_NONE, B , eig, Z , NULL);
matrix_free( B );
}
{
int i,j;
/* Lambda1 = (I + Lambda)^(-1) */
for (i=0; i < nrmin; i++)
eig[i] = 1.0 / (1 + eig[i]);
for (j=0; j < nrmin; j++)
for (i=0; i < nrmin; i++)
matrix_imul(Z , i , j , inv_sig0[i]); /* Z2 = Sigma0^(+) * Z; */
}
util_safe_free( inv_sig0 );
}
void enkf_linalg_lowrankCinv(const matrix_type * S ,
const matrix_type * R ,
matrix_type * W , /* Corresponding to X1 from Eq. 14.29 */
double * eig , /* Corresponding to 1 / (1 + Lambda_1) (14.29) */
double truncation ,
int ncomp) {
const int nrobs = matrix_get_rows( S );
const int nrens = matrix_get_columns( S );
const int nrmin = util_int_min( nrobs , nrens );
matrix_type * U0 = matrix_alloc( nrobs , nrmin );
matrix_type * Z = matrix_alloc( nrmin , nrmin );
enkf_linalg_lowrankCinv__( S , R , NULL , Z , eig , U0 , truncation , ncomp);
matrix_matmul(W , U0 , Z); /* X1 = W = U0 * Z2 = U0 * Sigma0^(+') * Z */
matrix_free( U0 );
matrix_free( Z );
}
void enkf_linalg_meanX5(const matrix_type * S ,
const matrix_type * W ,
const double * eig ,
const matrix_type * dObs,
matrix_type * X5) {
const int nrens = matrix_get_columns( S );
const int nrobs = matrix_get_rows( S );
const int nrmin = util_int_min( nrobs , nrens );
double * work = util_calloc( (2 * nrmin + nrobs + nrens) , sizeof * work );
matrix_type * innov = enkf_linalg_alloc_innov( dObs , S );
{
double * y1 = &work[0];
double * y2 = &work[nrmin];
double * y3 = &work[2*nrmin];
double * y4 = &work[2*nrmin + nrobs];
if (nrobs == 1) {
/* Is this special casing necessary ??? */
y1[0] = matrix_iget(W , 0,0) * matrix_iget( innov , 0 , 0);
y2[0] = eig[0] * y1[0];
y3[0] = matrix_iget(W , 0, 0) *y2[0];
for (int iens = 0; iens < nrens; iens++)
y4[iens] = y3[0] * matrix_iget(S , 0, iens);
} else {
matrix_dgemv(W , matrix_get_data( innov ) , y1 , true , 1.0, 0.0); /* y1 = Trans(W) * innov */
for (int i= 0; i < nrmin; i++)
y2[i] = eig[i] * y1[i]; /* y2 = eig * y1 */
matrix_dgemv(W , y2 , y3 , false , 1.0 , 0.0); /* y3 = W * y2; */
matrix_dgemv(S , y3 , y4 , true , 1.0 , 0.0); /* y4 = Trans(S) * y3 */
}
for (int iens = 0; iens < nrens; iens++)
matrix_set_column(X5 , y4 , iens );
matrix_shift(X5 , 1.0/nrens);
}
free( work );
matrix_free( innov );
}
void enkf_linalg_X5sqrt(matrix_type * X2 , matrix_type * X5 , const matrix_type * randrot, int nrobs) {
const int nrens = matrix_get_columns( X5 );
const int nrmin = util_int_min( nrobs , nrens );
matrix_type * VT = matrix_alloc( nrens , nrens );
double * sig = util_calloc( nrmin , sizeof * sig );
double * isig = util_calloc( nrmin , sizeof * sig );
matrix_dgesvd(DGESVD_NONE , DGESVD_ALL , X2 , sig , NULL , VT);
{
matrix_type * X3 = matrix_alloc( nrens , nrens );
matrix_type * X33 = matrix_alloc( nrens , nrens );
matrix_type * X4 = matrix_alloc( nrens , nrens );
matrix_type * IenN = matrix_alloc( nrens , nrens );
int i,j;
for (i = 0; i < nrmin; i++)
isig[i] = sqrt( util_double_max( 1.0 - sig[i]*sig[i] ,0.0));
for (j = 0; j < nrens; j++)
for (i = 0; i < nrens; i++)
matrix_iset(X3 , i , j , matrix_iget(VT , j , i));
for (j=0; j< nrmin; j++)
matrix_scale_column(X3 , j , isig[j]);
matrix_dgemm(X33 , X3 , VT , false , false , 1.0 , 0.0); /* X33 = X3 * VT */
if (randrot != NULL)
matrix_dgemm(X4 , X33 , randrot , false, false , 1.0 , 0.0); /* X4 = X33 * Randrot */
else
matrix_assign(X4 , X33);
matrix_set(IenN , -1.0/ nrens);
for (i = 0; i < nrens; i++)
matrix_iadd(IenN , i , i , 1.0);
matrix_dgemm(X5 , IenN , X4 , false , false , 1.0 , 1.0); /* X5 = IenN * X4 + X5 */
matrix_free( X3 );
matrix_free( X33 );
matrix_free( X4 );
matrix_free( IenN );
}
free(sig);
free(isig);
matrix_free( VT );
}
matrix_type * enkf_linalg_alloc_innov( const matrix_type * dObs , const matrix_type * S) {
matrix_type * innov = matrix_alloc_copy( dObs );
for (int iobs =0; iobs < matrix_get_row_sum( dObs , iobs); iobs++)
matrix_isub( innov , iobs , 0 , matrix_get_row_sum( S , iobs ));
return innov;
}
void enkf_linalg_init_stdX( matrix_type * X , const matrix_type * S , const matrix_type * D ,
const matrix_type * W , const double * eig , bool bootstrap) {
int nrobs = matrix_get_rows( W );
int ens_size = matrix_get_rows( X );
matrix_type * X3 = matrix_alloc(nrobs , ens_size);
enkf_linalg_genX3(X3 , W , D , eig ); /* X2 = diag(eig) * W' * D (Eq. 14.31, Evensen (2007)) */
/* X3 = W * X2 = X1 * X2 (Eq. 14.31, Evensen (2007)) */
matrix_dgemm( X , S , X3 , true , false , 1.0 , 0.0); /* X = S' * X3 */
if (!bootstrap) {
for (int i = 0; i < ens_size ; i++)
matrix_iadd( X , i , i , 1.0); /*X = I + X */
}
matrix_free( X3 );
}
void enkf_linalg_init_sqrtX(matrix_type * X5 ,
const matrix_type * S ,
const matrix_type * randrot ,
const matrix_type * innov ,
const matrix_type * W ,
const double * eig ,
bool bootstrap) {
const int nrobs = matrix_get_rows( S );
const int nrens = matrix_get_columns( S );
const int nrmin = util_int_min( nrobs , nrens );
matrix_type * X2 = matrix_alloc(nrmin , nrens);
if (bootstrap)
util_exit("%s: Sorry bootstrap support not fully implemented for SQRT scheme\n",__func__);
enkf_linalg_meanX5( S , W , eig , innov , X5 );
enkf_linalg_genX2(X2 , S , W , eig);
enkf_linalg_X5sqrt(X2 , X5 , randrot , nrobs);
matrix_free( X2 );
}
/*****************************************************************/
/**
This routine generates a real orthogonal random matrix.
The algorithm is the one by
Francesco Mezzadri (2007), How to generate random matrices from the classical
compact groups, Notices of the AMS, Vol. 54, pp 592-604.
1. First a matrix with independent random normal numbers are simulated.
2. Then the QR decomposition is computed, and Q will then be a random orthogonal matrix.
3. The diagonal elements of R are extracted and we construct the diagonal matrix X(j,j)=R(j,j)/|R(j,j)|
4. An updated Q'=Q X is computed, and this is now a random orthogonal matrix with a Haar measure.
The implementation is a plain reimplementation/copy of the old m_randrot.f90 function.
*/
/**
NB: This should rather use the implementation in m_mean_preserving_rotation.f90.
*/
void enkf_linalg_set_randrot( matrix_type * Q , rng_type * rng) {
int ens_size = matrix_get_rows( Q );
double * tau = util_calloc( ens_size , sizeof * tau );
int * sign = util_calloc( ens_size , sizeof * sign);
for (int i = 0; i < ens_size; i++)
for (int j = 0; j < ens_size; j++)
matrix_iset(Q , i , j , rng_std_normal( rng ));
matrix_dgeqrf( Q , tau ); /* QR factorization */
for (int i=0; i < ens_size; i++) {
double Qii = matrix_iget( Q , i,i);
sign[i] = Qii / abs(Qii);
}
matrix_dorgqr( Q , tau , ens_size );
for (int i = 0; i < ens_size; i++) {
if (sign[i] < 0)
matrix_scale_column( Q , i , -1 );
}
free( sign );
free( tau );
}
/**
Generates the mean preserving random rotation for the EnKF SQRT algorithm
using the algorithm from Sakov 2006-07. I.e, generate rotation Up such that
Up*Up^T=I and Up*1=1 (all rows have sum = 1) see eq 17.
From eq 18, Up=B * Upb * B^T
B is a random orthonormal basis with the elements in the first column equals 1/sqrt(nrens)
Upb = | 1 0 |
| 0 U |
where U is an arbitrary orthonormal matrix of dim nrens-1 x nrens-1 (eq. 19)
*/
matrix_type * enkf_linalg_alloc_mp_randrot(int ens_size , rng_type * rng) {
matrix_type * Up = matrix_alloc( ens_size , ens_size ); /* The return value. */
{
matrix_type * B = matrix_alloc( ens_size , ens_size );
matrix_type * Upb = matrix_alloc( ens_size , ens_size );
matrix_type * U = matrix_alloc_shared(Upb , 1 , 1 , ens_size - 1, ens_size - 1);
{
int k,j;
matrix_type * R = matrix_alloc( ens_size , ens_size );
matrix_random_init( B , rng); /* B is filled up with U(0,1) numbers. */
matrix_set_const_column( B , 1.0 / sqrt( ens_size ) , 0 );
/* modified_gram_schmidt is used to create the orthonormal basis in B.*/
for (k=0; k < ens_size; k++) {
double Rkk = sqrt( matrix_column_column_dot_product( B , k , B , k));
matrix_iset(R , k , k , Rkk);
matrix_scale_column(B , k , 1.0/Rkk);
for (j=k+1; j < ens_size; j++) {
double Rkj = matrix_column_column_dot_product(B , k , B , j);
matrix_iset(R , k , j , Rkj);
{
int i;
for (i=0; i < ens_size; i++) {
double Bij = matrix_iget(B , i , j);
double Bik = matrix_iget(B , i , k);
matrix_iset(B , i , j , Bij - Bik * Rkj);
}
}
}
}
matrix_free( R );
}
enkf_linalg_set_randrot( U , rng );
matrix_iset( Upb , 0 , 0 , 1);
{
matrix_type * Q = matrix_alloc( ens_size , ens_size );
matrix_dgemm( Q , B , Upb , false , false , 1, 0); /* Q = B * Ubp */
matrix_dgemm( Up , Q , B , false , true , 1, 0); /* Up = Q * T(B) */
matrix_free( Q );
}
matrix_free( B );
matrix_free( Upb );
matrix_free( U );
}
return Up;
}
/*****************************************************************/
/**
Checking that the sum through one row in the X matrix equals
@target_sum. @target_sum will be 1 normally, and zero if we are doing
bootstrap.
*/
void enkf_linalg_checkX(const matrix_type * X , bool bootstrap) {
matrix_assert_finite( X );
{
int target_sum;
if (bootstrap)
target_sum = 0;
else
target_sum = 1;
for (int icol = 0; icol < matrix_get_columns( X ); icol++) {
double col_sum = matrix_get_column_sum(X , icol);
if (fabs(col_sum - target_sum) > 0.0001)
util_abort("%s: something is seriously broken. col:%d col_sum = %g != %g - ABORTING\n",__func__ , icol , col_sum , target_sum);
}
}
}
/*****************************************************************/
int enkf_linalg_get_PC( const matrix_type * S0,
const matrix_type * dObs ,
double truncation,
int ncomp,
matrix_type * PC,
matrix_type * PC_obs,
double_vector_type * singular_values) {
const int nrobs = matrix_get_rows( S0 );
const int nrens = matrix_get_columns( S0 );
const int nrmin = util_int_min( nrobs , nrens );
matrix_type * U0 = matrix_alloc( nrobs , nrens );
matrix_type * S = matrix_alloc_copy( S0 );
double * inv_sig0;
int num_PC;
double_vector_iset( singular_values , nrmin - 1 , 0 );
matrix_subtract_row_mean( S );
ncomp = util_int_min( ncomp , nrmin );
inv_sig0 = double_vector_get_ptr( singular_values );
{
matrix_type * S_mean = matrix_alloc( nrobs , 1 );
num_PC = enkf_linalg_svdS(S , truncation , ncomp, DGESVD_NONE , inv_sig0 , U0 , NULL);
matrix_assign( S , S0); // The svd routine will overwrite S - we therefor must pick it up again from S0.
matrix_subtract_and_store_row_mean( S , S_mean);
/* Multiply with inverted singular values. */
matrix_resize( U0 , nrobs , num_PC , true);
for (int i=0; i < num_PC; i++)
matrix_imul_col( U0 , i , inv_sig0[i] );
/* The simulated components / projections */
{
matrix_resize( PC , num_PC , nrens , false );
matrix_dgemm( PC , U0 , S , true , false , 1.0 , 0.0 );
}
/* The observer projections. */
{
matrix_scale( S_mean , -1.0);
matrix_inplace_add_column( S_mean , dObs , 0 , 0 );
matrix_resize( PC_obs , num_PC , 1 , false );
matrix_dgemm( PC_obs , U0 , S_mean , true , false , 1.0 , 0.0 );
}
for (int i=0; i < double_vector_size( singular_values ); i++)
inv_sig0[i] = 1.0 / inv_sig0[i];
matrix_free( S_mean );
}
matrix_free( S );
matrix_free( U0 );
return num_PC;
}
void enkf_linalg_rml_enkfX1(matrix_type *X1, matrix_type *Udr, matrix_type *D, matrix_type *R)
{
/*
This routine computes X1 for RML_EnKF module as X1 = Ud(T)*Cd(-1/2)*D -- D= (dk-do)
here the negative sign cancels with one needed in X3 matrix computation
*/
matrix_type * tmp = matrix_alloc(matrix_get_columns(Udr),matrix_get_rows(R));
matrix_matmul_with_transpose( tmp, Udr, R, true, false);
matrix_matmul( X1 , tmp, D);
matrix_free(tmp);
}
void enkf_linalg_rml_enkfX2(matrix_type *X2 , double *Wdr , matrix_type * X1 , double a , int nsign)
{
/*
This routine computes X2 for RML_EnKF module as X2 = ((a*Ipd)+Wd^2)^-1 * X1
Since a+Ipd & Wd are diagonal in nature the computation is reduced to array operations
*/
for (int i=0; i< nsign ; i++) {
double scale_factor = 1 / (a + (Wdr[i]*Wdr[i]));
matrix_scale_row(X1 , i , scale_factor);
}
matrix_assign(X2,X1);
}
void enkf_linalg_rml_enkfX3(matrix_type *X3, matrix_type *VdTr, double *Wdr, matrix_type *X2, int nsign)
{
/*
This routine computes X3 for RML_EnKF module as X3 = Vd *Wd*X2
*/
printf("\nWd: ");
matrix_type *tmp = matrix_alloc_copy(VdTr);
for (int i=0; i< nsign ; i++) {
printf("%5.2f ", Wdr[i]);
matrix_scale_row(tmp, i, Wdr[i]);
}
printf("\n\n");
matrix_matmul_with_transpose( X3 , tmp , X2 , true, false);
matrix_free(tmp);
}
double enkf_linalg_data_mismatch(matrix_type *D , matrix_type *R , matrix_type *Sk)
{
matrix_type * tmp = matrix_alloc (matrix_get_columns(D), matrix_get_columns(R));
double mismatch;
matrix_matmul_with_transpose(tmp, D, R,true, false); // tmp = D' * R, i.e. N-by-p
matrix_matmul(Sk, tmp, D); // Sk = D' * R * D
// Calculate the mismatch
mismatch = matrix_trace(Sk)/(matrix_get_columns(D));
return mismatch;
}
// Cd = SampCov(E) (including (N-1) normalization)
void enkf_linalg_Covariance(matrix_type *Cd, const matrix_type *E, double nsc ,int nrobs)
{
matrix_matmul_with_transpose(Cd, E, E,false,true);
for (int i=0; i< nrobs; i++) {
for (int j=0;j< nrobs; j++) {
if (i!=j)
matrix_iset(Cd, i, j, 0.0);
}
}
nsc = nsc*nsc;
matrix_scale(Cd,nsc);
}
// Scale columns (not rows!) of Um by entries in diagonal Wm
void enkf_linalg_rml_enkfAm(matrix_type * Um, const double * Wm,int nsign1){
for (int i=0; i< nsign1 ; i++) {
double sc = 1 / Wm[i];
matrix_scale_column(Um, i, sc);
}
}
void enkf_linalg_rml_enkfX7(matrix_type * X7, matrix_type * VdT, double * Wdr, double a, matrix_type * X6){
int nsign = matrix_get_rows(VdT);
int ens_size = matrix_get_columns(VdT);
matrix_type *tmp1 = matrix_alloc_copy(VdT);
matrix_type *tmp2 = matrix_alloc(ens_size,ens_size);
for (int i=0; i < nsign ; i++) {
double scale_factor = 1 / ( a + (Wdr[i]*Wdr[i]));
matrix_scale_row( tmp1 , i , scale_factor);
}
matrix_matmul_with_transpose(tmp2, tmp1, VdT, true, false);
matrix_matmul(X7, tmp2, X6);
matrix_free(tmp1);
matrix_free(tmp2);
}

View File

@ -1,549 +0,0 @@
/*
copyright (C) 2011 Statoil ASA, Norway.
The file 'fwd_step_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include <ert/util/type_macros.h>
#include <ert/util/util.h>
#include <ert/util/rng.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/stepwise.h>
#include <ert/util/stringlist.h>
#include <ert/util/double_vector.h>
#include <ert/analysis/fwd_step_enkf.h>
#include <ert/analysis/fwd_step_log.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/module_data_block.h>
#include <ert/analysis/module_data_block_vector.h>
#include <ert/analysis/module_obs_block.h>
#include <ert/analysis/module_obs_block_vector.h>
#define FWD_STEP_ENKF_TYPE_ID 765524
#define DEFAULT_NFOLDS 5
#define DEFAULT_R2_LIMIT 0.99
#define DEFAULT_NUM_THREADS -1
#define NFOLDS_KEY "CV_NFOLDS"
#define R2_LIMIT_KEY "FWD_STEP_R2_LIMIT"
#define DEFAULT_VERBOSE false
#define VERBOSE_KEY "VERBOSE"
#define NUM_THREADS_KEY "NUM_THREADS"
#define LOG_FILE_KEY "LOG_FILE"
#define CLEAR_LOG_KEY "CLEAR_LOG"
struct fwd_step_enkf_data_struct {
UTIL_TYPE_ID_DECLARATION;
stepwise_type * stepwise_data;
rng_type * rng;
int nfolds;
long option_flags;
double r2_limit;
bool verbose;
int num_threads;
fwd_step_log_type * fwd_step_log;
};
static UTIL_SAFE_CAST_FUNCTION_CONST( fwd_step_enkf_data , FWD_STEP_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION( fwd_step_enkf_data , FWD_STEP_ENKF_TYPE_ID )
void fwd_step_enkf_set_nfolds( fwd_step_enkf_data_type * data , int nfolds ) {
data->nfolds = nfolds;
}
void fwd_step_enkf_set_r2_limit( fwd_step_enkf_data_type * data , double limit ) {
data->r2_limit = limit;
}
void fwd_step_enkf_set_verbose( fwd_step_enkf_data_type * data , bool verbose ) {
data->verbose = verbose;
}
void fwd_step_enkf_set_num_threads( fwd_step_enkf_data_type * data , int threads ) {
data->num_threads = threads;
}
void * fwd_step_enkf_data_alloc( rng_type * rng ) {
fwd_step_enkf_data_type * data = util_malloc( sizeof * data );
UTIL_TYPE_ID_INIT( data , FWD_STEP_ENKF_TYPE_ID );
data->stepwise_data = NULL;
data->rng = rng;
data->nfolds = DEFAULT_NFOLDS;
data->r2_limit = DEFAULT_R2_LIMIT;
data->option_flags = ANALYSIS_NEED_ED + ANALYSIS_UPDATE_A + ANALYSIS_SCALE_DATA;
data->verbose = DEFAULT_VERBOSE;
data->num_threads = DEFAULT_NUM_THREADS;
data->fwd_step_log = fwd_step_log_alloc();
return data;
}
void fwd_step_enkf_data_free( void * arg ) {
fwd_step_enkf_data_type * fwd_step_data = fwd_step_enkf_data_safe_cast( arg );
{
if (fwd_step_data != NULL) {
if (fwd_step_data->stepwise_data != NULL) {
stepwise_free( fwd_step_data->stepwise_data );
}
}
}
fwd_step_log_free( fwd_step_data->fwd_step_log );
free( fwd_step_data );
}
//**********************************************
// Log-file related stuff
//**********************************************
static void fwd_step_enkf_write_log_header( fwd_step_enkf_data_type * fwd_step_data, const char * ministep_name, const int nx, const int nd, const int ens_size) {
const char * format = "%-25s%-25s%-25s%-25s\n";
const char * column1 = "Parameter(ActiveIndex)";
const char * column2 = "GlobalIndex";
const char * column3 = "NumAttached";
const char * column4 = "AttachedObs(ActiveIndex)[Percentage sensitivity]";
int nfolds = fwd_step_data->nfolds;
int num_threads = fwd_step_data->num_threads;
double r2_limit = fwd_step_data->r2_limit;
if (fwd_step_log_is_open( fwd_step_data->fwd_step_log )) {
fwd_step_log_line(fwd_step_data->fwd_step_log, "===============================================================================================================================\n");
fwd_step_log_line(fwd_step_data->fwd_step_log, "Ministep : %s\n",ministep_name);
fwd_step_log_line(fwd_step_data->fwd_step_log, "Total number of parameters : %d\n",nx);
fwd_step_log_line(fwd_step_data->fwd_step_log, "Total number of observations: %d\n",nd);
fwd_step_log_line(fwd_step_data->fwd_step_log, "Number of ensembles : %d\n",ens_size);
fwd_step_log_line(fwd_step_data->fwd_step_log, "CV folds : %d\n",nfolds);
fwd_step_log_line(fwd_step_data->fwd_step_log, "Relative R2 tolerance : %f\n",r2_limit);
fwd_step_log_line(fwd_step_data->fwd_step_log, "===============================================================================================================================\n");
fwd_step_log_line(fwd_step_data->fwd_step_log, format, column1, column2, column3, column4);
fwd_step_log_line(fwd_step_data->fwd_step_log, "===============================================================================================================================\n");
}
printf("===============================================================================================================================\n");
printf("Ministep : %s\n",ministep_name);
printf("Total number of parameters : %d\n",nx);
printf("Total number of observations: %d\n",nd);
printf("Number of ensembles : %d\n",ens_size);
printf("CV folds : %d\n",nfolds);
printf("Number of threads : %d\n",num_threads);
printf("Relative R2 tolerance : %f\n",r2_limit);
printf("===============================================================================================================================\n");
printf(format, column1, column2, column3, column4);
printf("===============================================================================================================================\n");
}
static void fwd_step_enkf_write_iter_info( fwd_step_enkf_data_type * data , stepwise_type * stepwise, const char* key, const int data_active_index, const int global_index, const module_info_type * module_info ) {
const char * format = "%-25s%-25d%-25d";
int n_active = stepwise_get_n_active( stepwise);
bool_vector_type * active_set = stepwise_get_active_set(stepwise);
bool has_log = fwd_step_log_is_open( data->fwd_step_log );
module_obs_block_vector_type * module_obs_block_vector = module_info_get_obs_block_vector(module_info);
char * loc_key = util_alloc_string_copy(key);
char * data_active_index_str = util_alloc_sprintf( "(%d)" , data_active_index );
char * cat = util_strcat_realloc(loc_key , data_active_index_str );
if (has_log)
fwd_step_log_line( data->fwd_step_log , format, cat, global_index, n_active);
printf(format, cat, global_index,n_active);
const double sum_beta = stepwise_get_sum_beta(stepwise);
int obs_active_index = 0;
stringlist_type * obs_list = stringlist_alloc_new( );
double_vector_type * r_list = double_vector_alloc(0, 0);
const char * format1 = "%s(%d)[%.1f] ";
for (int ivar = 0; ivar < bool_vector_size( active_set); ivar++) {
if (!bool_vector_iget( active_set , ivar))
continue;
const module_obs_block_type * module_obs_block = module_obs_block_vector_search_module_obs_block(module_obs_block_vector, ivar);
const int* active_indices = module_obs_block_get_active_indices(module_obs_block);
bool all_active = active_indices == NULL; /* Inactive are not present in D */
int row_start = module_obs_block_get_row_start(module_obs_block);
int row_end = module_obs_block_get_row_end(module_obs_block);
const char* obs_key = module_obs_block_get_key(module_obs_block);
const double var_beta = stepwise_iget_beta(stepwise, ivar);
const double var_beta_percent = 100.0 * fabs(var_beta) / sum_beta;
int local_index = 0;
for (int i = row_start; i < row_end; i++) {
if (i == ivar){
if (all_active)
obs_active_index = local_index;
else
obs_active_index = active_indices[local_index];
break;
}
local_index ++;
}
char * obs_list_entry = util_alloc_sprintf(format1 , obs_key, obs_active_index,var_beta_percent);
stringlist_append_copy(obs_list, obs_list_entry);
double_vector_append(r_list, var_beta_percent);
free( obs_list_entry );
}
{
/* Sorting with respect to sensitivity */
perm_vector_type * sort_perm = double_vector_alloc_rsort_perm(r_list);
for (int i = 0; i < stringlist_get_size( obs_list); i++) {
const char * obs_list_entry = stringlist_iget(obs_list, perm_vector_iget(sort_perm, i));
if (has_log)
fwd_step_log_line( data->fwd_step_log , "%s", obs_list_entry);
printf("%s", obs_list_entry);
}
perm_vector_free(sort_perm);
}
if (has_log)
fwd_step_log_line( data->fwd_step_log , "\n");
printf("\n");
stringlist_free(obs_list);
util_safe_free(data_active_index_str);
util_safe_free(cat);
}
/*Main function: */
void fwd_step_enkf_updateA(void * module_data ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D ,
const module_info_type* module_info) {
fwd_step_enkf_data_type * fwd_step_data = fwd_step_enkf_data_safe_cast( module_data );
fwd_step_log_open(fwd_step_data->fwd_step_log);
module_data_block_vector_type * data_block_vector = module_info_get_data_block_vector(module_info);
printf("Running Forward Stepwise regression:\n");
{
int ens_size = matrix_get_columns( S );
int nx = matrix_get_rows( A );
int nd = matrix_get_rows( S );
int nfolds = fwd_step_data->nfolds;
double r2_limit = fwd_step_data->r2_limit;
bool verbose = fwd_step_data->verbose;
int num_kw = module_data_block_vector_get_size(data_block_vector);
#if defined(_OPENMP)
#pragma omp parallel
#pragma omp master
if (fwd_step_data->num_threads == DEFAULT_NUM_THREADS)
fwd_step_data->num_threads = omp_get_num_threads();
#else
fwd_step_data->num_threads = 1;
#endif
if ( ens_size <= nfolds)
util_abort("%s: The number of ensembles must be larger than the CV fold - aborting\n", __func__);
{
matrix_type * St = matrix_alloc( ens_size , nd );
matrix_type * Et = matrix_alloc( ens_size , nd );
/*workS = S' */
matrix_subtract_row_mean( S ); /* Shift away the mean */
St = matrix_alloc_transpose( S );
Et = matrix_alloc_transpose( E );
matrix_type * di = matrix_alloc( 1 , nd );
if (verbose){
char * ministep_name = module_info_get_ministep_name(module_info);
fwd_step_enkf_write_log_header(fwd_step_data, ministep_name, nx, nd, ens_size);
}
int kw,i;
/* This is to avoid a global-to-block search function since the number of parameters could be very large*/
int_vector_type * kw_list = int_vector_alloc(nx, -1);
int_vector_type * local_index_list = int_vector_alloc(nx, -1);
for (kw = 0; kw < num_kw; kw++) {
module_data_block_type * data_block = module_data_block_vector_iget_module_data_block(data_block_vector, kw);
int row_start = module_data_block_get_row_start(data_block);
int row_end = module_data_block_get_row_end(data_block);
for (i = row_start; i < row_end; i++) {
int_vector_iset(kw_list, i, kw);
int_vector_iset(local_index_list, i, i - row_start);
}
}
// =============================================
#pragma omp parallel for schedule(dynamic, 1) num_threads(fwd_step_data->num_threads)
for (i = 0; i < nx; i++) {
int kw_ind = int_vector_iget(kw_list, i);
module_data_block_type * data_block = module_data_block_vector_iget_module_data_block(data_block_vector, kw_ind);
const char * key = module_data_block_get_key(data_block);
const int* active_indices = module_data_block_get_active_indices(data_block);
int active_index = 0;
bool all_active = active_indices == NULL; /* Inactive are not present in A */
stepwise_type * stepwise_data = stepwise_alloc1(ens_size, nd , fwd_step_data->rng, St, Et);
/*Update values of y */
/*Start of the actual update */
matrix_type * y = matrix_alloc( ens_size , 1 );
for (int j = 0; j < ens_size; j++) {
matrix_iset(y , j , 0 , matrix_iget( A, i , j ) );
}
stepwise_set_Y0( stepwise_data , y );
stepwise_estimate(stepwise_data , r2_limit , nfolds );
/*manipulate A directly*/
for (int j = 0; j < ens_size; j++) {
for (int k = 0; k < nd; k++) {
matrix_iset(di , 0 , k , matrix_iget( D , k , j ) );
}
double aij = matrix_iget( A , i , j );
double xHat = stepwise_eval(stepwise_data , di );
matrix_iset(A , i , j , aij + xHat);
}
if (verbose){
int loc_ind = int_vector_iget(local_index_list, i );
if (all_active)
active_index = loc_ind;
else
active_index = active_indices[loc_ind];
fwd_step_enkf_write_iter_info(fwd_step_data, stepwise_data, key, active_index, i, module_info);
}
stepwise_free( stepwise_data );
}
if (verbose)
printf("===============================================================================================================================\n");
printf("Done with stepwise regression enkf\n");
matrix_free( di );
int_vector_free(kw_list);
int_vector_free(local_index_list);
}
}
fwd_step_log_close( fwd_step_data->fwd_step_log );
}
bool fwd_step_enkf_set_double( void * arg , const char * var_name , double value) {
fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , R2_LIMIT_KEY ) == 0)
fwd_step_enkf_set_r2_limit( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
bool fwd_step_enkf_set_int( void * arg , const char * var_name , int value) {
fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , NFOLDS_KEY) == 0)
fwd_step_enkf_set_nfolds( module_data , value); /*Set number of CV folds */
else if (strcmp( var_name , NUM_THREADS_KEY) == 0)
fwd_step_enkf_set_num_threads( module_data , value); /*Set number of OMP threads */
else
name_recognized = false;
return name_recognized;
}
}
bool fwd_step_enkf_set_bool( void * arg , const char * var_name , bool value) {
fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
/*Set verbose */
if (strcmp( var_name , VERBOSE_KEY) == 0)
fwd_step_enkf_set_verbose( module_data , value);
else if (strcmp( var_name , CLEAR_LOG_KEY) == 0)
fwd_step_log_set_clear_log( module_data->fwd_step_log , value );
else
name_recognized = false;
return name_recognized;
}
}
bool fwd_step_enkf_set_string( void * arg , const char * var_name , const char * value) {
fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , LOG_FILE_KEY) == 0)
fwd_step_log_set_log_file( module_data->fwd_step_log , value );
else
name_recognized = false;
return name_recognized;
}
}
long fwd_step_enkf_get_options( void * arg , long flag) {
fwd_step_enkf_data_type * fwd_step_data = fwd_step_enkf_data_safe_cast( arg );
{
return fwd_step_data->option_flags;
}
}
bool fwd_step_enkf_has_var( const void * arg, const char * var_name) {
{
if (strcmp(var_name , NFOLDS_KEY) == 0)
return true;
else if (strcmp(var_name , R2_LIMIT_KEY ) == 0)
return true;
else if (strcmp(var_name , VERBOSE_KEY ) == 0)
return true;
else if (strcmp(var_name , LOG_FILE_KEY) == 0)
return true;
else if (strcmp(var_name , CLEAR_LOG_KEY) == 0)
return true;
else if (strcmp(var_name , NUM_THREADS_KEY) == 0)
return true;
else
return false;
}
}
double fwd_step_enkf_get_double( const void * arg, const char * var_name) {
const fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , R2_LIMIT_KEY ) == 0)
return module_data->r2_limit;
else
return -1;
}
}
int fwd_step_enkf_get_int( const void * arg, const char * var_name) {
const fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , NFOLDS_KEY) == 0)
return module_data->nfolds;
if (strcmp(var_name , NUM_THREADS_KEY) == 0)
return module_data->num_threads;
else
return -1;
}
}
bool fwd_step_enkf_get_bool( const void * arg, const char * var_name) {
const fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , VERBOSE_KEY) == 0)
return module_data->verbose;
else if (strcmp(var_name , CLEAR_LOG_KEY) == 0)
return fwd_step_log_get_clear_log( module_data->fwd_step_log );
else
return false;
}
}
void * fwd_step_enkf_get_ptr( const void * arg , const char * var_name ) {
const fwd_step_enkf_data_type * module_data = fwd_step_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , LOG_FILE_KEY) == 0)
return (void *) fwd_step_log_get_log_file( module_data->fwd_step_log );
else
return NULL;
}
}
#ifdef INTERNAL_LINK
#define LINK_NAME FWD_STEP_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "FWD_STEP_ENKF",
.alloc = fwd_step_enkf_data_alloc,
.freef = fwd_step_enkf_data_free,
.set_int = fwd_step_enkf_set_int ,
.set_double = fwd_step_enkf_set_double ,
.set_bool = fwd_step_enkf_set_bool ,
.set_string = fwd_step_enkf_set_string ,
.get_options = fwd_step_enkf_get_options ,
.initX = NULL ,
.updateA = fwd_step_enkf_updateA,
.init_update = NULL ,
.complete_update = NULL ,
.has_var = fwd_step_enkf_has_var,
.get_int = fwd_step_enkf_get_int ,
.get_double = fwd_step_enkf_get_double ,
.get_bool = fwd_step_enkf_get_bool ,
.get_ptr = fwd_step_enkf_get_ptr
};

View File

@ -1,105 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'fwd_step_log.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ert/util/util.h>
#include <ert/analysis/fwd_step_log.h>
#define DEFAULT_LOG_FILE "fwd_step.out"
#define DEFAULT_CLEAR_LOG false
struct fwd_step_log_struct {
bool clear_log;
char * log_file;
FILE * log_stream;
};
fwd_step_log_type * fwd_step_log_alloc() {
fwd_step_log_type * fwd_step_log = util_malloc( sizeof * fwd_step_log );
fwd_step_log->log_file = NULL;
fwd_step_log->log_stream = NULL;
fwd_step_log_set_log_file( fwd_step_log , DEFAULT_LOG_FILE);
fwd_step_log_set_clear_log( fwd_step_log , DEFAULT_CLEAR_LOG );
return fwd_step_log;
}
bool fwd_step_log_get_clear_log( const fwd_step_log_type * data ) {
return data->clear_log;
}
void fwd_step_log_set_clear_log( fwd_step_log_type * data , bool clear_log) {
data->clear_log = clear_log;
}
void fwd_step_log_set_log_file( fwd_step_log_type * data , const char * log_file ) {
data->log_file = util_realloc_string_copy( data->log_file , log_file );
}
const char * fwd_step_log_get_log_file( const fwd_step_log_type * data) {
return data->log_file;
}
void fwd_step_log_free(fwd_step_log_type * fwd_step_log) {
fwd_step_log_close( fwd_step_log );
util_safe_free( fwd_step_log->log_file );
free( fwd_step_log );
}
void fwd_step_log_open( fwd_step_log_type * fwd_step_log ) {
if (fwd_step_log->log_file) {
if (fwd_step_log->clear_log)
fwd_step_log->log_stream = util_mkdir_fopen( fwd_step_log->log_file , "w");
else
fwd_step_log->log_stream = util_mkdir_fopen( fwd_step_log->log_file , "a");
}
}
bool fwd_step_log_is_open( const fwd_step_log_type * fwd_step_log ) {
if (fwd_step_log->log_stream)
return true;
else
return false;
}
void fwd_step_log_close( fwd_step_log_type * fwd_step_log ) {
if (fwd_step_log->log_stream)
fclose( fwd_step_log->log_stream );
fwd_step_log->log_stream = NULL;
}
void fwd_step_log_line( fwd_step_log_type * fwd_step_log , const char * fmt , ...) {
if (fwd_step_log->log_stream) {
va_list ap;
va_start(ap , fmt);
vfprintf( fwd_step_log->log_stream , fmt , ap );
va_end( ap );
}
}

View File

@ -1,67 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_data_block.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/module_data_block.h>
#define MODULE_DATA_BLOCK_TYPE_ID 73217801
static UTIL_SAFE_CAST_FUNCTION( module_data_block , MODULE_DATA_BLOCK_TYPE_ID);
UTIL_IS_INSTANCE_FUNCTION( module_data_block , MODULE_DATA_BLOCK_TYPE_ID)
module_data_block_type * module_data_block_alloc( const char * key, const int * index_list , const int row_start, const int n_active) {
module_data_block_type * module_data_block = util_malloc( sizeof * module_data_block );
UTIL_TYPE_ID_INIT( module_data_block , MODULE_DATA_BLOCK_TYPE_ID );
module_data_block->key = util_alloc_string_copy( key );
module_data_block->index_list = index_list;
module_data_block->A_row_start = row_start;
module_data_block->n_active = n_active;
return module_data_block;
}
const char * module_data_block_get_key(const module_data_block_type * module_data_block){
return module_data_block->key;
}
const int module_data_block_get_row_start(const module_data_block_type * module_data_block){
return module_data_block->A_row_start;
}
const int module_data_block_get_row_end(const module_data_block_type * module_data_block){
return module_data_block->A_row_start + module_data_block->n_active;
}
const int * module_data_block_get_active_indices(const module_data_block_type * module_data_block ){
return module_data_block->index_list;
}
void module_data_block_free( module_data_block_type * module_data_block ) {
util_safe_free(module_data_block->key);
free( module_data_block );
}
void module_data_block_free__( void * arg ) {
module_data_block_type * data_block = module_data_block_safe_cast( arg );
module_data_block_free( data_block );
}

View File

@ -1,64 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_data_block_vector.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <ert/util/vector.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/module_data_block.h>
#include <ert/analysis/module_data_block_vector.h>
#define MODULE_DATA_BLOCK_VECTOR_TYPE_ID 732178012
struct module_data_block_vector_struct {
UTIL_TYPE_ID_DECLARATION;
vector_type * data_block_vector;
};
UTIL_IS_INSTANCE_FUNCTION( module_data_block_vector , MODULE_DATA_BLOCK_VECTOR_TYPE_ID)
module_data_block_vector_type * module_data_block_vector_alloc( ) {
module_data_block_vector_type * module_data_block_vector = util_malloc( sizeof * module_data_block_vector );
UTIL_TYPE_ID_INIT( module_data_block_vector , MODULE_DATA_BLOCK_VECTOR_TYPE_ID );
module_data_block_vector->data_block_vector = vector_alloc_new();
return module_data_block_vector;
}
void module_data_block_vector_free( module_data_block_vector_type * module_data_block_vector ) {
vector_free( module_data_block_vector->data_block_vector );
free( module_data_block_vector );
}
void module_data_block_vector_add_data_block( module_data_block_vector_type * module_data_block_vector , const module_data_block_type * data_block) {
vector_append_owned_ref(module_data_block_vector->data_block_vector, data_block , module_data_block_free__);
}
module_data_block_type * module_data_block_vector_iget_module_data_block(const module_data_block_vector_type * module_data_block_vector, int index){
return vector_iget(module_data_block_vector->data_block_vector, index);
}
int module_data_block_vector_get_size(const module_data_block_vector_type * module_data_block_vector){
return vector_get_size(module_data_block_vector->data_block_vector);
}

View File

@ -1,66 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_info.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <ert/util/vector.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/module_info.h>
#define MODULE_INFO_TYPE_ID 73780123
struct module_info_struct {
UTIL_TYPE_ID_DECLARATION;
char * ministep_name;
module_data_block_vector_type * data_block_vector;
module_obs_block_vector_type * obs_block_vector;
};
UTIL_IS_INSTANCE_FUNCTION( module_info , MODULE_INFO_TYPE_ID)
module_info_type * module_info_alloc( const char* ministep_name ) {
module_info_type * module_info = util_malloc( sizeof * module_info );
UTIL_TYPE_ID_INIT( module_info , MODULE_INFO_TYPE_ID );
module_info->ministep_name = util_alloc_string_copy( ministep_name );
module_info->data_block_vector = module_data_block_vector_alloc();
module_info->obs_block_vector = module_obs_block_vector_alloc();
return module_info;
}
void module_info_free( module_info_type * module_info ) {
util_safe_free(module_info->ministep_name);
module_data_block_vector_free( module_info->data_block_vector );
module_obs_block_vector_free( module_info->obs_block_vector );
free( module_info );
}
module_data_block_vector_type * module_info_get_data_block_vector(const module_info_type * module_info){
return module_info->data_block_vector;
}
module_obs_block_vector_type * module_info_get_obs_block_vector(const module_info_type * module_info){
return module_info->obs_block_vector;
}
char * module_info_get_ministep_name(const module_info_type * module_info){
return module_info->ministep_name;
}

View File

@ -1,67 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_obs_block.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/module_obs_block.h>
#define MODULE_OBS_BLOCK_TYPE_ID 73217901
static UTIL_SAFE_CAST_FUNCTION( module_obs_block , MODULE_OBS_BLOCK_TYPE_ID);
UTIL_IS_INSTANCE_FUNCTION( module_obs_block , MODULE_OBS_BLOCK_TYPE_ID)
module_obs_block_type * module_obs_block_alloc( const char * key, const int * index_list, const int row_start, const int n_active) {
module_obs_block_type * module_obs_block = util_malloc( sizeof * module_obs_block );
UTIL_TYPE_ID_INIT( module_obs_block , MODULE_OBS_BLOCK_TYPE_ID );
module_obs_block->key = util_alloc_string_copy( key );
module_obs_block->index_list = index_list;
module_obs_block->D_row_start = row_start;
module_obs_block->n_active = n_active;
return module_obs_block;
}
const char * module_obs_block_get_key(const module_obs_block_type * module_obs_block){
return module_obs_block->key;
}
const int module_obs_block_get_row_start(const module_obs_block_type * module_obs_block){
return module_obs_block->D_row_start;
}
const int module_obs_block_get_row_end(const module_obs_block_type * module_obs_block){
return module_obs_block->D_row_start + module_obs_block->n_active;
}
const int * module_obs_block_get_active_indices(const module_obs_block_type * module_obs_block ){
return module_obs_block->index_list;
}
void module_obs_block_free( module_obs_block_type * module_obs_block ) {
util_safe_free(module_obs_block->key);
free( module_obs_block );
}
void module_obs_block_free__( void * arg ) {
module_obs_block_type * obs_block = module_obs_block_safe_cast( arg );
module_obs_block_free( obs_block );
}

View File

@ -1,82 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'module_obs_block_vector.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <ert/util/vector.h>
#include <ert/util/util.h>
#include <ert/util/type_macros.h>
#include <ert/analysis/module_obs_block.h>
#include <ert/analysis/module_obs_block_vector.h>
#define MODULE_OBS_BLOCK_VECTOR_TYPE_ID 732188012
struct module_obs_block_vector_struct {
UTIL_TYPE_ID_DECLARATION;
vector_type * obs_block_vector;
};
UTIL_IS_INSTANCE_FUNCTION( module_obs_block_vector , MODULE_OBS_BLOCK_VECTOR_TYPE_ID)
module_obs_block_vector_type * module_obs_block_vector_alloc() {
module_obs_block_vector_type * module_obs_block_vector = util_malloc( sizeof * module_obs_block_vector );
UTIL_TYPE_ID_INIT( module_obs_block_vector , MODULE_OBS_BLOCK_VECTOR_TYPE_ID );
module_obs_block_vector->obs_block_vector = vector_alloc_new();
return module_obs_block_vector;
}
void module_obs_block_vector_free( module_obs_block_vector_type * module_obs_block_vector ) {
vector_free( module_obs_block_vector->obs_block_vector );
free( module_obs_block_vector );
}
void module_obs_block_vector_add_obs_block( module_obs_block_vector_type * module_obs_block_vector , module_obs_block_type * obs_block) {
vector_append_owned_ref(module_obs_block_vector->obs_block_vector, obs_block , module_obs_block_free__);
}
module_obs_block_type * module_obs_block_vector_iget_module_obs_block(const module_obs_block_vector_type * module_obs_block_vector, int block_index){
return vector_iget(module_obs_block_vector->obs_block_vector, block_index);
}
const module_obs_block_type * module_obs_block_vector_search_module_obs_block(const module_obs_block_vector_type * module_obs_block_vector, int global_index){
/* This function maps from a global index to an observation information block. Will return NULL if block is not found */
int block_nr = 0;
while (true) {
if (block_nr >= module_obs_block_vector_get_size( module_obs_block_vector ))
break;
module_obs_block_type * module_obs_block = module_obs_block_vector_iget_module_obs_block (module_obs_block_vector, block_nr);
int row_start = module_obs_block_get_row_start(module_obs_block);
int row_end = module_obs_block_get_row_end(module_obs_block);
if (global_index >= row_start && global_index < row_end)
return module_obs_block;
block_nr++;
}
return NULL;
}
int module_obs_block_vector_get_size(const module_obs_block_vector_type * module_obs_block_vector){
return vector_get_size(module_obs_block_vector->obs_block_vector);
}

View File

@ -1,212 +0,0 @@
Overview
--------
The ERT application has evolved into a quite complex beast. Originally
the actual EnKF algorithm was located very deep down in the code, and
changes to the EnKF algorithm required detailed knowledge about the
enkf_node objects, the datatype for measurements and observations,
serialisation and so on. Quite complex and fragile stuff.
To facilitate easier development and testing of new update schemes the
core EnKF update step has been factored out as analysis modules, which
are called from the enkf_main scope. The update functions in the
module get ordinary matrices as input, and do not need to know
anything about the internals of the ERT application.
The modules can either be built in, or you can compile your own module
as a shared library and load it runtime. Apart from the initial
loading internal modules and external modules are treated 100%
identically.
How modules work
----------------
The modules are instances of the object type analysis_module_type, and
the enkf_main layer interacts with the module through the
analyis_module instance. The most important part of the
analysis_module type is a list of function pointers to functions which
"actually do the work". In addition to some functions for setting
internal module variables the most core functions are:
init_update()
initX()
updateA()
complete_update()
Of these functions a module should have ONLY ONE of initX() and
updateA(); the initX() function will initialize an X matrix which is
then subsequently used to update the ensemble matrix A. Alternatively
the updateA() function should will directly manipulate the A matrix.
The init_update() and complete_update() functions are optional, they
can be used to avoid repeated initialization calculations. These
functions interact quite closely with the scheme used for local
analysis; so you should understand that in detail before deciding
whether it is worthwile to implement init_update() and
complete_update() functions.
Loading modules
---------------
The loading of modules is based on the dlopen() function to open a
shared a library and map it into the adress space of the current
process, and then the dlsym() function to locate a symbol table which
is a list of function pointers. The only difference between internal
and external modules is in the arguments passed to the dlopen() and
dlsym() function calls:
Loading internal modules
------------------------
Internal modules means modules which have been compiled into the
libanalyis library, i.e. they are already part of the ERT
executable, however before we have "loaded" these modules we have
no way to access them. The current executable is loaded by
passing NULL as argument to dlopen().
When dlopen() has succeded we must use dlsym() to get a handle to
the symbol table. The symbol table is essentially a global
variable in the ERT adress space, and must have a unique name for
each module.
Loading external modules
------------------------
External modules are ordinary shared libraries. To load an external
module the name of the shared library must be given to the dlopen()
function, normal rules for runtime loading of dynamic libraries
apply - i.e. the shared library must be in a location where the
dynamic linker can find it. The name of module should be a
filename, including the .so extension. undo
When dlopen() has succeded we must use dlsym() to get a handle to
the symbol table; when the module loading is hidden behind a
dlopen() call we have essentially created a module namespace, and
the symbol tables from the different modules can have the same
name. For convenience we assume that the symbol table is given by
the name defined by the symbol EXTERNAL_MODULE_TABLE in
analysis_module.h.
In practice all of is handled by the functions:
analysis_module_type * analysis_module_alloc_internal( );
analysis_module_type * analysis_module_alloc_external( );
symbol_table
------------
Interacting with modules
------------------------
The modules can implement four different functions to set a scalar
value. The four functions have signature:
bool set_int (void * module_data, const char * var_name , int value)
bool set_double( void * module_data , const char * var_name , double value)
bool set_bool( void * module_data , const char * var_name , bool value )
bool set_string( void * module_data , const char * var_name , const char * value )
Common for all these functions is:
1. It is not necessary to implement these functions; if you know
that the module has no internal integer variables which should be
user-modifiable you can just set the set_int function pointer to
NULL.
2. If the module recognizes the variable name and actually sets an
internal variable it should return true, otherwise return false.
3. The set_xxx() functions are called from the wrapper function
analysis_module_set_var(); when calling the wrapper function the
value variable is a string which we try to convert to int, double
and bool respectively and then cascade through the functions in
the order listed above. This involves two things:
a) A module has an internal variable namespace which is shared
among all variable types.
b) If the string value argument is incorrectly formatted,
i.e. an integer is passed as "12x" the correct low level
function will not be called.
The method to get information out from the module is much more
limited. Each module should contain an internal variable:
long option_flags;
And when instantiating the module data you should initialize the
option_flags variable by adding together the relevant option flags
from analysis_module.h. The enkf_main_UPDATE() method which invokes
the module functions will inspect the option_flags to see which
variables to pass to the module, and which module functions to invoke,
so this must be correct.
Example
-------
The module/file std_enkf.c is commented quite heavily to serve as an
example.
---------------------------------------------------------------------
With the analysis modules we have essentially got a three layer
design:
1. The ert core layer which creates/loads a list of analysis_module
instances.
2. analysis_module instances are a thing layer which:
a) Hold on to specific analysis implementations like e.g. the
std_enkf implementation on one side.
b) Present a uniform module interface to the ert layer on the
'other side'.
3. Specific analysis module implementations like the std_enkf.
In fine ASCII art:
.
+----------------------+ . +---------------------------+
| Analysis module | . | Implementation std_enkf |
+----------------------+ . +---------------------------+
| | /------> | std_enkf_alloc() |
----------------------> | | / . | std_enkf_free() |
/ | X |o--------> | std_enkf_get_options() |
/ | | \ . | std_enkf_initX() |
+------------------------------------------+ / | | \------> | std_enkf_set_int() |
| The ert core layer; in particular | / | | . | std_enkf_set_double() |
| the following functions: | / +----------------------+ . +---------------------------+
| - analysis_config_load_external_module() |o .
| - analysis_config_load_internal_module() | \ +----------------------+ . +---------------------------+
| - enkf_main_module_update() | \ | Analysis module | . | Implementation sqrt_enkf |
+------------------------------------------+ \ +----------------------+ . +---------------------------+
\ | | /------> | sqrt_enkf_alloc() |
\ | | / . | sqrt_enkf_free() |
\---------------------> | |o--------> | sqrt_enkf_get_options() |
\ | X | \ . | sqrt_enkf_initX() |
\ | | \------> | sqrt_enkf_set_int() |
\ | | . | sqrt_enkf_set_double() |
\ +----------------------+ . +---------------------------+
\ .
In the ert core layer the \ +----------------------+ . +---------------------------+
different analysis module \ | Analysis module | . | Implementation cv_enkf |
instances are collected in \ +----------------------+ . +---------------------------+
a hash table, and all function \ | | /------> | cv_enkf_alloc() |
invocations go through the \ | | / . | cv_enkf_free() |
functions in the analysis_module -----------> | |o--------> | cv_enkf_get_options() |
layer. | X | \ . | cv_enkf_initX() |
| | \------> | cv_enkf_set_int() |
| | . | cv_enkf_set_double() |
+----------------------+ . +---------------------------+
.
.
.
.
.
The links between the analysis
modules and the std_enkf, sqrt_enkf
and cv_enkf implementations are
in terms of function pointers. These
links are established runtime, and
the vertical dotted line represents
an opaque wall which ert core layer
can not see through.

View File

@ -1,86 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'null_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ert/util/util.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
void null_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D) {
matrix_diag_set_scalar( X , 1.0 );
}
long null_enkf_get_options( void * arg , long flag ) {
return 0L;
}
/**
gcc -fpic -c <object_file> -I?? <src_file>
gcc -shared -o <lib_file> <object_files>
*/
#ifdef INTERNAL_LINK
#define LINK_NAME NULL_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "NULL_ENKF",
.alloc = NULL ,
.freef = NULL ,
.set_int = NULL ,
.set_double = NULL ,
.set_bool = NULL ,
.set_string = NULL ,
.get_options = null_enkf_get_options,
.initX = null_enkf_initX ,
.updateA = NULL,
.init_update = NULL,
.complete_update = NULL,
.has_var = NULL,
.get_int = NULL,
.get_double = NULL,
.get_ptr = NULL,
};

View File

@ -1,223 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'sqrt_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ert/util/util.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/std_enkf.h>
/*
The sqrt_enkf module performs a EnKF update based on the square root
scheme. Observe that this module shares quite a lot of
implementation with the std_enkf module.
*/
#define SQRT_ENKF_TYPE_ID 268823
typedef struct {
UTIL_TYPE_ID_DECLARATION;
std_enkf_data_type * std_data;
matrix_type * randrot;
rng_type * rng;
long options;
} sqrt_enkf_data_type;
static UTIL_SAFE_CAST_FUNCTION( sqrt_enkf_data , SQRT_ENKF_TYPE_ID )
static UTIL_SAFE_CAST_FUNCTION_CONST( sqrt_enkf_data , SQRT_ENKF_TYPE_ID )
void * sqrt_enkf_data_alloc( rng_type * rng ) {
sqrt_enkf_data_type * data = util_malloc( sizeof * data );
UTIL_TYPE_ID_INIT( data , SQRT_ENKF_TYPE_ID );
data->std_data = std_enkf_data_alloc( rng );
data->randrot = NULL;
data->rng = rng;
data->options = ANALYSIS_SCALE_DATA;
return data;
}
void sqrt_enkf_data_free( void * data ) {
sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast( data );
{
std_enkf_data_free( module_data->std_data );
free( module_data );
}
}
bool sqrt_enkf_set_double( void * arg , const char * var_name , double value) {
sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast( arg );
{
if (std_enkf_set_double( module_data->std_data , var_name , value ))
return true;
else {
/* Could in principle set sqrt specific variables here. */
return false;
}
}
}
bool sqrt_enkf_set_int( void * arg , const char * var_name , int value) {
sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast( arg );
{
if (std_enkf_set_int( module_data->std_data , var_name , value ))
return true;
else {
/* Could in principle set sqrt specific variables here. */
return false;
}
}
}
void sqrt_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type *D ) {
sqrt_enkf_data_type * data = sqrt_enkf_data_safe_cast( module_data );
{
int ncomp = std_enkf_get_subspace_dimension( data->std_data );
double truncation = std_enkf_get_truncation( data->std_data );
int nrobs = matrix_get_rows( S );
int ens_size = matrix_get_columns( S );
int nrmin = util_int_min( ens_size , nrobs);
matrix_type * W = matrix_alloc(nrobs , nrmin);
double * eig = util_calloc( nrmin , sizeof * eig );
matrix_subtract_row_mean( S ); /* Shift away the mean */
enkf_linalg_lowrankCinv( S , R , W , eig , truncation , ncomp);
enkf_linalg_init_sqrtX( X , S , data->randrot , dObs , W , eig , false);
matrix_free( W );
free( eig );
enkf_linalg_checkX( X , false );
}
}
long sqrt_enkf_get_options( void * arg , long flag ) {
sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast( arg );
{
return module_data->options;
}
}
// Called from analysis_module.c: analysis_module_init_update()
void sqrt_enkf_init_update( void * arg ,
const bool_vector_type * ens_mask,
const matrix_type * S ,
const matrix_type * R ,
const matrix_type * dObs ,
const matrix_type * E ,
const matrix_type * D ) {
sqrt_enkf_data_type * sqrt_data = sqrt_enkf_data_safe_cast( arg );
{
int ens_size = matrix_get_columns( S );
sqrt_data->randrot = enkf_linalg_alloc_mp_randrot( ens_size , sqrt_data->rng );
}
}
void sqrt_enkf_complete_update( void * arg ) {
sqrt_enkf_data_type * sqrt_data = sqrt_enkf_data_safe_cast( arg );
{
matrix_free( sqrt_data->randrot );
sqrt_data->randrot = NULL;
}
}
bool sqrt_enkf_has_var( const void * arg, const char * var_name) {
const sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast_const( arg );
{
return std_enkf_has_var(module_data->std_data, var_name);
}
}
double sqrt_enkf_get_double( const void * arg, const char * var_name) {
const sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast_const( arg );
{
return std_enkf_get_double( module_data->std_data , var_name);
}
}
int sqrt_enkf_get_int( const void * arg, const char * var_name) {
const sqrt_enkf_data_type * module_data = sqrt_enkf_data_safe_cast_const( arg );
{
return std_enkf_get_int( module_data->std_data , var_name);
}
}
/*****************************************************************/
#ifdef INTERNAL_LINK
#define LINK_NAME SQRT_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "SQRT_ENKF",
.alloc = sqrt_enkf_data_alloc,
.freef = sqrt_enkf_data_free,
.set_int = sqrt_enkf_set_int ,
.set_double = sqrt_enkf_set_double ,
.set_bool = NULL ,
.set_string = NULL ,
.initX = sqrt_enkf_initX ,
.updateA = NULL,
.init_update = sqrt_enkf_init_update,
.complete_update = sqrt_enkf_complete_update,
.get_options = sqrt_enkf_get_options,
.has_var = sqrt_enkf_has_var,
.get_int = sqrt_enkf_get_int,
.get_double = sqrt_enkf_get_double,
.get_bool = NULL,
.get_ptr = NULL
};

View File

@ -1,368 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'std_enkf.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ert/util/util.h>
#include <ert/util/matrix.h>
#include <ert/util/matrix_blas.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
#include <ert/analysis/analysis_table.h>
#include <ert/analysis/enkf_linalg.h>
#include <ert/analysis/std_enkf.h>
/*
A random 'magic' integer id which is used for run-time type checking
of the input data.
*/
#define STD_ENKF_TYPE_ID 261123
/*
Observe that only one of the settings subspace_dimension and
truncation can be valid at a time; otherwise the svd routine will
fail. This implies that the set_truncation() and
set_subspace_dimension() routines will set one variable, AND
INVALIDATE THE OTHER. For most situations this will be OK, but if
you have repeated calls to both of these functions the end result
might be a surprise.
*/
#define INVALID_SUBSPACE_DIMENSION -1
#define INVALID_TRUNCATION -1
#define DEFAULT_SUBSPACE_DIMENSION INVALID_SUBSPACE_DIMENSION
#define DEFAULT_USE_EE false
#define DEFAULT_USE_GE false
#define DEFAULT_ANALYSIS_SCALE_DATA true
/*
The configuration data used by the std_enkf module is contained in a
std_enkf_data_struct instance. The data type used for the std_enkf
module is quite simple; with only a few scalar variables, but there
are essentially no limits to what you can pack into such a datatype.
All the functions in the module have a void pointer as the first
argument, this will immediately be casted to a std_enkf_data_type
instance, to get some type safety the UTIL_TYPE_ID system should be
used (see documentation in util.h)
The data structure holding the data for your analysis module should
be created and initialized by a constructor, which should be
registered with the '.alloc' element of the analysis table; in the
same manner the desctruction of this data should be handled by a
destructor or free() function registered with the .freef field of
the analysis table.
*/
struct std_enkf_data_struct {
UTIL_TYPE_ID_DECLARATION;
double truncation; // Controlled by config key: ENKF_TRUNCATION_KEY
int subspace_dimension; // Controlled by config key: ENKF_NCOMP_KEY (-1: use Truncation instead)
long option_flags;
bool use_EE;
bool use_GE;
bool analysis_scale_data;
};
static UTIL_SAFE_CAST_FUNCTION_CONST( std_enkf_data , STD_ENKF_TYPE_ID )
/*
This is a macro which will expand to generate a function:
std_enkf_data_type * std_enkf_data_safe_cast( void * arg ) {}
which is used for runtime type checking of all the functions which
accept a void pointer as first argument.
*/
static UTIL_SAFE_CAST_FUNCTION( std_enkf_data , STD_ENKF_TYPE_ID )
double std_enkf_get_truncation( std_enkf_data_type * data ) {
return data->truncation;
}
int std_enkf_get_subspace_dimension( std_enkf_data_type * data ) {
return data->subspace_dimension;
}
void std_enkf_set_truncation( std_enkf_data_type * data , double truncation ) {
data->truncation = truncation;
if (truncation > 0.0)
data->subspace_dimension = INVALID_SUBSPACE_DIMENSION;
}
void std_enkf_set_subspace_dimension( std_enkf_data_type * data , int subspace_dimension) {
data->subspace_dimension = subspace_dimension;
if (subspace_dimension > 0)
data->truncation = INVALID_TRUNCATION;
}
void * std_enkf_data_alloc( rng_type * rng) {
std_enkf_data_type * data = util_malloc( sizeof * data );
UTIL_TYPE_ID_INIT( data , STD_ENKF_TYPE_ID );
std_enkf_set_truncation( data , DEFAULT_ENKF_TRUNCATION_ );
std_enkf_set_subspace_dimension( data , DEFAULT_SUBSPACE_DIMENSION );
data->option_flags = ANALYSIS_NEED_ED;
data->use_EE = DEFAULT_USE_EE;
data->use_GE = DEFAULT_USE_GE;
data->analysis_scale_data = DEFAULT_ANALYSIS_SCALE_DATA;
return data;
}
void std_enkf_data_free( void * data ) {
free( data );
}
static void std_enkf_initX__( matrix_type * X ,
matrix_type * S ,
matrix_type * R ,
matrix_type * E ,
matrix_type * D ,
double truncation,
int ncomp,
bool bootstrap ,
bool use_EE ,
bool use_GE) {
int nrobs = matrix_get_rows( S );
int ens_size = matrix_get_columns( S );
int nrmin = util_int_min( ens_size , nrobs);
matrix_type * W = matrix_alloc(nrobs , nrmin);
double * eig = util_calloc( nrmin , sizeof * eig);
matrix_subtract_row_mean( S ); /* Shift away the mean */
if (use_EE) {
if (use_GE) {
enkf_linalg_lowrankE( S , E , W , eig , truncation , ncomp);
}
else {
matrix_type * Et = matrix_alloc_transpose( E );
matrix_type * Cee = matrix_alloc_matmul( E , Et );
matrix_scale( Cee , 1.0 / (ens_size - 1));
enkf_linalg_lowrankCinv( S , Cee , W , eig , truncation , ncomp);
matrix_free( Et );
matrix_free( Cee );
}
}
else {
enkf_linalg_lowrankCinv( S , R , W , eig , truncation , ncomp);
}
enkf_linalg_init_stdX( X , S , D , W , eig , bootstrap);
matrix_free( W );
free( eig );
enkf_linalg_checkX( X , bootstrap );
}
void std_enkf_initX(void * module_data ,
matrix_type * X ,
matrix_type * A ,
matrix_type * S ,
matrix_type * R ,
matrix_type * dObs ,
matrix_type * E ,
matrix_type * D) {
std_enkf_data_type * data = std_enkf_data_safe_cast( module_data );
{
int ncomp = data->subspace_dimension;
double truncation = data->truncation;
std_enkf_initX__(X,S,R,E,D,truncation,ncomp,false,data->use_EE,data->use_GE);
}
}
bool std_enkf_set_double( void * arg , const char * var_name , double value) {
std_enkf_data_type * module_data = std_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_TRUNCATION_KEY_) == 0)
std_enkf_set_truncation( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
bool std_enkf_set_int( void * arg , const char * var_name , int value) {
std_enkf_data_type * module_data = std_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , ENKF_NCOMP_KEY_) == 0)
std_enkf_set_subspace_dimension( module_data , value );
else
name_recognized = false;
return name_recognized;
}
}
bool std_enkf_set_bool( void * arg , const char * var_name , bool value) {
std_enkf_data_type * module_data = std_enkf_data_safe_cast( arg );
{
bool name_recognized = true;
if (strcmp( var_name , USE_EE_KEY_) == 0)
module_data->use_EE = value;
else if (strcmp( var_name , USE_GE_KEY_) == 0)
module_data->use_GE = value;
else if (strcmp( var_name , ANALYSIS_SCALE_DATA_KEY_) == 0)
module_data->analysis_scale_data = value;
else
name_recognized = false;
return name_recognized;
}
}
long std_enkf_get_options( void * arg , long flag ) {
std_enkf_data_type * module_data = std_enkf_data_safe_cast( arg );
int scale_option = (module_data->analysis_scale_data) ? ANALYSIS_SCALE_DATA : 0;
return module_data->option_flags + scale_option;
}
bool std_enkf_has_var( const void * arg, const char * var_name) {
{
if (strcmp(var_name , ENKF_NCOMP_KEY_) == 0)
return true;
else if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return true;
else if (strcmp(var_name , USE_EE_KEY_) == 0)
return true;
else if (strcmp(var_name , USE_GE_KEY_) == 0)
return true;
else if (strcmp(var_name , ANALYSIS_SCALE_DATA_KEY_) == 0)
return true;
else
return false;
}
}
double std_enkf_get_double( const void * arg, const char * var_name) {
const std_enkf_data_type * module_data = std_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_TRUNCATION_KEY_) == 0)
return module_data->truncation;
else
return -1;
}
}
int std_enkf_get_int( const void * arg, const char * var_name) {
const std_enkf_data_type * module_data = std_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , ENKF_NCOMP_KEY_) == 0)
return module_data->subspace_dimension;
else
return -1;
}
}
bool std_enkf_get_bool( const void * arg, const char * var_name) {
const std_enkf_data_type * module_data = std_enkf_data_safe_cast_const( arg );
{
if (strcmp(var_name , USE_EE_KEY_) == 0)
return module_data->use_EE;
else if (strcmp(var_name , USE_GE_KEY_) == 0)
return module_data->use_GE;
else if (strcmp(var_name , ANALYSIS_SCALE_DATA_KEY_) == 0)
return module_data->analysis_scale_data;
else
return false;
}
}
/**
gcc -fpic -c <object_file> -I?? <src_file>
gcc -shared -o <lib_file> <object_files>
*/
#ifdef INTERNAL_LINK
#define LINK_NAME STD_ENKF
#else
#define LINK_NAME EXTERNAL_MODULE_SYMBOL
#endif
analysis_table_type LINK_NAME = {
.name = "STD_ENKF",
.alloc = std_enkf_data_alloc,
.freef = std_enkf_data_free,
.set_int = std_enkf_set_int ,
.set_double = std_enkf_set_double ,
.set_bool = std_enkf_set_bool,
.set_string = NULL ,
.get_options = std_enkf_get_options ,
.initX = std_enkf_initX ,
.updateA = NULL,
.init_update = NULL,
.complete_update = NULL,
.has_var = std_enkf_has_var,
.get_int = std_enkf_get_int,
.get_double = std_enkf_get_double,
.get_bool = std_enkf_get_bool,
.get_ptr = NULL,
};

View File

@ -1,21 +0,0 @@
ert_module_name( VAR_RML rml_enkf ${LIBRARY_OUTPUT_PATH} )
add_executable(analysis_test_external_module analysis_test_external_module.c )
target_link_libraries( analysis_test_external_module analysis util test_util )
add_test( analysis_module_rml ${EXECUTABLE_OUTPUT_PATH}/analysis_test_external_module "RML_ENKF" ${VAR_RML} 41
ITER:45
USE_PRIOR:False
LAMBDA_REDUCE:0.10
LAMBDA_INCREASE:2.5
ENKF_TRUNCATION:0.77
LAMBDA0:0.25
LAMBDA_MIN:0.01
LOG_FILE:LogFile.txt
CLEAR_LOG:True
LAMBDA_RECALCULATE:True )
add_executable( analysis_test_module_info analysis_test_module_info.c )
target_link_libraries( analysis_test_module_info analysis util test_util)
add_test( analysis_test_module_info ${EXECUTABLE_OUTPUT_PATH}/analysis_test_module_info )

View File

@ -1,106 +0,0 @@
/*
Copyright (C) 2013 Statoil ASA, Norway.
The file 'analysis_test_external_module.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <ert/util/util.h>
#include <ert/util/test_util.h>
#include <ert/util/rng.h>
#include <ert/analysis/analysis_module.h>
void test_set_get(analysis_module_type * module , const char * var_value) {
char * var , *string_value;
util_binary_split_string( var_value , ":" , false , &var , &string_value);
if (var && string_value) {
printf("Testing variable:%s \n",var);
while (true) {
int int_value;
double double_value;
bool bool_value;
test_assert_true(analysis_module_has_var( module , var ));
if (util_sscanf_int( string_value , &int_value)) {
test_assert_true(analysis_module_set_var( module , var , string_value ));
test_assert_int_equal( int_value , analysis_module_get_int( module , var ));
break;
}
if (util_sscanf_double( string_value , &double_value)) {
test_assert_true(analysis_module_set_var( module , var , string_value ));
test_assert_double_equal( double_value , analysis_module_get_double( module , var ));
break;
}
if (util_sscanf_bool( string_value , &bool_value)) {
test_assert_true(analysis_module_set_var( module , var , string_value ));
test_assert_bool_equal( bool_value , analysis_module_get_bool( module , var ));
break;
}
test_assert_true(analysis_module_set_var( module , var , string_value ));
test_assert_string_equal( string_value , (const char *) analysis_module_get_ptr( module , var ));
break;
}
} else {
fprintf(stderr,"Invalid test input data: %s -> could not split in var:value\n" , var_value);
exit(1);
}
}
void load_module( rng_type * rng , const char * user_name , const char * lib_name, const char * options_str , int nvar , const char ** var_list) {
long flags = strtol(options_str , NULL , 10);
analysis_module_type * analysis_module = analysis_module_alloc_external(rng , lib_name);
printf("Loading:%s \n" , lib_name);
test_assert_string_equal( EXTERNAL_MODULE_NAME , analysis_module_get_table_name(analysis_module));
if (util_is_abs_path(lib_name))
test_assert_string_equal( lib_name , analysis_module_get_lib_name(analysis_module));
test_assert_true( analysis_module_is_instance( analysis_module));
{
for (int i=0; i < nvar; i++)
test_set_get( analysis_module , var_list[i] );
}
test_assert_false( analysis_module_has_var(analysis_module , "DoesNotHaveThisVariable"));
test_assert_true( analysis_module_check_option( analysis_module , flags));
flags += 1;
test_assert_false( analysis_module_check_option( analysis_module , flags));
analysis_module_free( analysis_module);
}
int main(int argc , char ** argv) {
const char * user_name = argv[1];
const char * lib_name = argv[2];
const char * options_str = argv[3];
int nvar = argc - 4;
rng_type * rng = rng_alloc( MZRAN , INIT_DEFAULT);
load_module(rng , user_name , lib_name , options_str , nvar , (const char **) &argv[4]);
rng_free( rng );
exit(0);
}

View File

@ -1,50 +0,0 @@
/*
Copyright (C) 2016 Statoil ASA, Norway.
The file 'analysis_test_module_info.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <ert/util/test_util.h>
#include <ert/analysis/module_info.h>
int main(int argc , char ** argv) {
const char* ministep_name = "SOME MINISTEP";
module_info_type * module_info = module_info_alloc( ministep_name );
test_assert_true( module_info_is_instance( module_info ));
module_data_block_vector_type * module_data_block_vector = module_info_get_data_block_vector(module_info);
test_assert_true( module_data_block_vector_is_instance( module_data_block_vector ));
module_obs_block_vector_type * module_obs_block_vector = module_info_get_obs_block_vector(module_info);
test_assert_true( module_obs_block_vector_is_instance( module_obs_block_vector ));
int index_list[1] = { 1 };
module_data_block_type * module_data_block = module_data_block_alloc( "PARAMETER", &index_list[0], 0, 1 );
test_assert_true( module_data_block_is_instance( module_data_block ));
module_data_block_vector_add_data_block(module_data_block_vector, module_data_block);
module_obs_block_type * module_obs_block = module_obs_block_alloc( "OBS", &index_list[0], 0, 1 );
test_assert_true( module_obs_block_is_instance( module_obs_block ));
module_obs_block_vector_add_obs_block(module_obs_block_vector, module_obs_block);
module_info_free( module_info );
exit(0);
}

View File

@ -1,4 +0,0 @@
add_subdirectory( src )
if (BUILD_TESTS)
add_subdirectory( tests )
endif()

View File

@ -1,213 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf_test.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <conf.h>
int main()
{
const char * enkf_conf_help = "The main enkf conf shall contain neccessary infomation to run the enkf.";
conf_class_type * enkf_conf_class = conf_class_alloc_empty("ENKF_conf", true, false, enkf_conf_help);
conf_class_set_help(enkf_conf_class, enkf_conf_help);
/** Create and insert HISTORY_OBSERVATION class. */
{
const char * help_class_history_observation = "The class HISTORY_OBSERVATION is used to condition on a time series from the production history. The name of the an instance is used to define the item to condition on, and should be in summary.x syntax. E.g., creating a HISTORY_OBSERVATION instance with name GOPR:P4 conditions on GOPR for group P4.";
conf_class_type * history_observation_class = conf_class_alloc_empty("HISTORY_OBSERVATION", false, false, help_class_history_observation);
conf_class_set_help(history_observation_class, help_class_history_observation);
const char * help_item_spec_error_mode = "The string ERROR_MODE gives the error mode for the observation.";
conf_item_spec_type * item_spec_error_mode = conf_item_spec_alloc("ERROR_MODE", true, DT_STR, help_item_spec_error_mode);
conf_item_spec_set_help(item_spec_error_mode, help_item_spec_error_mode);
conf_item_spec_add_restriction(item_spec_error_mode, "rel");
conf_item_spec_add_restriction(item_spec_error_mode, "abs");
conf_item_spec_add_restriction(item_spec_error_mode, "relmin");
conf_item_spec_set_default_value(item_spec_error_mode, "rel");
const char * help_item_spec_error = "The positive floating number ERROR gives the standard deviation (abs) or the relative uncertainty (rel/relmin) of the observations.";
conf_item_spec_type * item_spec_error = conf_item_spec_alloc("ERROR", true, DT_POSFLOAT, help_item_spec_error);
conf_item_spec_set_default_value(item_spec_error, "0.10");
conf_item_spec_set_help(item_spec_error, help_item_spec_error);
const char * help_item_spec_error_min = "The positive floating point number ERROR_MIN gives the minimum value for the standard deviation of the observation when relmin is used.";
conf_item_spec_type * item_spec_error_min = conf_item_spec_alloc("ERROR_MIN", true, DT_POSFLOAT, help_item_spec_error_min);
conf_item_spec_set_default_value(item_spec_error_min, "0.10");
conf_item_spec_set_help(item_spec_error_min, help_item_spec_error_min);
conf_class_insert_owned_item_spec(history_observation_class, item_spec_error_mode);
conf_class_insert_owned_item_spec(history_observation_class, item_spec_error);
conf_class_insert_owned_item_spec(history_observation_class, item_spec_error_min);
conf_class_insert_owned_sub_class(enkf_conf_class, history_observation_class);
}
/** Create and insert SUMMARY_OBSERVATION class. */
{
const char * help_class_summary_observation = "The class SUMMARY_OBSERVATION can be used to condition on any observation whos simulated value is written to the summary file.";
conf_class_type * summary_observation_class = conf_class_alloc_empty("SUMMARY_OBSERVATION", false, false, help_class_summary_observation);
conf_class_set_help(summary_observation_class, help_class_summary_observation);
const char * help_item_spec_value = "The floating point number VALUE gives the observed value.";
conf_item_spec_type * item_spec_value = conf_item_spec_alloc("VALUE", true, DT_FLOAT, help_item_spec_value);
conf_item_spec_set_help(item_spec_value, help_item_spec_value);
const char * help_item_spec_error = "The positive floating point number ERROR is the standard deviation of the observed value.";
conf_item_spec_type * item_spec_error = conf_item_spec_alloc("ERROR", true, DT_POSFLOAT, help_item_spec_error);
conf_item_spec_set_help(item_spec_error, help_item_spec_error);
const char * help_item_spec_date = "The DATE item gives the date of the observation. Format is dd/mm/yyyy.";
conf_item_spec_type * item_spec_date = conf_item_spec_alloc("DATE", false, DT_DATE, help_item_spec_date);
conf_item_spec_set_help(item_spec_date, help_item_spec_date);
const char * help_item_spec_days = "The DAYS item gives the observation time as days after simulation start.";
conf_item_spec_type * item_spec_days = conf_item_spec_alloc("DAYS", false, DT_POSFLOAT, help_item_spec_days);
conf_item_spec_set_help(item_spec_days, help_item_spec_days);
const char * help_item_spec_restart = "The RESTART item gives the observation time as the ECLIPSE restart nr.";
conf_item_spec_type * item_spec_restart = conf_item_spec_alloc("RESTART", false, DT_POSINT, help_item_spec_restart);
conf_item_spec_set_help(item_spec_restart, help_item_spec_restart);
const char * help_item_spec_sumkey = "The string SUMMARY_KEY is used to look up the simulated value in the summary file. It has the same format as the summary.x program, e.g. WOPR:P4";
conf_item_spec_type * item_spec_sumkey = conf_item_spec_alloc("KEY", true, DT_STR, help_item_spec_sumkey);
conf_item_spec_set_help(item_spec_sumkey, help_item_spec_sumkey);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_value);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_error);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_date);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_days);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_restart);
conf_class_insert_owned_item_spec(summary_observation_class, item_spec_sumkey);
/** Create a mutex on DATE, DAYS and RESTART. */
conf_item_mutex_type * time_mutex = conf_class_new_item_mutex(summary_observation_class , true , false);
conf_item_mutex_add_item_spec(time_mutex, item_spec_date);
conf_item_mutex_add_item_spec(time_mutex, item_spec_days);
conf_item_mutex_add_item_spec(time_mutex, item_spec_restart);
conf_class_insert_owned_sub_class(enkf_conf_class, summary_observation_class);
}
/** Create and insert BLOCK_OBSERVATION class. */
{
const char * help_class_block_observation = "The class BLOCK_OBSERVATION can be used to condition on an observation whos simulated values are block/cell values of a field, e.g. RFT tests.";
conf_class_type * block_observation_class = conf_class_alloc_empty("BLOCK_OBSERVATION", false, false, help_class_block_observation);
conf_class_set_help(block_observation_class, help_class_block_observation);
const char * help_item_spec_field = "The item FIELD gives the observed field. E.g., ECLIPSE fields such as PRESSURE, SGAS or any user defined fields such as PORO or PERMX.";
conf_item_spec_type * item_spec_field = conf_item_spec_alloc("FIELD", true, DT_STR, help_item_spec_field);
conf_item_spec_set_help(item_spec_field, help_item_spec_field);
const char * help_item_spec_date = "The DATE item gives the date of the observation. Format is dd/mm/yyyy.";
conf_item_spec_type * item_spec_date = conf_item_spec_alloc("DATE", true, DT_DATE, help_item_spec_date);
conf_item_spec_set_help(item_spec_date, help_item_spec_date);
conf_class_insert_owned_item_spec(block_observation_class, item_spec_field);
conf_class_insert_owned_item_spec(block_observation_class, item_spec_date);
/** Create and insert the sub class OBS. */
{
const char * help_class_obs = "The class OBS is used to specify a single observed point.";
conf_class_type * obs_class = conf_class_alloc_empty("OBS", true, true , help_class_obs);
conf_class_set_help(obs_class, help_class_obs);
const char * help_item_i = "The item I gives the I index of the block observation.";
conf_item_spec_type * item_spec_i = conf_item_spec_alloc("I", true, DT_POSINT, help_item_i);
conf_item_spec_set_help(item_spec_i, help_item_i);
const char * help_item_j = "The item J gives the J index of the block observation.";
conf_item_spec_type * item_spec_j = conf_item_spec_alloc("J", true, DT_POSINT, help_item_j);
conf_item_spec_set_help(item_spec_j, help_item_j);
const char * help_item_k = "The item K gives the K index of the block observation.";
conf_item_spec_type * item_spec_k = conf_item_spec_alloc("K", true, DT_POSINT, help_item_k);
conf_item_spec_set_help(item_spec_k, help_item_k);
const char * help_item_spec_value = "The floating point number VALUE gives the observed value.";
conf_item_spec_type * item_spec_value = conf_item_spec_alloc("VALUE", true, DT_FLOAT, help_item_spec_value);
conf_item_spec_set_help(item_spec_value, help_item_spec_value);
const char * help_item_spec_error = "The positive floating point number ERROR is the standard deviation of the observed value.";
conf_item_spec_type * item_spec_error = conf_item_spec_alloc("ERROR", true, DT_POSFLOAT, help_item_spec_error);
conf_item_spec_set_help(item_spec_error, help_item_spec_error);
conf_class_insert_owned_item_spec(obs_class, item_spec_i);
conf_class_insert_owned_item_spec(obs_class, item_spec_j);
conf_class_insert_owned_item_spec(obs_class, item_spec_k);
conf_class_insert_owned_item_spec(obs_class, item_spec_value);
conf_class_insert_owned_item_spec(obs_class, item_spec_error);
conf_class_insert_owned_sub_class(block_observation_class, obs_class);
}
conf_class_insert_owned_sub_class(enkf_conf_class, block_observation_class);
}
/** Try to create an instance of the enkf_conf_class. */
conf_instance_type * enkf_conf = conf_instance_alloc_from_file(enkf_conf_class, "enkf_conf", "testcase/test.txt");
conf_instance_type * enkf_conf2 = conf_instance_alloc_from_file(enkf_conf_class, "enkf_conf2", "testcase/test2.txt");
/** Validate enkf_conf_class. */
conf_instance_validate(enkf_conf);
conf_instance_validate(enkf_conf2);
/** Overload. */
conf_instance_overload(enkf_conf, enkf_conf2);
/** Print the name of the HISTORY_OBSERVATION instances. */
{
stringlist_type * history_observations = conf_instance_alloc_list_of_sub_instances_of_class_by_name(enkf_conf, "HISTORY_OBSERVATION");
int num_history_observations = stringlist_get_size(history_observations);
for(int obs_nr = 0; obs_nr < num_history_observations ; obs_nr++)
{
printf("%2i. %s\n", obs_nr, stringlist_iget(history_observations, obs_nr));
const conf_instance_type * sched_obs = conf_instance_get_sub_instance_ref(enkf_conf, stringlist_iget(history_observations, obs_nr));
double error = conf_instance_get_item_value_double(sched_obs, "ERROR");
printf(" std.dev : %f\n", error);
}
stringlist_free(history_observations);
}
/** Clean up. */
conf_instance_free(enkf_conf);
conf_instance_free(enkf_conf2);
conf_class_free(enkf_conf_class);
}

View File

@ -1,59 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'config_test.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <stringlist.h>
#include <hash.h>
#include <config.h>
int main(void) {
const char * config_file = "config_test_input";
config_parser_type * config = config_alloc();
config_schema_item_type * item;
item = config_add_schema_item(config , "KEY1" , true , true);
item = config_add_schema_item(config , "KEY2" , true , false);
config_schema_item_set_argc_minmax(item , 1 , 4 , 4 , (const config_item_types [4]) {CONFIG_EXECUTABLE , CONFIG_EXISTING_FILE , CONFIG_BOOLEAN , CONFIG_BOOLEAN});
item = config_add_schema_item(config , "FATHER" , false , false);
{
stringlist_type * children = stringlist_alloc_argv_ref( (const char *[2]) {"CHILD1" , "CHILD2"} , 2);
config_schema_item_set_required_children(item , children);
stringlist_free(children);
}
item = config_add_schema_item(config , "CHILD1" , false , false);
config_schema_item_set_argc_minmax(item , 1 , 1 , 1 , (const config_item_types [1]) {CONFIG_INT});
config_parse(config , config_file , "--" , "INCLUDE" , NULL , true, true);
{
stringlist_type * sl = config_alloc_complete_stringlist(config , "KEY1");
char * s = stringlist_alloc_joined_string(sl , "|");
printf("KEY1 -> \"%s\" \n",s);
printf("CONFIG_IGET:%s\n" , config_iget(config , "KEY2" , 0 , 0));
free(s);
stringlist_free(sl);
}
config_free(config);
}

View File

@ -1,354 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONF_H
#define ERT_CONF_H
/* libconfig: lightweight configuration parser
*
*
*
* Introduction
*
* This library provides a lightweight configuration parser for the
* enkf application. The goal of the library is to provide the
* developer with a tool for rapid specification of configuration
* files, automatic checking of user provided configuration files
* and typed access to configuration items.
*
*
*
* A Simple Example
*
* Let us consider a simple example of user provided configuration
* file that can be used with the parser:
*
*
* res_sim FrontSim2007
* {
* executable = /bin/frontsim2007;
* version = 2007;
*
* run_host bgo179lin
* {
* hostname = bgo179lin.nho.hydro.com;
* num_jobs = 4;
* };
* };
*
*
* Note that the newlines are not neccessary. In the example above,
* the user has provided an instance of the class "res_sim" with name
* FrontSim2007. Further, the user has set the items executable and version.
* He has also provided a instance of the sub class "run_host" with name
* bgo179lin and allocated 4 jobs to this machine.
*
*
*
* Structure
*
* The system is built around four basic objects:
*
* - Class definitions.
* - Item specifications.
* - Instances of classes.
* - Instances of item specifications, i.e. items.
*
* The relationship between the objects is as follows :
*
* - Class:
* . Can have contain both classes and item specifications.
* . Can not contain items or class instances.
*
* - Item specifications:
* . Can not contain any of the other objects.
*
* - Instances of classes:
* . Can contain class instances and items.
*
* - Items:
* . Can not contain any of the other objects.
*
*
*
* General Use
*
* The parser is designed to be used in the following way:
*
* - The developer creates the classes and item specifications needed.
* - Using the library and the classes, user provided configuration
* files are read and validated.
* - If the validation fails, the developer can choose to exit.
* - Using the library, the devloper has typed access to all
* information provided by the user.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <ert/util/set.h>
#include <ert/util/stringlist.h>
#include <ert/config/conf_data.h>
typedef struct conf_class_struct conf_class_type;
typedef struct conf_instance_struct conf_instance_type;
typedef struct conf_item_spec_struct conf_item_spec_type;
typedef struct conf_item_struct conf_item_type;
typedef struct conf_item_mutex_struct conf_item_mutex_type;
/** D E F A U L T A L L O C / F R E E F U N C T I O N S */
conf_class_type * conf_class_alloc_empty(
const char * class_name,
bool require_instance,
bool singleton,
const char * help);
void conf_class_free(
conf_class_type * conf_class);
void conf_class_free__(
void * conf_class);
conf_instance_type * conf_instance_alloc_default(
const conf_class_type * conf_class,
const char * name);
conf_instance_type * conf_instance_copyc(
const conf_instance_type * conf_instance);
void conf_instance_free(
conf_instance_type * conf_instance);
void conf_instance_free__(
void * conf_instance);
conf_item_spec_type * conf_item_spec_alloc(
char * name,
bool required_set,
dt_enum dt,
const char * help);
void conf_item_spec_free(
conf_item_spec_type * conf_item_spec);
void conf_item_spec_free__(
void * conf_item_spec);
conf_item_type * conf_item_alloc(
const conf_item_spec_type * conf_item_spec,
const char * value);
conf_item_type * conf_item_copyc(
const conf_item_type * conf_item);
void conf_item_free(
conf_item_type * conf_item);
void conf_item_free__(
void * conf_item);
void conf_item_mutex_free(
conf_item_mutex_type * conf_item_mutex);
void conf_item_mutex_free__(
void * conf_item_mutex);
/** M A N I P U L A T O R S , I N S E R T I O N */
void conf_class_insert_owned_sub_class(
conf_class_type * conf_class,
conf_class_type * sub_conf_class);
void conf_class_insert_owned_item_spec(
conf_class_type * conf_class,
conf_item_spec_type * item_spec);
void conf_instance_insert_owned_sub_instance(
conf_instance_type * conf_instance,
conf_instance_type * sub_conf_instance);
void conf_instance_insert_owned_item(
conf_instance_type * conf_instance,
conf_item_type * conf_item);
void conf_instance_insert_item(
conf_instance_type * conf_instance,
const char * item_name,
const char * value);
void conf_instance_overload(
conf_instance_type * conf_instance_target,
const conf_instance_type * conf_instance_source);
conf_item_mutex_type * conf_class_new_item_mutex(
conf_class_type * conf_class,
bool require_one,
bool inverse);
void conf_item_mutex_add_item_spec(
conf_item_mutex_type * conf_item_mutex,
const conf_item_spec_type * conf_item_spec);
/** M A N I P U L A T O R S , C L A S S A N D I T E M S P E C I F I C A T I O N */
void conf_class_set_help(
conf_class_type * conf_class,
const char * help);
void conf_item_spec_add_restriction(
conf_item_spec_type * conf_item_spec,
const char * restriction);
void conf_item_spec_set_default_value(
conf_item_spec_type * conf_item_spec,
const char * default_value);
void conf_item_spec_set_help(
conf_item_spec_type * conf_item_spec,
const char * help);
/** A C C E S S O R S */
bool conf_class_has_item_spec(
const conf_class_type * conf_class,
const char * item_name);
bool conf_class_has_sub_class(
const conf_class_type * conf_class,
const char * sub_class_name);
const conf_item_spec_type * conf_class_get_item_spec_ref(
const conf_class_type * conf_class,
const char * item_name);
const conf_class_type * conf_class_get_sub_class_ref(
const conf_class_type * conf_class,
const char * sub_class_name);
const char * conf_instance_get_name_ref(
const conf_instance_type * conf_instance);
bool conf_instance_is_of_class(
const conf_instance_type * conf_instance,
const char * class_name);
bool conf_instance_has_item(
const conf_instance_type * conf_instance,
const char * item_name);
bool conf_instance_has_sub_instance(
const conf_instance_type * conf_instance,
const char * sub_instance_name);
const conf_instance_type * conf_instance_get_sub_instance_ref(
const conf_instance_type * conf_instance,
const char * sub_instance_name);
stringlist_type * conf_instance_alloc_list_of_sub_instances_of_class(
const conf_instance_type * conf_instance,
const conf_class_type * conf_class);
stringlist_type * conf_instance_alloc_list_of_sub_instances_of_class_by_name(
const conf_instance_type * conf_instance,
const char * sub_class_name);
const conf_class_type * conf_instance_get_class_ref(
const conf_instance_type * conf_instance);
const char * conf_instance_get_class_name_ref(
const conf_instance_type * conf_instance);
const char * conf_instance_get_item_value_ref(
const conf_instance_type * conf_instance,
const char * item_name);
/** If the dt supports it, these functions will parse the item
value to the requested types.
NOTE:
If the dt does not support it, or the conf_instance
does not have the item, the functions will abort your program.
*/
int conf_instance_get_item_value_int(
const conf_instance_type * conf_instance,
const char * item_name);
double conf_instance_get_item_value_double(
const conf_instance_type * conf_instance,
const char * item_name);
time_t conf_instance_get_item_value_time_t(
const conf_instance_type * conf_instance,
const char * item_name);
/** V A L I D A T O R S */
bool conf_instance_validate(
const conf_instance_type * conf_instance);
/** A L L O C F R O M F I L E */
conf_instance_type * conf_instance_alloc_from_file(
const conf_class_type * conf_class,
const char * name,
const char * file_name);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,61 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf_data.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONF_DATA_H
#define ERT_CONF_DATA_H
#include <stdbool.h>
#include <time.h>
typedef enum {
DT_STR,
DT_INT,
DT_POSINT,
DT_FLOAT,
DT_POSFLOAT,
DT_FILE,
DT_EXEC,
DT_FOLDER,
DT_DATE
} dt_enum;
dt_enum conf_data_get_dt_from_string(
const char * str);
bool conf_data_string_is_dt(
const char * str);
const char * conf_data_get_dt_name_ref(
dt_enum dt);
bool conf_data_validate_string_as_dt_value(
dt_enum dt,
const char * str);
int conf_data_get_int_from_string(
dt_enum dt,
const char * str);
double conf_data_get_double_from_string(
dt_enum dt,
const char * str);
time_t conf_data_get_time_t_from_string(
dt_enum dt,
const char * str);
#endif

View File

@ -1,26 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf_util.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONF_UTIL_H
#define ERT_CONF_UTIL_H
char * conf_util_fscanf_alloc_token_buffer( const char * file_name );
char * conf_util_alloc_next_token( char ** buffer_position );
#endif

View File

@ -1,84 +0,0 @@
/*
Copyright (C) 2015 Statoil ASA, Norway.
The file 'config_content.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_CONTENT_H
#define ERT_CONFIG_CONTENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/util/type_macros.h>
#include <ert/util/stringlist.h>
#include <ert/util/subst_list.h>
#include <ert/config/config_content_item.h>
#include <ert/config/config_schema_item.h>
#include <ert/config/config_error.h>
#include <ert/config/config_root_path.h>
typedef struct config_content_struct config_content_type;
config_content_type * config_content_alloc(const char * filename);
void config_content_free( config_content_type * content );
void config_content_set_valid( config_content_type * content);
bool config_content_is_valid( const config_content_type * content );
bool config_content_has_item( const config_content_type * content , const char * key);
void config_content_add_item( config_content_type * content , const config_schema_item_type * schema_item , const config_path_elm_type * path_elm);
config_content_item_type * config_content_get_item( const config_content_type * content , const char * key);
void config_content_add_node( config_content_type * content , config_content_node_type * content_node );
config_error_type * config_content_get_errors( const config_content_type * content);
const char * config_content_iget( const config_content_type * content , const char * key , int occurence , int index);
int config_content_iget_as_int( const config_content_type * content , const char * key , int occurence , int index);
bool config_content_iget_as_bool( const config_content_type * content , const char * key , int occurence , int index);
double config_content_iget_as_double( const config_content_type * content , const char * key , int occurence , int index);
const char * config_content_iget_as_path( const config_content_type * content , const char * key , int occurence , int index);
const char * config_content_safe_iget(const config_content_type * content , const char *kw, int occurence , int index);
int config_content_get_occurences(const config_content_type * content, const char * kw);
bool config_content_get_value_as_bool(const config_content_type * config , const char * kw);
int config_content_get_value_as_int(const config_content_type * config , const char * kw);
double config_content_get_value_as_double(const config_content_type * config , const char * kw);
const char * config_content_get_value_as_path( const config_content_type * config , const char * kw);
const char * config_content_get_value_as_abspath( const config_content_type * config , const char * kw);
const char * config_content_get_value_as_relpath( const config_content_type * config , const char * kw);
const char * config_content_get_value(const config_content_type * config , const char * kw);
char * config_content_alloc_joined_string(const config_content_type * content , const char * kw, const char * sep);
stringlist_type * config_content_alloc_complete_stringlist(const config_content_type * content , const char * kw);
const stringlist_type * config_content_iget_stringlist_ref(const config_content_type * content , const char * kw, int occurence);
config_content_node_type * config_content_get_value_node( const config_content_type * content , const char * kw);
void config_content_add_define( config_content_type * content , const char * key , const char * value );
subst_list_type * config_content_get_define_list( config_content_type * content );
const char * config_content_get_config_file( const config_content_type * content , bool abs_path );
int config_content_get_size(const config_content_type * content);
const config_content_node_type * config_content_iget_node( const config_content_type * content , int index);
bool config_content_add_file( config_content_type * content , const char * config_file);
config_root_path_type * config_content_get_invoke_path( config_content_type * content );
config_path_elm_type * config_content_add_path_elm( config_content_type * content , const char * path );
void config_content_pop_path_stack( config_content_type * content );
const stringlist_type * config_content_get_warnings( const config_content_type * content);
UTIL_IS_INSTANCE_HEADER( config_content );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,69 +0,0 @@
/*
Copyright (C) 2012 Statoil ASA, Norway.
The file 'config_content_item.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_CONTENT_ITEM_H
#define ERT_CONFIG_CONTENT_ITEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/util/hash.h>
#include <ert/util/stringlist.h>
#include <ert/util/type_macros.h>
#include <ert/config/config_error.h>
#include <ert/config/config_schema_item.h>
#include <ert/config/config_path_elm.h>
#include <ert/config/config_content_node.h>
typedef struct config_content_item_struct config_content_item_type;
int config_content_item_get_size(const config_content_item_type * item);
config_content_node_type * config_content_item_get_last_node(const config_content_item_type * item);
config_content_node_type * config_content_item_iget_node(const config_content_item_type * item , int index);
const config_content_node_type * config_content_item_get_last_node_const(const config_content_item_type * item);
const config_content_node_type * config_content_item_iget_node_const(const config_content_item_type * item , int index);
char * config_content_item_ialloc_joined_string(const config_content_item_type * item , const char * sep , int occurence);
char * config_content_item_alloc_joined_string(const config_content_item_type * item , const char * sep);
const stringlist_type * config_content_item_iget_stringlist_ref(const config_content_item_type * item, int occurence);
const stringlist_type * config_content_item_get_stringlist_ref(const config_content_item_type * item);
stringlist_type * config_content_item_alloc_complete_stringlist(const config_content_item_type * item, bool copy);
stringlist_type * config_content_item_alloc_stringlist(const config_content_item_type * item, bool copy);
hash_type * config_content_item_alloc_hash(const config_content_item_type * item , bool copy);
const char * config_content_item_iget(const config_content_item_type * item , int occurence , int index);
bool config_content_item_iget_as_bool(const config_content_item_type * item, int occurence , int index);
int config_content_item_iget_as_int(const config_content_item_type * item, int occurence , int index);
double config_content_item_iget_as_double(const config_content_item_type * item, int occurence , int index);
void config_content_item_clear( config_content_item_type * item );
void config_content_item_free( config_content_item_type * item );
void config_content_item_free__( void * arg );
config_content_item_type * config_content_item_alloc( const config_schema_item_type * schema , const config_path_elm_type * path_elm);
void config_content_item_validate(const config_content_item_type * item, config_error_type * error);
config_content_node_type * config_content_item_alloc_node( const config_content_item_type * item , const config_path_elm_type * path_elm);
const config_schema_item_type * config_content_item_get_schema( const config_content_item_type * item );
const config_path_elm_type * config_content_item_get_path_elm( const config_content_item_type * item );
UTIL_IS_INSTANCE_HEADER( config_content_item );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,63 +0,0 @@
/*
Copyright (C) 2012 Statoil ASA, Norway.
The file 'config_content_node.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_CONTENT_NODE_H
#define ERT_CONFIG_CONTENT_NODE_H
#ifdef __cplusplus
define extern "C" {
#endif
#include <ert/util/hash.h>
#include <ert/config/config_schema_item.h>
#include <ert/config/config_path_elm.h>
typedef struct config_content_node_struct config_content_node_type;
config_item_types config_content_node_iget_type( const config_content_node_type * node , int index);
config_content_node_type * config_content_node_alloc( const config_schema_item_type * schema , const config_path_elm_type * cwd);
void config_content_node_add_value(config_content_node_type * node , const char * value);
void config_content_node_set(config_content_node_type * node , const stringlist_type * token_list);
char * config_content_node_alloc_joined_string(const config_content_node_type * node, const char * sep);
void config_content_node_free(config_content_node_type * node);
void config_content_node_free__(void * arg);
const char * config_content_node_get_full_string( config_content_node_type * node , const char * sep );
const char * config_content_node_iget(const config_content_node_type * node , int index);
bool config_content_node_iget_as_bool(const config_content_node_type * node , int index);
int config_content_node_iget_as_int(const config_content_node_type * node , int index);
double config_content_node_iget_as_double(const config_content_node_type * node , int index);
const char * config_content_node_iget_as_path(config_content_node_type * node , int index);
const char * config_content_node_iget_as_abspath( config_content_node_type * node , int index);
const char * config_content_node_iget_as_relpath( config_content_node_type * node , int index);
time_t config_content_node_iget_as_isodate(const config_content_node_type * node , int index);
const stringlist_type * config_content_node_get_stringlist( const config_content_node_type * node );
const char * config_content_node_safe_iget(const config_content_node_type * node , int index);
int config_content_node_get_size( const config_content_node_type * node );
const char * config_content_node_get_kw( const config_content_node_type * node );
void config_content_node_assert_key_value( const config_content_node_type * node );
const config_path_elm_type * config_content_node_get_path_elm( const config_content_node_type * node );
void config_content_node_init_opt_hash( const config_content_node_type * node , hash_type * opt_hash , int elm_offset);
void config_content_node_fprintf( const config_content_node_type * node , FILE * stream );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,45 +0,0 @@
/*
Copyright (C) 2012 Statoil ASA, Norway.
The file 'config_error.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_ERROR_H
#define ERT_CONFIG_ERROR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
typedef struct config_error_struct config_error_type;
config_error_type * config_error_alloc();
config_error_type * config_error_alloc_copy( const config_error_type * src_error);
void config_error_free(config_error_type * error);
const char * config_error_iget(const config_error_type * error , int index);
void config_error_add( config_error_type * error , char * new_error );
void config_error_clear( config_error_type * error );
int config_error_count( const config_error_type * error );
void config_error_fprintf( const config_error_type * error , bool add_count , FILE * stream );
bool config_error_equal( const config_error_type * error1 , const config_error_type * error2);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,105 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'config.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_H
#define ERT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <ert/util/stringlist.h>
#include <ert/util/subst_list.h>
#include <ert/util/hash.h>
#include <ert/config/config_schema_item.h>
#include <ert/config/config_content_item.h>
#include <ert/config/config_content_node.h>
#include <ert/config/config_content.h>
#define ECL_COM_KW "--"
#define ENKF_COM_KW "--"
typedef struct config_parser_struct config_parser_type;
void config_free(config_parser_type *);
config_parser_type * config_alloc( );
char ** config_alloc_active_list(const config_parser_type * , int * );
config_content_type * config_parse(config_parser_type * config, const char * filename, const char * comment_string, const char * include_kw, const char * define_kw, const hash_type * pre_defined_kw_map, config_schema_unrecognized_enum unrecognized_behaviour , bool validate);
bool config_has_schema_item(const config_parser_type * config , const char * kw);
/*****************************************************************/
config_schema_item_type * config_get_schema_item(const config_parser_type *, const char *);
bool config_item_set(const config_parser_type * , const char * );
void config_add_alias(config_parser_type * , const char * , const char * );
void config_install_message(config_parser_type * , const char * , const char * );
const char * config_safe_get(const config_parser_type * , const char *);
char * config_alloc_joined_string(const config_parser_type * , const char * , const char * );
void config_add_define( config_parser_type * config , const char * key , const char * value );
/*
bool config_schema_item_is_set(const config_schema_item_type * );
void config_schema_item_set_argc_minmax(config_schema_item_type * , int , int , int type_map_size , const config_item_types * );
void config_schema_item_set_common_selection_set(config_schema_item_type * , int argc , const char ** argv);
void config_schema_item_set_indexed_selection_set(config_schema_item_type * item , int , int , const char ** );
void config_schema_item_set_required_children(config_schema_item_type * , stringlist_type * );
void config_schema_item_set_required_children_on_value(config_schema_item_type * , const char * , stringlist_type * );
void config_schema_item_add_required_children(config_schema_item_type * item , const char * child_key);
*/
config_schema_item_type * config_add_schema_item(config_parser_type * config,
const char * kw,
bool required);
stringlist_type * config_alloc_complete_stringlist(const config_parser_type * , const char * );
stringlist_type * config_alloc_stringlist(const config_parser_type * config , const char * );
hash_type * config_alloc_hash(const config_parser_type * , const char * );
const stringlist_type * config_iget_stringlist_ref(const config_parser_type * , const char * , int );
int config_get_occurences(const config_parser_type * , const char * );
int config_get_occurence_size( const config_parser_type * config , const char * kw , int occurence);
bool config_has_content_item( const config_parser_type * config , const char * input_kw);
config_content_item_type * config_get_content_item( const config_parser_type * config , const char * input_kw);
config_schema_item_type * config_add_key_value( config_parser_type * config , const char * key , bool required , config_item_types item_type);
;
const char * config_get_value_as_relpath( const config_parser_type * config , const char * kw);
const char * config_get_value_as_path( const config_parser_type * config , const char * kw);
const char * config_get_value(const config_parser_type * config , const char * kw);
const subst_list_type * config_get_define_list( const config_parser_type * config);
int config_get_schema_size( const config_parser_type * config );
config_content_node_type * config_get_value_node( const config_parser_type * config , const char * kw);
void config_parser_deprecate(config_parser_type * config , const char * kw, const char * msg);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,44 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'config_path_elm.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_PATH_ELM_H
#define ERT_CONFIG_PATH_ELM_H
#ifdef __cplusplus
extern "C"
#endif
#include <ert/config/config_root_path.h>
typedef struct config_path_elm_struct config_path_elm_type;
void config_path_elm_free( config_path_elm_type * path_elm );
void config_path_elm_free__( void * arg );
config_path_elm_type * config_path_elm_alloc( const config_root_path_type * root_path , const char * path);
const char * config_path_elm_get_abspath( const config_path_elm_type * path_elm );
const char * config_path_elm_get_relpath( const config_path_elm_type * path_elm );
const config_root_path_type * config_path_elm_get_rootpath( const config_path_elm_type * path_elm );
char * config_path_elm_alloc_abspath(const config_path_elm_type * path_elm , const char * input_path);
char * config_path_elm_alloc_relpath(const config_path_elm_type * path_elm , const char * input_path);
char * config_path_elm_alloc_path(const config_path_elm_type * path_elm , const char * input_path);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,40 +0,0 @@
/*
Copyright (C) 2013 Statoil ASA, Norway.
The file 'config_root_path.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_ROOT_PATH_H
#define ERT_CONFIG_ROOT_PATH_H
#ifdef __cplusplus
extern "C"
#endif
typedef struct config_root_path_struct config_root_path_type;
void config_root_path_free( config_root_path_type * root_path );
config_root_path_type * config_root_path_alloc( const char * input_path );
void config_root_path_printf( const config_root_path_type * root_path );
const char * config_root_path_get_input_path( const config_root_path_type * root_path );
const char * config_root_path_get_rel_path( const config_root_path_type * root_path );
const char * config_root_path_get_abs_path( const config_root_path_type * root_path );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,109 +0,0 @@
/*
Copyright (C) 2012 Statoil ASA, Norway.
The file 'config_schema_item.h' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_SCHEMA_ITEM_H
#define ERT_CONFIG_SCHEMA_ITEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ert/util/stringlist.h>
#include <ert/config/config_error.h>
#include <ert/config/config_path_elm.h>
/**
Types used for validation of config items.
*/
typedef enum {
CONFIG_STRING = 1,
CONFIG_INT = 2,
CONFIG_FLOAT = 4,
CONFIG_PATH = 8,
CONFIG_EXISTING_PATH = 16,
CONFIG_BOOL = 32,
CONFIG_CONFIG = 64,
CONFIG_BYTESIZE = 128,
CONFIG_EXECUTABLE = 256,
CONFIG_ISODATE = 512,
CONFIG_INVALID = 1024
} config_item_types;
typedef enum {
CONFIG_UNRECOGNIZED_IGNORE = 0,
CONFIG_UNRECOGNIZED_WARN = 1,
CONFIG_UNRECOGNIZED_ERROR = 2
} config_schema_unrecognized_enum;
#define CONFIG_DEFAULT_ARG_MIN -1
#define CONFIG_DEFAULT_ARG_MAX -1
typedef struct config_schema_item_struct config_schema_item_type;
config_schema_item_type * config_schema_item_alloc(const char * kw , bool required);
bool config_schema_item_validate_set(const config_schema_item_type * item ,
stringlist_type * token_list ,
const char * config_file,
const config_path_elm_type * path_elm,
config_error_type * error_list);
void config_schema_item_free( config_schema_item_type * item);
void config_schema_item_free__ (void * void_item);
void config_schema_item_set_required_children_on_value(config_schema_item_type * item , const char * value , stringlist_type * child_list);
void config_schema_item_set_common_selection_set(config_schema_item_type * item , int argc , const char ** argv);
void config_schema_item_set_indexed_selection_set(config_schema_item_type * item , int index , int argc , const char ** argv);
void config_schema_item_add_indexed_alternative(config_schema_item_type * item , int index , const char * value);
void config_schema_item_set_required_children(config_schema_item_type * item , stringlist_type * stringlist);
void config_schema_item_add_required_children(config_schema_item_type * item , const char * child_key);
void config_schema_item_set_envvar_expansion( config_schema_item_type * item , bool expand_envvar );
void config_schema_item_set_argc_minmax(config_schema_item_type * item ,
int argc_min ,
int argc_max);
void config_schema_item_assure_type(const config_schema_item_type * item , int index , int type_mask);
int config_schema_item_num_required_children(const config_schema_item_type * item);
const char * config_schema_item_iget_required_child( const config_schema_item_type * item , int index);
const char * config_schema_item_get_kw( const config_schema_item_type * item );
bool config_schema_item_required( const config_schema_item_type * item );
bool config_schema_item_expand_envvar( const config_schema_item_type * item );
void config_schema_item_get_argc( const config_schema_item_type * item , int *argc_min , int *argc_max);
bool config_schema_item_has_required_children_value( const config_schema_item_type * item );
stringlist_type * config_schema_item_get_required_children_value(const config_schema_item_type * item , const char * value);
void config_schema_item_iset_type( config_schema_item_type * item , int index , config_item_types type);
config_item_types config_schema_item_iget_type(const config_schema_item_type * item , int index );
void config_schema_item_set_default_type( config_schema_item_type * item , config_item_types type);
bool config_schema_item_is_deprecated( const config_schema_item_type * item);
const char * config_schema_item_get_deprecate_msg( const config_schema_item_type * item);
void config_schema_item_set_deprecated( config_schema_item_type * item , const char * msg);
bool config_schema_item_valid_string(config_item_types value_type , const char * value);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,67 +0,0 @@
/*
Copyright (C) 2017 Statoil ASA, Norway.
The file 'config_settings.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#ifndef ERT_CONFIG_SETTINGS_H
#define ERT_CONFIG_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <ert/util/stringlist.h>
#include <ert/config/config_parser.h>
#include <ert/config/config_content.h>
#include <ert/config/config_schema_item.h>
typedef struct config_settings_struct config_settings_type;
config_settings_type * config_settings_alloc( const char * root_key );
void config_settings_free( config_settings_type * settings);
bool config_settings_has_key( const config_settings_type * settings , const char * key);
config_item_types config_settings_get_value_type( const config_settings_type * config_settings , const char * key);
bool config_settings_set_value( const config_settings_type * config_settings , const char * key, const char * value);
void config_settings_init_parser( const config_settings_type * config_settings, config_parser_type * config , bool required);
void config_settings_init_parser__( const char * root_key , config_parser_type * config , bool required);
void config_settings_apply(config_settings_type * config_settings , const config_content_type * config );
stringlist_type * config_settings_alloc_keys( const config_settings_type * config_settings );
bool config_settings_add_setting(config_settings_type * settings , const char* key, config_item_types value_type , const char* initial_value);
void config_settings_add_int_setting(config_settings_type * settings , const char* key, int initial_value);
void config_settings_add_double_setting(config_settings_type * settings , const char* key, double initial_value);
void config_settings_add_string_setting(config_settings_type * settings , const char* key, const char * initial_value);
void config_settings_add_bool_setting(config_settings_type * settings , const char* key, bool initial_value);
const char * config_settings_get_value( const config_settings_type * config_settings , const char * key);
const char * config_settings_get_string_value( const config_settings_type * config_settings , const char * key);
int config_settings_get_int_value( const config_settings_type * config_settings , const char * key);
bool config_settings_get_bool_value( const config_settings_type * config_settings , const char * key);
double config_settings_get_double_value( const config_settings_type * config_settings , const char * key);
bool config_settings_set_value( const config_settings_type * config_settings , const char * key, const char * value);
bool config_settings_set_int_value( const config_settings_type * config_settings , const char * key, int value);
bool config_settings_set_double_value( const config_settings_type * config_settings , const char * key, double value);
bool config_settings_set_bool_value( const config_settings_type * config_settings , const char * key, bool value);
bool config_settings_set_string_value( const config_settings_type * config_settings , const char * key, const char * value);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,17 +0,0 @@
set( source_files config_parser.c config_content.c config_error.c config_schema_item.c config_content_item.c config_content_node.c config_root_path.c config_path_elm.c conf.c conf_util.c conf_data.c config_settings.c)
set( header_files config_parser.h config_content.h config_error.h config_schema_item.h config_content_item.h config_content_node.h config_root_path.h config_path_elm.h conf.h conf_data.h config_settings.h)
add_library( config ${LIBRARY_TYPE} ${source_files} )
set_target_properties( config PROPERTIES VERSION ${ERT_VERSION_MAJOR}.${ERT_VERSION_MINOR} SOVERSION ${ERT_VERSION_MAJOR} )
target_link_libraries( config ert_util )
if (USE_RUNPATH)
add_runpath( config )
endif()
if (INSTALL_ERT)
install(TARGETS config DESTINATION ${CMAKE_INSTALL_LIBDIR})
foreach(header ${header_files})
install(FILES ../include/ert/config/${header} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ert/config)
endforeach()
endif()

File diff suppressed because it is too large Load Diff

View File

@ -1,259 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf_data.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ert/util/util.h>
#include <ert/config/conf_data.h>
#define DT_STR_STRING "string"
#define DT_INT_STRING "integer"
#define DT_POSINT_STRING "positive integer"
#define DT_FLOAT_STRING "floating point number"
#define DT_POSFLOAT_STRING "positive floating foint number"
#define DT_FILE_STRING "file"
#define DT_EXEC_STRING "executable"
#define DT_FOLDER_STRING "folder"
#define DT_DATE_STRING "date"
#define RETURN_TYPE_IF_MATCH(STRING,TYPE) if(strcmp(STRING, TYPE ##_STRING) == 0){ return TYPE;}
dt_enum conf_data_get_dt_from_string(
const char * str)
{
RETURN_TYPE_IF_MATCH(str, DT_STR);
RETURN_TYPE_IF_MATCH(str, DT_INT);
RETURN_TYPE_IF_MATCH(str, DT_POSINT);
RETURN_TYPE_IF_MATCH(str, DT_FLOAT);
RETURN_TYPE_IF_MATCH(str, DT_POSFLOAT);
RETURN_TYPE_IF_MATCH(str, DT_FILE);
RETURN_TYPE_IF_MATCH(str, DT_EXEC);
RETURN_TYPE_IF_MATCH(str, DT_FOLDER);
RETURN_TYPE_IF_MATCH(str, DT_DATE);
util_abort("%s: Data type \"%s\" is unkown.\n", __func__, str);
return 0;
}
#undef RETURN_TYPE_IF_MATCH
bool conf_data_string_is_dt(
const char * str)
{
if( !strcmp(str, DT_STR_STRING )) return true;
else if(!strcmp(str, DT_INT_STRING )) return true;
else if(!strcmp(str, DT_POSINT_STRING )) return true;
else if(!strcmp(str, DT_FLOAT_STRING )) return true;
else if(!strcmp(str, DT_POSFLOAT_STRING )) return true;
else if(!strcmp(str, DT_FILE_STRING )) return true;
else if(!strcmp(str, DT_EXEC_STRING )) return true;
else if(!strcmp(str, DT_FOLDER_STRING )) return true;
else if(!strcmp(str, DT_DATE_STRING )) return true;
else return false;
}
const char * conf_data_get_dt_name_ref(
dt_enum dt)
{
switch(dt)
{
case(DT_STR):
return DT_STR_STRING;
case(DT_INT):
return DT_INT_STRING;
case(DT_POSINT):
return DT_POSINT_STRING;
case(DT_FLOAT):
return DT_FLOAT_STRING;
case(DT_POSFLOAT):
return DT_POSFLOAT_STRING;
case(DT_FILE):
return DT_FILE_STRING;
case(DT_EXEC):
return DT_EXEC_STRING;
case(DT_FOLDER):
return DT_FOLDER_STRING;
case(DT_DATE):
return DT_DATE_STRING;
default:
util_abort("%s: Internal error.\n", __func__);
return "";
}
}
bool conf_data_validate_string_as_dt_value(
dt_enum dt,
const char * str)
{
if(str == NULL)
return false;
switch(dt)
{
case(DT_STR):
return true;
case(DT_INT):
return util_sscanf_int(str, NULL);
case(DT_POSINT):
{
int val;
bool ok = util_sscanf_int(str, &val);
if(!ok)
return false;
else
return val > 0;
}
case(DT_FLOAT):
return util_sscanf_double(str, NULL);
case(DT_POSFLOAT):
{
double val;
bool ok = util_sscanf_double(str, &val);
if(!ok)
return false;
else
return val >= 0.0;
}
case(DT_FILE):
{
return util_file_exists(str);
}
case(DT_EXEC):
{
bool ok;
char * exec = util_alloc_PATH_executable(str);
ok = exec != NULL;
free(exec);
return ok;
}
case(DT_FOLDER):
{
return util_is_directory(str);
}
case(DT_DATE):
{
time_t date;
return util_sscanf_date_utc(str, &date);
}
default:
util_abort("%s: Internal error.\n", __func__);
}
return true;
}
int conf_data_get_int_from_string(
dt_enum dt,
const char * str)
{
int value = 0;
bool ok = true;
switch(dt)
{
case(DT_INT):
ok = util_sscanf_int(str, &value);
break;
case(DT_POSINT):
ok = util_sscanf_int(str, &value);
break;
default:
ok = false;
}
if(!ok)
util_abort("%s: Can not get an int from \"%s\".\n",
__func__, str);
return value;
}
double conf_data_get_double_from_string(
dt_enum dt,
const char * str)
{
double value = 0;
bool ok = true;
switch(dt)
{
case(DT_INT):
ok = util_sscanf_double(str, &value);
break;
case(DT_POSINT):
ok = util_sscanf_double(str, &value);
break;
case(DT_FLOAT):
ok = util_sscanf_double(str, &value);
break;
case(DT_POSFLOAT):
ok = util_sscanf_double(str, &value);
break;
default:
ok = false;
}
if(!ok)
util_abort("%s: Can not get a double from \"%s\".\n",
__func__, str);
return value;
}
time_t conf_data_get_time_t_from_string(
dt_enum dt,
const char * str)
{
time_t value = 0;
bool ok = true;
switch(dt)
{
case(DT_DATE):
ok = util_sscanf_date_utc(str, &value);
break;
default:
ok = false;
}
if(!ok)
util_abort("%s: Can not get a time_t from \"%s\".\n",
__func__, str);
return value;
}

View File

@ -1,161 +0,0 @@
/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'conf_util.c' is part of ERT - Ensemble based Reservoir Tool.
ERT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <assert.h>
#include <string.h>
#include <ert/util/util.h>
#include <ert/util/parser.h>
#include <ert/config/conf_util.h>
/*
This function creates a string buffer from a file. Furthermore, if the strings in pad_keys are found in the buffer,
they are padded with a space before and after.
I.e., if the file contains
key=value
and "=" is in pad_keys, then the buffer will read
key = value
*/
static
char * __conf_util_fscanf_alloc_token_buffer(
const char * file,
const char * comment,
int num_pad_keys,
const char ** pad_keys)
{
char * buffer_wrk = basic_parser_fread_alloc_file_content( file , NULL /* quote_set */ , NULL /* delete_set */ , "--" /* Comment start*/ , "\n" /* Comment end */);
char ** padded_keys = util_calloc(num_pad_keys , sizeof * padded_keys);
for(int key_nr = 0; key_nr < num_pad_keys; key_nr++)
{
assert(pad_keys[key_nr] != NULL);
int key_len = strlen(pad_keys[key_nr]);
padded_keys[key_nr] = util_calloc((key_len + 3) , sizeof * padded_keys[key_nr]);
padded_keys[key_nr][0] = ' ';
for(int i=0; i<key_len; i++)
{
padded_keys[key_nr][1+i] = pad_keys[key_nr][i];
}
padded_keys[key_nr][key_len + 1] = ' ';
padded_keys[key_nr][key_len + 2] = '\0';
}
char * buffer = util_string_replacen_alloc(buffer_wrk, num_pad_keys,
pad_keys, (const char **) padded_keys);
free(buffer_wrk);
util_free_stringlist(padded_keys, num_pad_keys);
return buffer;
}
char * conf_util_fscanf_alloc_token_buffer(
const char * file_name)
{
char * pad_keys[] = {"{","}","=",";"};
char * buffer = __conf_util_fscanf_alloc_token_buffer(file_name, "--", 4, (const char **) pad_keys);
return buffer;
}
/*
This function takes a pointer to a position in a string and returns a copy
of the next token in the string. Furthermore, the position in the string is
moved to the position after the token. Strings inside quotations " and ' are
treated as one token, and the quotations removed.
Note: Quoted strings with no content, e.g. " " are NOT considered as tokens!
*/
char * conf_util_alloc_next_token(
char ** buff_pos)
{
char * sep = " \t\r\n";
int len_token = 0;
bool found = false;
bool quoted = false;
while(!found)
{
int init_whitespace = strspn(*buff_pos, sep);
*buff_pos += init_whitespace;
if(*buff_pos[0] == '"')
{
quoted = true;
*buff_pos += 1;
len_token = strcspn(*buff_pos, "\"");
if(len_token == strspn(*buff_pos, sep))
{
*buff_pos += len_token;
len_token=0;
}
}
else if(*buff_pos[0] == '\'')
{
quoted = true;
*buff_pos += 1;
len_token = strcspn(*buff_pos, "\'");
if(len_token == strspn(*buff_pos, sep))
{
*buff_pos += len_token;
len_token=0;
}
}
else if(*buff_pos[0] == '[')
{
quoted = true;
*buff_pos += 1;
len_token = strcspn(*buff_pos, "]");
if(len_token == strspn(*buff_pos, sep))
{
*buff_pos += len_token;
len_token=0;
}
}
else
{
quoted = false;
len_token = strcspn(*buff_pos, sep);
}
if(len_token > 0)
found = true;
else if(len_token == 0 && !quoted)
return NULL;
else if(len_token == 0 && quoted)
*buff_pos += 1;
}
char * token = util_calloc( (len_token + 1) , sizeof * token);
memmove(token, *buff_pos, len_token);
token[len_token] = '\0';
*buff_pos += len_token;
if(quoted)
*buff_pos += 1;
return token;
}

Some files were not shown because too many files have changed in this diff Show More