Files
ResInsight/ThirdParty/Ert/applications/ecl/sum_write.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 );
}