mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
311 lines
12 KiB
C
311 lines
12 KiB
C
/*
|
|
Copyright (C) 2012 Statoil ASA, Norway.
|
|
The file 'sum_write' 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/util.h>
|
|
#include <ert/util/vector.h>
|
|
|
|
#include <ert/ecl/ecl_kw.h>
|
|
#include <ert/ecl/ecl_sum.h>
|
|
#include <ert/ecl/smspec_node.h>
|
|
|
|
|
|
/*
|
|
The ECLIPSE summary data is stored in two different files:
|
|
|
|
- A header file which contains metadata of the stored data; this
|
|
header file has extension SMSPEC.
|
|
|
|
- The actual data is stored as blocks of data where each block
|
|
contains all the variables for one timestep (called MINISTEP in
|
|
ECLIPSE lingo). The data can be stored in a unified summary file
|
|
with all the data in one file, or alternatively several separate
|
|
files - one for each report step.
|
|
|
|
In the case of a unified file the extension is UNSMRY whereas the
|
|
multiple summary files haver extension Snnnn.
|
|
|
|
The format is quite primitive, and very much influenced by Fortran77
|
|
arrays which are fixed-size-large-enough thank you. The header file
|
|
is (mainly) based on three different ecl_kw vectors which together
|
|
completely specify the variables. The example below consists of the
|
|
following:
|
|
|
|
- Variables: Field Oil Production Total (FOPT), Group Oil
|
|
Production Rate (GOPR) in group P-North, the Block Pressure
|
|
(BPR) in cell 5423 and the Well Gas Production Rate (WGPR) in
|
|
the well GasW.
|
|
|
|
- A total of two report steps (dates), where the first consist of
|
|
two timesteps and the latter of three timesteps.
|
|
|
|
|
|
|
|
CASE.SMSPEC CASE.S0001 CASE.S0002
|
|
------------------------------ -------------------------- ---------------------------------------
|
|
| KEYWORD | WGNAMES | NUMS | | MINISTEP 1| MINISTEP 2| | MINISTEP 3| MINISTEP 4| MINISTEP 5|
|
|
+----------------------------+ +------------------------+ +-------------------------------------+
|
|
| TIME | | | --> | | | --> | | | |
|
|
| FOPT | | | --> | | | --> | | | |
|
|
| GOPR | P-North | | --> | | | --> | | | |
|
|
| BPR | | 5423 | --> | | | --> | | | |
|
|
| WGPR | GasW | | --> | | | --> | | | |
|
|
+----------------------------+ +------------------------+ +-------------------------------------+
|
|
|
|
|<--- -- CASE.UNSMRY -- --->|
|
|
|
|
Observe the following points:
|
|
|
|
1. The variable name supplied in the KEYWORD array is significant;
|
|
ECLIPSE will determine the type of variable by looking at the
|
|
first letter of the keyword: "W" for well variables, "F" for
|
|
field variables and so on. This is further documented in the
|
|
ecl_smspec_identify_var_type() function.
|
|
|
|
2. The KEYWORD vector in the SMSPEC file is relevant for all the
|
|
entries, whereas the WGNAMES and NUMS entries should be
|
|
considered as further qualifiers which apply selectively
|
|
depending on the variable type - for instance both the WGNAMES
|
|
and NUMS vectors are ignored in the case of field variable like
|
|
FOPT.
|
|
|
|
3. The actual data is organised in blocks of data, one continous
|
|
block for each (simulator) timestep. These blocks are collected
|
|
in report steps; when stored the data can be either lumped
|
|
together in a unified file, or split in many different files.
|
|
|
|
4. Each block of data is exactly as large as the header. This
|
|
implies that:
|
|
|
|
- The number of elements in the summary file must be known up
|
|
front; it is not possible to add/remove variables during
|
|
simulation.
|
|
- All timesteps are equally large.
|
|
|
|
Due to this fixed size nature an important element in the
|
|
ecl_sum implementation is "the index of a variable" - i.e. the
|
|
"FOPT" variable in the example above will be found at index 1 of
|
|
every datablock.
|
|
|
|
5. The header contains a "TIME" variable; to some extent this looks
|
|
like just any other variable, but it must be present in the
|
|
SMSPEC header. In the example above the first element in every
|
|
data block is the current time (in days) for that datablock; if
|
|
labunits is used the stored value is the elapsed time in hours.
|
|
|
|
6. In the ecl_sum library the concept of a 'gen_key' is used quite
|
|
extensively. The gen_key is a string combination of the KEYWORD,
|
|
WGNAMES and NUMS values from the smspec header file. Only the
|
|
relevant elements are combined when forming a gen_key; i.e. for
|
|
the example above we will have:
|
|
|
|
------------------------------
|
|
| KEYWORD | WGNAMES | NUMS | General key
|
|
+----------------------------+ ------------
|
|
| TIME | | | --> TIME
|
|
| FOPT | | | --> FOPT
|
|
| GOPR | P-North | | --> GOPR:P-North
|
|
| BPR | | 5423 | --> BPR:5423 , BPR:i,j,k
|
|
| WGPR | GasW | | --> WGPR:GasW
|
|
+----------------------------+
|
|
|
|
Note the following:
|
|
|
|
o The keys are joined with a string typically called
|
|
'key_join_string' in the code; in the example above this is a
|
|
":" which is quite close to a standard. The gen_key values are
|
|
never inverted, so the join string can be arbitrary.
|
|
|
|
o For the block quantities, like the BPR in the example above
|
|
the NUMS value is the cell number in (i,j,k) ordering:
|
|
|
|
NUMS = i + (j - 1)*nx + (k-1)*nx*ny
|
|
|
|
The block related properties are also available as the general
|
|
key BPR:i,j,k where the coordinates (i,j,k) are offset 1.
|
|
|
|
Due to the fixed size nature of the summary file format described in
|
|
point 4 above, the library is somewhat cumbersome and unflexible to
|
|
use. Very briefly the usage pattern will be like:
|
|
|
|
1. Create a ecl_sum instance and add variables to it with the
|
|
ecl_sum_add_var() function.
|
|
|
|
2. Use your simulator to step forward in time, and add timesteps
|
|
with ecl_sum_add_tstep().
|
|
|
|
Now - the important thing is that steps 1 and 2 two can not be
|
|
interchanged, that will lead to crash and burn.
|
|
*/
|
|
|
|
|
|
|
|
int main( int argc , char ** argv) {
|
|
time_t start_time = util_make_date_utc( 1,1,2010 );
|
|
int nx = 10;
|
|
int ny = 10;
|
|
int nz = 10;
|
|
|
|
|
|
/*
|
|
We create a new summary case which will be used for writing. The
|
|
arguments are:
|
|
|
|
1: The case - this an ECLIPSE basename, with an optional leading
|
|
path component. Can later be modified with ecl_sum_set_case().
|
|
|
|
2: Should formatted files be used? Can be modified with
|
|
ecl_sum_set_fmt_output().
|
|
|
|
3: Character(s) to separate the items from the smspec header
|
|
generate a gen_key value. The value ":" is close to a
|
|
standard.
|
|
|
|
4: Should the data be output as a unified file, or as a
|
|
collection of files - one for each report step. Can be
|
|
modified with ecl_sum_set_unified_output().
|
|
|
|
5: The real-world start time of this simulation, as a unix
|
|
time_t value.
|
|
|
|
6-8: Grid dimensions.
|
|
*/
|
|
bool time_in_days = true;
|
|
ecl_sum_type * ecl_sum = ecl_sum_alloc_writer( "/tmp/CASE" , false , true , ":" , start_time , time_in_days , nx , ny , nz );
|
|
|
|
|
|
/*
|
|
We add the variables we wish to measure. Due to the rather
|
|
inflexible nature of the format we must add all the variables we
|
|
are interested in before we start adding data.
|
|
|
|
The arguments to this function are:
|
|
|
|
1. self / this
|
|
|
|
2. The KEYWORD value for the variable we are considering; the
|
|
function ecl_smspec_identify_var_type() will be called with
|
|
this string - i.e. you must follow the ECLIPSE rules (see
|
|
table 3.4 in the ECLIPSE file format reference manual).
|
|
|
|
3. The WGNAME value for this variable. WGNAME is the well or
|
|
group name; if the variable in question is neither a well nor
|
|
a group variable you can just send in NULL.
|
|
|
|
4. The NUMS value for this variable.
|
|
|
|
5. The unit for this variable.
|
|
|
|
6. A defualt value for this variable.
|
|
|
|
*/
|
|
ecl_sum_add_var( ecl_sum , "FOPT" , NULL , 0 , "Barrels" , 99.0 );
|
|
ecl_sum_add_var( ecl_sum , "BPR" , NULL , 567 , "BARS" , 0.0 );
|
|
ecl_sum_add_var( ecl_sum , "WWCT" , "OP-1" , 0 , "(1)" , 0.0 );
|
|
ecl_sum_add_var( ecl_sum , "WOPR" , "OP-1" , 0 , "Barrels" , 0.0 );
|
|
|
|
|
|
/*
|
|
The return value from the ecl_sum_add_var() function is an
|
|
smspec_node_type instance (implemented in file smspec_node.c);
|
|
which is essentially a struct holding header information about
|
|
this varible. There are several options on how to handle the
|
|
return value from the ecl_sum_add_var() function; which affect how
|
|
you can add data at a later stage:
|
|
|
|
1. You can just ignore it - that is not very clean; in this
|
|
case you must make an assumption of gen_key format at a
|
|
later stage.
|
|
|
|
2. You can use the smspec_node_get_gen_key1() or
|
|
smspec_node_get_params_index() and hold on to the gen_key or
|
|
params_index values. You will need these later.
|
|
|
|
3. You can hold on to the complete smspec_node instance, and
|
|
then later on call one of the smspec_node_get_params_index()
|
|
or smspec_node_get_gen_key1() functions.
|
|
|
|
*/
|
|
|
|
smspec_node_type * wwct_wellx = ecl_sum_add_var( ecl_sum , "WWCT" , NULL , 0 , "(1)" , 0.0);
|
|
smspec_node_type * wopr_wellx = ecl_sum_add_var( ecl_sum , "WOPR" , NULL , 0 , "Barrels" , 0.0);
|
|
|
|
|
|
{
|
|
int num_dates = 10;
|
|
int num_step = 10;
|
|
double sim_days = 0;
|
|
int report_step;
|
|
int step;
|
|
for (report_step = 0; report_step < num_dates; report_step++) {
|
|
for (step = 0; step < num_step; step++) {
|
|
/* Simulate .... */
|
|
|
|
sim_days += 10;
|
|
{
|
|
/*
|
|
Here we add a new timestep. The report steps are not
|
|
added explicitly; the ecl_sum layer will just see if this
|
|
is a new report step. Observe that report_step == 1 is
|
|
the first permissible report step.
|
|
|
|
The new time step is essentially a block of data with one
|
|
element for each variable, and now we must set the
|
|
various elements in the block. There are different ways
|
|
to do this - depending on which metadata information we
|
|
are holding on to from the ecl_sum_add_var() calls.
|
|
|
|
Observe that one element for the number of simulation
|
|
days has already been inserted in the timestep. The
|
|
elements which are not set explicitly will have the
|
|
default value given in the ecl_sum_add_var() call.
|
|
*/
|
|
ecl_sum_tstep_type * tstep = ecl_sum_add_tstep( ecl_sum , report_step + 1 , sim_days );
|
|
|
|
|
|
/*
|
|
We can just set a value by it's index using the
|
|
ecl_sum_tstep_iset() function. The index value should come
|
|
from the smspec_get_params_index() function.
|
|
*/
|
|
ecl_sum_tstep_iset( tstep , 3 , 0.98);
|
|
|
|
/*
|
|
We can use the gen_key value to set the numerical
|
|
values. The gen_key value should could from the
|
|
smpec_get_gen_key1() function:
|
|
*/
|
|
ecl_sum_tstep_set_from_key( tstep , "WWCT:OP-1" , sim_days / 10);
|
|
if (report_step >= 5) {
|
|
/*
|
|
We can use the smspec_node value from the
|
|
ecl_sum_add_var() function directly:
|
|
*/
|
|
ecl_sum_tstep_set_from_node( tstep , wwct_wellx , sim_days );
|
|
ecl_sum_tstep_set_from_node( tstep, wopr_wellx, sim_days * 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ecl_sum_fwrite( ecl_sum );
|
|
ecl_sum_free( ecl_sum );
|
|
}
|