mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
1223 lines
42 KiB
C++
1223 lines
42 KiB
C++
/*
|
|
Copyright (C) 2012 Statoil ASA, Norway.
|
|
|
|
The file 'smspec_node.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 <string.h>
|
|
#include <stdbool.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
|
|
#include <ert/util/hash.hpp>
|
|
#include <ert/util/util.h>
|
|
#include <ert/util/vector.hpp>
|
|
#include <ert/util/int_vector.hpp>
|
|
#include <ert/util/stringlist.hpp>
|
|
#include <ert/util/type_macros.hpp>
|
|
|
|
#include <ert/ecl/ecl_kw.hpp>
|
|
#include <ert/ecl/ecl_util.hpp>
|
|
#include <ert/ecl/ecl_smspec.hpp>
|
|
#include <ert/ecl/smspec_node.hpp>
|
|
#include <ert/ecl/ecl_file.hpp>
|
|
#include <ert/ecl/ecl_kw_magic.hpp>
|
|
|
|
|
|
|
|
|
|
/**
|
|
This struct contains meta-information about one element in the smspec
|
|
file; the content is based on the smspec vectors WGNAMES, KEYWORDS, UNIT
|
|
and NUMS. The index field of this struct points to where the actual data
|
|
can be found in the PARAMS vector of the *.Snnnn / *.UNSMRY files;
|
|
probably the most important field.
|
|
*/
|
|
|
|
#define SMSPEC_TYPE_ID 61550451
|
|
|
|
|
|
struct smspec_node_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
char * wgname; /* The value of the WGNAMES vector for this element. */
|
|
char * keyword; /* The value of the KEYWORDS vector for this elements. */
|
|
char * unit; /* The value of the UNITS vector for this elements. */
|
|
int num; /* The value of the NUMS vector for this elements - NB this will have the value SMSPEC_NUMS_INVALID if the smspec file does not have a NUMS vector. */
|
|
char * lgr_name; /* The lgr name of the current variable - will be NULL for non-lgr variables. */
|
|
int * lgr_ijk; /* The (i,j,k) coordinate, in the local grid, if this is a LGR variable. WIll be NULL for no-lgr variables. */
|
|
|
|
/*------------------------------------------- All members below this line are *derived* quantities. */
|
|
|
|
char * gen_key1; /* The main composite key, i.e. WWCT:OP3 for this element. */
|
|
char * gen_key2; /* Some of the ijk based elements will have both a xxx:i,j,k and a xxx:num key. Some of the region_2_region elements will have both a xxx:num and a xxx:r2-r2 key. Mostly NULL. */
|
|
ecl_smspec_var_type var_type; /* The variable type */
|
|
int * ijk; /* The ijk coordinates (NB: OFFSET 1) corresponding to the nums value - will be NULL if not relevant. */
|
|
bool rate_variable; /* Is this a rate variable (i.e. WOPR) or a state variable (i.e. BPR). Relevant when doing time interpolation. */
|
|
bool total_variable; /* Is this a total variable like WOPT? */
|
|
bool historical; /* Does the name end with 'H'? */
|
|
int params_index; /* The index of this variable (applies to all the vectors - in particular the PARAMS vectors of the summary files *.Snnnn / *.UNSMRY ). */
|
|
float default_value; /* Default value for this variable. */
|
|
};
|
|
|
|
|
|
|
|
bool smspec_node_equal( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
return smspec_node_cmp( node1 , node2 ) == 0;
|
|
}
|
|
|
|
static bool smspec_node_need_wgname(ecl_smspec_var_type var_type) {
|
|
if (var_type == ECL_SMSPEC_COMPLETION_VAR ||
|
|
var_type == ECL_SMSPEC_GROUP_VAR ||
|
|
var_type == ECL_SMSPEC_WELL_VAR ||
|
|
var_type == ECL_SMSPEC_SEGMENT_VAR)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool smspec_node_type_supported(ecl_smspec_var_type var_type) {
|
|
if (var_type == ECL_SMSPEC_NETWORK_VAR)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
/*
|
|
The key formats for the combined keys like e.g. 'WWCT:OP_5' should
|
|
have the keyword, i.e. 'WWCT', as the first part of the string. That
|
|
guarantees that the function ecl_smspec_identify_var_type() can take
|
|
both a pure ECLIPSE variable name, like .e.g 'WWCT' and also an
|
|
ecl_sum combined key like 'WWCT:OPX' as input.
|
|
*/
|
|
|
|
#define ECL_SUM_KEYFMT_AQUIFER "%s%s%d"
|
|
#define ECL_SUM_KEYFMT_BLOCK_IJK "%s%s%d,%d,%d"
|
|
#define ECL_SUM_KEYFMT_BLOCK_NUM "%s%s%d"
|
|
#define ECL_SUM_KEYFMT_LOCAL_BLOCK "%s%s%s%s%d,%d,%d"
|
|
#define ECL_SUM_KEYFMT_COMPLETION_IJK "%s%s%s%s%d,%d,%d"
|
|
#define ECL_SUM_KEYFMT_COMPLETION_NUM "%s%s%s%s%d"
|
|
#define ECL_SUM_KEYFMT_LOCAL_COMPLETION "%s%s%s%s%s%s%d,%d,%d"
|
|
#define ECL_SUM_KEYFMT_GROUP "%s%s%s"
|
|
#define ECL_SUM_KEYFMT_WELL "%s%s%s"
|
|
#define ECL_SUM_KEYFMT_REGION "%s%s%d"
|
|
#define ECL_SUM_KEYFMT_REGION_2_REGION_R1R2 "%s%s%d-%d"
|
|
#define ECL_SUM_KEYFMT_REGION_2_REGION_NUM "%s%s%d"
|
|
#define ECL_SUM_KEYFMT_SEGMENT "%s%s%s%s%d"
|
|
#define ECL_SUM_KEYFMT_LOCAL_WELL "%s%s%s%s%s"
|
|
|
|
UTIL_SAFE_CAST_FUNCTION( smspec_node , SMSPEC_TYPE_ID )
|
|
static UTIL_SAFE_CAST_FUNCTION_CONST( smspec_node , SMSPEC_TYPE_ID )
|
|
|
|
|
|
char * smspec_alloc_block_num_key( const char * join_string , const char * keyword , int num) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_BLOCK_NUM,
|
|
keyword ,
|
|
join_string ,
|
|
num );
|
|
}
|
|
|
|
char * smspec_alloc_aquifer_key( const char * join_string , const char * keyword , int num) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_AQUIFER,
|
|
keyword ,
|
|
join_string ,
|
|
num );
|
|
}
|
|
|
|
|
|
char * smspec_alloc_local_block_key( const char * join_string , const char * keyword , const char * lgr_name , int i , int j , int k) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_LOCAL_BLOCK ,
|
|
keyword ,
|
|
join_string ,
|
|
lgr_name ,
|
|
join_string ,
|
|
i,j,k);
|
|
}
|
|
|
|
|
|
char * smspec_alloc_region_key( const char * join_string , const char * keyword , int num) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_REGION ,
|
|
keyword ,
|
|
join_string ,
|
|
num );
|
|
}
|
|
|
|
char * smspec_alloc_region_2_region_r1r2_key( const char * join_string , const char * keyword , int r1, int r2) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_REGION_2_REGION_R1R2,
|
|
keyword,
|
|
join_string,
|
|
r1,
|
|
r2);
|
|
}
|
|
|
|
char * smspec_alloc_region_2_region_num_key( const char * join_string , const char * keyword , int num) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_REGION_2_REGION_NUM,
|
|
keyword ,
|
|
join_string ,
|
|
num);
|
|
}
|
|
|
|
|
|
|
|
char * smspec_alloc_block_ijk_key( const char * join_string , const char * keyword , int i , int j , int k) {
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_BLOCK_IJK ,
|
|
keyword,
|
|
join_string ,
|
|
i,j,k);
|
|
}
|
|
|
|
|
|
|
|
char * smspec_alloc_completion_ijk_key( const char * join_string , const char * keyword, const char * wgname , int i , int j , int k) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf( ECL_SUM_KEYFMT_COMPLETION_IJK ,
|
|
keyword ,
|
|
join_string ,
|
|
wgname ,
|
|
join_string ,
|
|
i , j , k );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
char * smspec_alloc_completion_num_key( const char * join_string , const char * keyword, const char * wgname , int num) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_COMPLETION_NUM,
|
|
keyword ,
|
|
join_string ,
|
|
wgname ,
|
|
join_string ,
|
|
num );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
To support ECLIPSE behaviour where new wells/groups can be created
|
|
during the simulation it must be possible to create a smspec node
|
|
with an initially unknown well/group name; all gen_key formats which
|
|
use the wgname value must therefore accept a NULL value for wgname.
|
|
*/
|
|
|
|
static char * smspec_alloc_wgname_key( const char * join_string , const char * keyword , const char * wgname) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_WELL,
|
|
keyword ,
|
|
join_string ,
|
|
wgname );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
char * smspec_alloc_group_key( const char * join_string , const char * keyword , const char * wgname) {
|
|
return smspec_alloc_wgname_key( join_string , keyword , wgname );
|
|
}
|
|
|
|
char * smspec_alloc_well_key( const char * join_string , const char * keyword , const char * wgname) {
|
|
return smspec_alloc_wgname_key( join_string , keyword , wgname );
|
|
}
|
|
|
|
char * smspec_alloc_segment_key( const char * join_string , const char * keyword , const char * wgname , int num) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_SEGMENT ,
|
|
keyword ,
|
|
join_string ,
|
|
wgname ,
|
|
join_string ,
|
|
num );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
char * smspec_alloc_local_well_key( const char * join_string , const char * keyword , const char * lgr_name , const char * wgname) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf( ECL_SUM_KEYFMT_LOCAL_WELL ,
|
|
keyword ,
|
|
join_string ,
|
|
lgr_name ,
|
|
join_string ,
|
|
wgname);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
char * smspec_alloc_local_completion_key( const char * join_string, const char * keyword , const char * lgr_name , const char * wgname , int i , int j , int k) {
|
|
if (wgname != NULL)
|
|
return util_alloc_sprintf(ECL_SUM_KEYFMT_LOCAL_COMPLETION ,
|
|
keyword ,
|
|
join_string ,
|
|
lgr_name ,
|
|
join_string ,
|
|
wgname ,
|
|
join_string ,
|
|
i,j,k);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
static void smspec_node_set_keyword( smspec_node_type * smspec_node , const char * keyword ) {
|
|
// ECLIPSE Standard: Max eight characters - everything beyond is silently dropped
|
|
// This function can __ONLY__ be called on time; run-time chaning of keyword is not
|
|
// allowed.
|
|
if (smspec_node->keyword == NULL)
|
|
smspec_node->keyword = util_alloc_substring_copy( keyword , 0 , 8);
|
|
else
|
|
util_abort("%s: fatal error - attempt to change keyword runtime detected - aborting\n",__func__);
|
|
}
|
|
|
|
|
|
static void smspec_node_set_invalid_flags( smspec_node_type * smspec_node) {
|
|
smspec_node->rate_variable = false;
|
|
smspec_node->total_variable = false;
|
|
smspec_node->historical = false;
|
|
}
|
|
|
|
static char LAST_CHAR(const char * s) {
|
|
return s[ strlen(s) - 1];
|
|
}
|
|
|
|
|
|
bool smspec_node_identify_rate(const char * keyword) {
|
|
const char *rate_vars[] = {"OPR" , "GPR" , "WPR" , "LPR", "OIR", "GIR", "WIR", "LIR", "GOR" , "WCT"};
|
|
int num_rate_vars = sizeof( rate_vars ) / sizeof( rate_vars[0] );
|
|
bool is_rate = false;
|
|
int ivar;
|
|
for (ivar = 0; ivar < num_rate_vars; ivar++) {
|
|
const char * var_substring = &keyword[1];
|
|
if (strncmp( rate_vars[ivar] , var_substring , strlen( rate_vars[ivar] )) == 0) {
|
|
is_rate = true;
|
|
break;
|
|
}
|
|
}
|
|
return is_rate;
|
|
}
|
|
|
|
|
|
bool smspec_node_identify_total(const char * keyword, ecl_smspec_var_type var_type) {
|
|
/*
|
|
This code checks in a predefined list whether a certain WGNAMES
|
|
variable represents a total accumulated quantity. Only the last three
|
|
characters in the variable is considered (i.e. the leading 'W', 'G' or
|
|
'F' is discarded).
|
|
|
|
The list below is all the keyowrds with 'Total' in the information from
|
|
the tables 2.7 - 2.11 in the ECLIPSE fileformat documentation. Have
|
|
skipped some of the most exotic keywords.
|
|
*/
|
|
bool is_total = false;
|
|
if (var_type == ECL_SMSPEC_WELL_VAR ||
|
|
var_type == ECL_SMSPEC_GROUP_VAR ||
|
|
var_type == ECL_SMSPEC_FIELD_VAR ||
|
|
var_type == ECL_SMSPEC_REGION_VAR ||
|
|
var_type == ECL_SMSPEC_COMPLETION_VAR ) {
|
|
const char *total_vars[] = {"OPT" , "GPT" , "WPT" , "GIT", "WIT", "OPTF" , "OPTS" , "OIT" , "OVPT" , "OVIT" , "MWT" ,
|
|
"WVPT" , "WVIT" , "GMT" , "GPTF" , "SGT" , "GST" , "FGT" , "GCT" , "GIMT" ,
|
|
"WGPT" , "WGIT" , "EGT" , "EXGT" , "GVPT" , "GVIT" , "LPT" , "VPT" , "VIT" , "NPT" , "NIT",
|
|
"CPT", "CIT"};
|
|
|
|
int num_total_vars = sizeof( total_vars ) / sizeof( total_vars[0] );
|
|
int ivar;
|
|
for (ivar = 0; ivar < num_total_vars; ivar++) {
|
|
const char * var_substring = &keyword[1];
|
|
/*
|
|
We want to mark both FOPT and FOPTH as total variables;
|
|
we use strncmp() to make certain that the trailing 'H' is
|
|
not included in the comparison.
|
|
*/
|
|
if (strncmp( total_vars[ivar] , var_substring , strlen( total_vars[ivar] )) == 0) {
|
|
is_total = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return is_total;
|
|
}
|
|
|
|
|
|
static void smspec_node_set_flags( smspec_node_type * smspec_node) {
|
|
/*
|
|
Check if this is a rate variabel - that info is used when
|
|
interpolating results to true_time between ministeps.
|
|
*/
|
|
smspec_node->rate_variable = smspec_node_identify_rate(smspec_node->keyword);
|
|
if (LAST_CHAR(smspec_node->keyword) == 'H')
|
|
smspec_node->historical = true;
|
|
smspec_node->total_variable = smspec_node_identify_total(smspec_node->keyword, smspec_node->var_type);
|
|
}
|
|
|
|
/**
|
|
It is possible to change the default value of an smspec node
|
|
runtime, but observe that the new value will only be applied to the
|
|
new timesteps you add after the change. Already created timesteps
|
|
will not be updated if the default value is changed.
|
|
*/
|
|
void smspec_node_set_default( smspec_node_type * smspec_node , float default_value) {
|
|
smspec_node->default_value = default_value;
|
|
}
|
|
|
|
|
|
float smspec_node_get_default( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->default_value;
|
|
}
|
|
|
|
|
|
smspec_node_type * smspec_node_alloc_new(int params_index, float default_value) {
|
|
smspec_node_type * node = (smspec_node_type*)util_malloc( sizeof * node );
|
|
|
|
UTIL_TYPE_ID_INIT( node , SMSPEC_TYPE_ID);
|
|
node->params_index = params_index;
|
|
smspec_node_set_default( node , default_value );
|
|
|
|
node->wgname = NULL;
|
|
node->ijk = NULL;
|
|
|
|
node->gen_key1 = NULL;
|
|
node->gen_key2 = NULL;
|
|
|
|
node->var_type = ECL_SMSPEC_INVALID_VAR;
|
|
node->unit = NULL;
|
|
node->keyword = NULL;
|
|
node->lgr_name = NULL;
|
|
node->lgr_ijk = NULL;
|
|
|
|
smspec_node_set_invalid_flags( node );
|
|
return node; // This is NOT usable
|
|
}
|
|
|
|
|
|
static void smspec_node_set_wgname( smspec_node_type * index , const char * wgname ) {
|
|
index->wgname = util_realloc_string_copy(index->wgname , wgname );
|
|
}
|
|
|
|
|
|
|
|
static void smspec_node_set_lgr_name( smspec_node_type * index , const char * lgr_name ) {
|
|
index->lgr_name = util_realloc_string_copy(index->lgr_name , lgr_name);
|
|
}
|
|
|
|
|
|
static void smspec_node_set_lgr_ijk( smspec_node_type * index , int lgr_i , int lgr_j , int lgr_k) {
|
|
if (index->lgr_ijk == NULL)
|
|
index->lgr_ijk = (int*)util_calloc( 3 , sizeof * index->lgr_ijk );
|
|
|
|
index->lgr_ijk[0] = lgr_i;
|
|
index->lgr_ijk[1] = lgr_j;
|
|
index->lgr_ijk[2] = lgr_k;
|
|
}
|
|
|
|
|
|
static void smspec_node_init_num( smspec_node_type * node , ecl_smspec_var_type var_type) {
|
|
switch( node->var_type ) {
|
|
case(ECL_SMSPEC_WELL_VAR):
|
|
node->num = SMSPEC_NUMS_WELL;
|
|
break;
|
|
case(ECL_SMSPEC_GROUP_VAR):
|
|
node->num = SMSPEC_NUMS_GROUP;
|
|
break;
|
|
case(ECL_SMSPEC_FIELD_VAR):
|
|
node->num = SMSPEC_NUMS_FIELD;
|
|
break;
|
|
default:
|
|
node->num = SMSPEC_NUMS_INVALID;
|
|
}
|
|
}
|
|
static void smspec_node_set_num( smspec_node_type * index , const int grid_dims[3] , int num) {
|
|
if (num == SMSPEC_NUMS_INVALID)
|
|
util_abort("%s: explicitly trying to set nums == SMSPEC_NUMS_INVALID - seems like a bug?!\n",__func__);
|
|
|
|
index->num = num;
|
|
if ((index->var_type == ECL_SMSPEC_COMPLETION_VAR) || (index->var_type == ECL_SMSPEC_BLOCK_VAR)) {
|
|
int global_index = num - 1;
|
|
index->ijk = (int*)util_calloc( 3 , sizeof * index->ijk );
|
|
|
|
index->ijk[2] = global_index / ( grid_dims[0] * grid_dims[1] ); global_index -= index->ijk[2] * (grid_dims[0] * grid_dims[1]);
|
|
index->ijk[1] = global_index / grid_dims[0] ; global_index -= index->ijk[1] * grid_dims[0];
|
|
index->ijk[0] = global_index;
|
|
|
|
index->ijk[0] += 1;
|
|
index->ijk[1] += 1;
|
|
index->ijk[2] += 1;
|
|
}
|
|
}
|
|
|
|
static void smspec_node_decode_R1R2( const smspec_node_type * smspec_node , int * r1 , int * r2) {
|
|
if (smspec_node->var_type == ECL_SMSPEC_REGION_2_REGION_VAR) {
|
|
*r1 = smspec_node->num % 32768;
|
|
*r2 = ((smspec_node->num - (*r1)) / 32768)-10;
|
|
} else {
|
|
*r1 = -1;
|
|
*r2 = -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
This function will init the gen_key field of the smspec_node
|
|
instance; this is the keyw which is used to install the
|
|
smspec_node instance in the gen_var dictionary. The node related
|
|
to grid locations are installed with both a XXX:num and XXX:i,j,k
|
|
in the gen_var dictionary; this function will initializethe XXX:num
|
|
form.
|
|
*/
|
|
|
|
|
|
static void smspec_node_set_gen_keys( smspec_node_type * smspec_node , const char * key_join_string) {
|
|
switch( smspec_node->var_type) {
|
|
case(ECL_SMSPEC_COMPLETION_VAR):
|
|
// KEYWORD:WGNAME:NUM
|
|
smspec_node->gen_key1 = smspec_alloc_completion_ijk_key( key_join_string , smspec_node->keyword , smspec_node->wgname , smspec_node->ijk[0], smspec_node->ijk[1], smspec_node->ijk[2]);
|
|
smspec_node->gen_key2 = smspec_alloc_completion_num_key( key_join_string , smspec_node->keyword , smspec_node->wgname , smspec_node->num);
|
|
break;
|
|
case(ECL_SMSPEC_FIELD_VAR):
|
|
// KEYWORD
|
|
smspec_node->gen_key1 = util_alloc_string_copy( smspec_node->keyword );
|
|
break;
|
|
case(ECL_SMSPEC_GROUP_VAR):
|
|
// KEYWORD:WGNAME
|
|
smspec_node->gen_key1 = smspec_alloc_group_key( key_join_string , smspec_node->keyword , smspec_node->wgname);
|
|
break;
|
|
case(ECL_SMSPEC_WELL_VAR):
|
|
// KEYWORD:WGNAME
|
|
smspec_node->gen_key1 = smspec_alloc_well_key( key_join_string , smspec_node->keyword , smspec_node->wgname);
|
|
break;
|
|
case(ECL_SMSPEC_REGION_VAR):
|
|
// KEYWORD:NUM
|
|
smspec_node->gen_key1 = smspec_alloc_region_key( key_join_string , smspec_node->keyword , smspec_node->num);
|
|
break;
|
|
case (ECL_SMSPEC_SEGMENT_VAR):
|
|
// KEYWORD:WGNAME:NUM
|
|
smspec_node->gen_key1 = smspec_alloc_segment_key( key_join_string , smspec_node->keyword , smspec_node->wgname , smspec_node->num);
|
|
break;
|
|
case(ECL_SMSPEC_REGION_2_REGION_VAR):
|
|
// KEYWORDS:RXF:NUM and RXF:R1-R2
|
|
{
|
|
int r1,r2;
|
|
smspec_node_decode_R1R2( smspec_node , &r1 , &r2);
|
|
smspec_node->gen_key1 = smspec_alloc_region_2_region_r1r2_key( key_join_string , smspec_node->keyword , r1, r2);
|
|
}
|
|
smspec_node->gen_key2 = smspec_alloc_region_2_region_num_key( key_join_string , smspec_node->keyword , smspec_node->num);
|
|
break;
|
|
case(ECL_SMSPEC_MISC_VAR):
|
|
// KEYWORD
|
|
/* Misc variable - i.e. date or CPU time ... */
|
|
smspec_node->gen_key1 = util_alloc_string_copy( smspec_node->keyword );
|
|
break;
|
|
case(ECL_SMSPEC_BLOCK_VAR):
|
|
// KEYWORD:NUM
|
|
smspec_node->gen_key1 = smspec_alloc_block_ijk_key( key_join_string , smspec_node->keyword , smspec_node->ijk[0], smspec_node->ijk[1], smspec_node->ijk[2]);
|
|
smspec_node->gen_key2 = smspec_alloc_block_num_key( key_join_string , smspec_node->keyword , smspec_node->num);
|
|
break;
|
|
case(ECL_SMSPEC_LOCAL_WELL_VAR):
|
|
/** KEYWORD:LGR:WGNAME */
|
|
smspec_node->gen_key1 = smspec_alloc_local_well_key( key_join_string , smspec_node->keyword , smspec_node->lgr_name , smspec_node->wgname);
|
|
break;
|
|
case(ECL_SMSPEC_LOCAL_BLOCK_VAR):
|
|
/* KEYWORD:LGR:i,j,k */
|
|
smspec_node->gen_key1 = smspec_alloc_local_block_key( key_join_string ,
|
|
smspec_node->keyword ,
|
|
smspec_node->lgr_name ,
|
|
smspec_node->lgr_ijk[0] ,
|
|
smspec_node->lgr_ijk[1] ,
|
|
smspec_node->lgr_ijk[2] );
|
|
break;
|
|
case(ECL_SMSPEC_LOCAL_COMPLETION_VAR):
|
|
/* KEYWORD:LGR:WELL:i,j,k */
|
|
smspec_node->gen_key1 = smspec_alloc_local_completion_key( key_join_string ,
|
|
smspec_node->keyword ,
|
|
smspec_node->lgr_name ,
|
|
smspec_node->wgname ,
|
|
smspec_node->lgr_ijk[0],
|
|
smspec_node->lgr_ijk[1],
|
|
smspec_node->lgr_ijk[2]);
|
|
|
|
break;
|
|
case(ECL_SMSPEC_AQUIFER_VAR):
|
|
smspec_node->gen_key1 = smspec_alloc_aquifer_key( key_join_string , smspec_node->keyword , smspec_node->num);
|
|
break;
|
|
default:
|
|
util_abort("%s: internal error - should not be here? \n" , __func__);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void smspec_node_common_init( smspec_node_type * node , ecl_smspec_var_type var_type , const char * keyword , const char * unit ) {
|
|
if (node->var_type == ECL_SMSPEC_INVALID_VAR) {
|
|
smspec_node_set_unit( node , unit );
|
|
smspec_node_set_keyword( node , keyword);
|
|
node->var_type = var_type;
|
|
smspec_node_set_flags( node );
|
|
smspec_node_init_num( node , var_type );
|
|
} else
|
|
util_abort("%s: trying to re-init smspec node with keyword:%s - invalid \n",__func__ , keyword );
|
|
}
|
|
|
|
|
|
static bool smspec_node_init__( smspec_node_type * smspec_node,
|
|
ecl_smspec_var_type var_type ,
|
|
const char * wgname ,
|
|
const char * keyword ,
|
|
const char * unit ,
|
|
const char * key_join_string ,
|
|
const int grid_dims[3] ,
|
|
int num) {
|
|
|
|
bool initOK = true;
|
|
|
|
smspec_node_common_init( smspec_node , var_type , keyword , unit );
|
|
switch (var_type) {
|
|
case(ECL_SMSPEC_COMPLETION_VAR):
|
|
/* Completion variable : WGNAME & NUM */
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
if (num < 0)
|
|
initOK = false;
|
|
break;
|
|
case(ECL_SMSPEC_GROUP_VAR):
|
|
/* Group variable : WGNAME */
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
break;
|
|
case(ECL_SMSPEC_WELL_VAR):
|
|
/* Well variable : WGNAME */
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
break;
|
|
case(ECL_SMSPEC_SEGMENT_VAR):
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
if (num < 0)
|
|
initOK = false;
|
|
break;
|
|
case(ECL_SMSPEC_FIELD_VAR):
|
|
/* Field variable : */
|
|
/* Fully initialized with the smspec_common_init() function */
|
|
break;
|
|
case(ECL_SMSPEC_REGION_VAR):
|
|
/* Region variable : NUM */
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
break;
|
|
case(ECL_SMSPEC_REGION_2_REGION_VAR):
|
|
/* Region 2 region variable : NUM */
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
break;
|
|
case(ECL_SMSPEC_BLOCK_VAR):
|
|
/* A block variable : NUM*/
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
break;
|
|
case(ECL_SMSPEC_MISC_VAR):
|
|
/* Misc variable : */
|
|
|
|
/*
|
|
For some keywords the SMSPEC files generated by Eclipse have a
|
|
non zero NUMS value although; it seems that value is required
|
|
for the generatd summaryfiles to display nicely in
|
|
e.g. S3GRAF.
|
|
*/
|
|
|
|
if (util_string_equal( keyword ,SMSPEC_TIME_KEYWORD))
|
|
smspec_node_set_num( smspec_node , grid_dims , SMSPEC_TIME_NUMS_VALUE );
|
|
|
|
if (util_string_equal( keyword ,SMSPEC_YEARS_KEYWORD))
|
|
smspec_node_set_num( smspec_node , grid_dims , SMSPEC_YEARS_NUMS_VALUE );
|
|
|
|
break;
|
|
case(ECL_SMSPEC_AQUIFER_VAR):
|
|
smspec_node_set_num( smspec_node , grid_dims , num );
|
|
break;
|
|
default:
|
|
/* Lots of legitimate alternatives which are not internalized. */
|
|
initOK = false;
|
|
break;
|
|
}
|
|
|
|
if (initOK)
|
|
smspec_node_set_gen_keys( smspec_node , key_join_string );
|
|
|
|
return initOK;
|
|
}
|
|
|
|
/*
|
|
This function should be removed from the public API.
|
|
*/
|
|
void smspec_node_init( smspec_node_type * smspec_node,
|
|
ecl_smspec_var_type var_type ,
|
|
const char * wgname ,
|
|
const char * keyword ,
|
|
const char * unit ,
|
|
const char * key_join_string ,
|
|
const int grid_dims[3] ,
|
|
int num) {
|
|
|
|
smspec_node_init__(smspec_node,
|
|
var_type,
|
|
wgname,
|
|
keyword,
|
|
unit,
|
|
key_join_string,
|
|
grid_dims,
|
|
num);
|
|
|
|
}
|
|
|
|
/**
|
|
This function will allocate a smspec_node instance, and initialize
|
|
all the elements. Observe that the function can return NULL, in the
|
|
case we do not care to internalize the variable in question,
|
|
i.e. if it is a well_rate from a dummy well or a variable type we
|
|
do not support at all.
|
|
|
|
This function initializes a valid smspec_node instance based on
|
|
the supplied var_type, and the input. Observe that when a new
|
|
variable type is supported, the big switch() statement must be
|
|
updated in the functions ecl_smspec_install_gen_key() and
|
|
ecl_smspec_fread_header() functions in addition. UGGGLY
|
|
*/
|
|
|
|
|
|
|
|
smspec_node_type * smspec_node_alloc( ecl_smspec_var_type var_type ,
|
|
const char * wgname ,
|
|
const char * keyword ,
|
|
const char * unit ,
|
|
const char * key_join_string ,
|
|
const int grid_dims[3] ,
|
|
int num , int param_index, float default_value) {
|
|
/*
|
|
Well and group names in the wgname parameter is quite messy. The
|
|
situation is as follows:
|
|
|
|
o The ECLIPSE SMSPEC files are very verbose, and contain many
|
|
entries like this:
|
|
|
|
KEYWORD : "WWCT"
|
|
WGNAME : ":+:+:+:+"
|
|
|
|
i.e. the keyword indicates that this is a perfectly legitimate
|
|
well variable, however the special wgname value ":+:+:+:+"
|
|
shows that this just a rubbish entry. We do not want to
|
|
internalize these rubbish entries and this function should just
|
|
return NULL.
|
|
|
|
The ":+:+:+:+" string is in the #define symbol DUMMY_WELL and
|
|
the macro IS_DUMMY_WELL(wgname) can used to compare with the
|
|
DUMMY_WELL value.
|
|
|
|
o When the ecl_sum instance is created in write mode; it must be
|
|
possible to add smspec nodes for wells/groups which do not have
|
|
a name yet. In this case we accept NULL as input value for the
|
|
wgname parameter.
|
|
|
|
o In the case of variables which do not use the wgname variable
|
|
at all, e.g. like "FOPT" - the wgname input value is ignored
|
|
completely.
|
|
*/
|
|
|
|
if (smspec_node_need_wgname(var_type) && IS_DUMMY_WELL(wgname))
|
|
return NULL;
|
|
|
|
if (!smspec_node_type_supported(var_type))
|
|
return NULL;
|
|
|
|
/*
|
|
TODO: The alloc_new and init functions should be joined in one function.
|
|
*/
|
|
smspec_node_type * smspec_node = smspec_node_alloc_new( param_index , default_value );
|
|
bool initOK = smspec_node_init__( smspec_node , var_type , wgname , keyword , unit , key_join_string , grid_dims, num);
|
|
if (!initOK) {
|
|
smspec_node_free(smspec_node);
|
|
smspec_node = NULL;
|
|
}
|
|
|
|
return smspec_node;
|
|
}
|
|
|
|
|
|
|
|
static void smspec_node_init_lgr( smspec_node_type * smspec_node ,
|
|
ecl_smspec_var_type var_type ,
|
|
const char * wgname ,
|
|
const char * keyword ,
|
|
const char * unit ,
|
|
const char * lgr ,
|
|
const char * key_join_string ,
|
|
int lgr_i, int lgr_j , int lgr_k
|
|
) {
|
|
bool initOK = true;
|
|
bool wgnameOK = true;
|
|
if ((wgname != NULL) && (IS_DUMMY_WELL(wgname)))
|
|
wgnameOK = false;
|
|
|
|
smspec_node_common_init( smspec_node , var_type , keyword , unit );
|
|
switch (var_type) {
|
|
case(ECL_SMSPEC_LOCAL_WELL_VAR):
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
smspec_node_set_lgr_name( smspec_node , lgr );
|
|
initOK = wgnameOK;
|
|
break;
|
|
case(ECL_SMSPEC_LOCAL_BLOCK_VAR):
|
|
smspec_node_set_lgr_name( smspec_node , lgr );
|
|
smspec_node_set_lgr_ijk( smspec_node , lgr_i, lgr_j , lgr_k );
|
|
break;
|
|
case(ECL_SMSPEC_LOCAL_COMPLETION_VAR):
|
|
smspec_node_set_lgr_name( smspec_node , lgr );
|
|
smspec_node_set_wgname( smspec_node , wgname );
|
|
smspec_node_set_lgr_ijk( smspec_node , lgr_i, lgr_j , lgr_k );
|
|
initOK = wgnameOK;
|
|
break;
|
|
default:
|
|
util_abort("%s: internal error: in LGR function with non-LGR keyword:%s \n",__func__ , keyword);
|
|
}
|
|
|
|
if (initOK)
|
|
smspec_node_set_gen_keys( smspec_node , key_join_string );
|
|
}
|
|
|
|
|
|
|
|
smspec_node_type * smspec_node_alloc_lgr( ecl_smspec_var_type var_type ,
|
|
const char * wgname ,
|
|
const char * keyword ,
|
|
const char * unit ,
|
|
const char * lgr ,
|
|
const char * key_join_string ,
|
|
int lgr_i, int lgr_j , int lgr_k,
|
|
int param_index , float default_value) {
|
|
|
|
smspec_node_type * smspec_node = smspec_node_alloc_new( param_index , default_value );
|
|
smspec_node_init_lgr( smspec_node , var_type , wgname , keyword , unit , lgr , key_join_string , lgr_i, lgr_j , lgr_k);
|
|
return smspec_node;
|
|
}
|
|
|
|
smspec_node_type* smspec_node_alloc_copy( const smspec_node_type* node ) {
|
|
|
|
if( !node ) return NULL;
|
|
|
|
{
|
|
smspec_node_type* copy = (smspec_node_type*)util_malloc( sizeof * copy );
|
|
UTIL_TYPE_ID_INIT( copy, SMSPEC_TYPE_ID );
|
|
copy->gen_key1 = util_alloc_string_copy( node->gen_key1 );
|
|
copy->gen_key2 = util_alloc_string_copy( node->gen_key2 );
|
|
copy->var_type = node->var_type;
|
|
copy->wgname = util_alloc_string_copy( node->wgname );
|
|
copy->keyword = util_alloc_string_copy( node->keyword );
|
|
copy->unit = util_alloc_string_copy( node->unit );
|
|
copy->num = node->num;
|
|
|
|
copy->ijk = NULL;
|
|
if( node->ijk ) {
|
|
copy->ijk = (int*)util_calloc( 3 , sizeof * node->ijk );
|
|
memcpy( copy->ijk, node->ijk, 3 * sizeof( * node->ijk ) );
|
|
}
|
|
|
|
copy->lgr_name = util_alloc_string_copy( node->lgr_name );
|
|
copy->lgr_ijk = NULL;
|
|
if( node->lgr_ijk ) {
|
|
copy->lgr_ijk = (int*)util_calloc( 3 , sizeof * node->lgr_ijk );
|
|
memcpy( copy->lgr_ijk, node->lgr_ijk, 3 * sizeof( * node->lgr_ijk ) );
|
|
}
|
|
|
|
copy->rate_variable = node->rate_variable;
|
|
copy->total_variable = node->total_variable;
|
|
copy->historical = node->historical;
|
|
copy->params_index = node->params_index;
|
|
copy->default_value = node->default_value;
|
|
return copy;
|
|
}
|
|
}
|
|
|
|
void smspec_node_free( smspec_node_type * index ) {
|
|
free( index->unit );
|
|
free( index->keyword );
|
|
free( index->ijk );
|
|
free( index->gen_key1 );
|
|
free( index->gen_key2 );
|
|
free( index->wgname );
|
|
free( index->lgr_name );
|
|
free( index->lgr_ijk );
|
|
free( index );
|
|
}
|
|
|
|
void smspec_node_free__( void * arg ) {
|
|
smspec_node_type * node = smspec_node_safe_cast( arg );
|
|
smspec_node_free( node );
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
|
|
int smspec_node_get_params_index( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->params_index;
|
|
}
|
|
|
|
|
|
void smspec_node_set_params_index( smspec_node_type * smspec_node , int params_index) {
|
|
smspec_node->params_index = params_index;
|
|
}
|
|
|
|
const char * smspec_node_get_gen_key1( const smspec_node_type * smspec_node) {
|
|
return smspec_node->gen_key1;
|
|
}
|
|
|
|
const char * smspec_node_get_gen_key2( const smspec_node_type * smspec_node) {
|
|
return smspec_node->gen_key2;
|
|
}
|
|
|
|
|
|
const char * smspec_node_get_wgname( const smspec_node_type * smspec_node) {
|
|
return smspec_node->wgname;
|
|
}
|
|
|
|
const char * smspec_node_get_keyword( const smspec_node_type * smspec_node) {
|
|
return smspec_node->keyword;
|
|
}
|
|
|
|
|
|
|
|
ecl_smspec_var_type smspec_node_get_var_type( const smspec_node_type * smspec_node) {
|
|
return smspec_node->var_type;
|
|
}
|
|
|
|
int smspec_node_get_num( const smspec_node_type * smspec_node) {
|
|
return smspec_node->num;
|
|
}
|
|
|
|
bool smspec_node_is_rate( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->rate_variable;
|
|
}
|
|
|
|
|
|
bool smspec_node_is_total( const smspec_node_type * smspec_node ){
|
|
return smspec_node->total_variable;
|
|
}
|
|
|
|
bool smspec_node_is_historical( const smspec_node_type * smspec_node ){
|
|
return smspec_node->historical;
|
|
}
|
|
|
|
const char * smspec_node_get_unit( const smspec_node_type * smspec_node) {
|
|
return smspec_node->unit;
|
|
}
|
|
|
|
void smspec_node_set_unit( smspec_node_type * smspec_node , const char * unit ) {
|
|
// ECLIPSE Standard: Max eight characters - everything beyond is silently dropped
|
|
free( smspec_node->unit );
|
|
smspec_node->unit = util_alloc_substring_copy( unit , 0 , 8);
|
|
}
|
|
|
|
|
|
// Will be NULL for smspec_nodes which do not have i,j,k
|
|
const int* smspec_node_get_ijk( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->ijk;
|
|
}
|
|
|
|
// Will be NULL for smspec_nodes which are not related to an LGR.
|
|
const char* smspec_node_get_lgr_name( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->lgr_name;
|
|
}
|
|
|
|
// Will be NULL for smspec_nodes which are not related to an LGR.
|
|
const int* smspec_node_get_lgr_ijk( const smspec_node_type * smspec_node ) {
|
|
return smspec_node->lgr_ijk;
|
|
}
|
|
|
|
/*
|
|
Will return -1 for smspec_node variables which are not
|
|
of type ECL_SMSPEC_REGION_2_REGION_VAR.
|
|
*/
|
|
|
|
int smspec_node_get_R1( const smspec_node_type * smspec_node ) {
|
|
if (smspec_node->var_type == ECL_SMSPEC_REGION_2_REGION_VAR) {
|
|
int r1,r2;
|
|
smspec_node_decode_R1R2( smspec_node , &r1 , &r2);
|
|
return r1;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
int smspec_node_get_R2( const smspec_node_type * smspec_node ) {
|
|
if (smspec_node->var_type == ECL_SMSPEC_REGION_2_REGION_VAR) {
|
|
int r1,r2;
|
|
smspec_node_decode_R1R2( smspec_node , &r1 , &r2);
|
|
return r2;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool smspec_node_need_nums( const smspec_node_type * smspec_node ) {
|
|
/*
|
|
Check if this node needs the nums field; if at least one of the
|
|
nodes need the NUMS field must be stored when writing a SMSPEC
|
|
file.
|
|
*/
|
|
{
|
|
if (smspec_node->var_type == ECL_SMSPEC_COMPLETION_VAR ||
|
|
smspec_node->var_type == ECL_SMSPEC_SEGMENT_VAR ||
|
|
smspec_node->var_type == ECL_SMSPEC_REGION_VAR ||
|
|
smspec_node->var_type == ECL_SMSPEC_REGION_2_REGION_VAR ||
|
|
smspec_node->var_type == ECL_SMSPEC_BLOCK_VAR ||
|
|
smspec_node->var_type == ECL_SMSPEC_AQUIFER_VAR)
|
|
return true;
|
|
else {
|
|
if (smspec_node->num == SMSPEC_NUMS_INVALID)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void smspec_node_fprintf( const smspec_node_type * smspec_node , FILE * stream) {
|
|
fprintf(stream, "KEYWORD: %s \n",smspec_node->keyword);
|
|
fprintf(stream, "WGNAME : %s \n",smspec_node->wgname);
|
|
fprintf(stream, "UNIT : %s \n",smspec_node->unit);
|
|
fprintf(stream, "TYPE : %d \n",smspec_node->var_type);
|
|
fprintf(stream, "NUM : %d \n\n",smspec_node->num);
|
|
}
|
|
|
|
|
|
static bool smspec_node_equal_MISC( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
return util_string_equal( node1->keyword , node2->keyword);
|
|
}
|
|
|
|
|
|
/*
|
|
MISC variables are generally sorted to the end of the list,
|
|
but some special case variables come at the very beginning.
|
|
*/
|
|
|
|
static int smspec_node_cmp_MISC( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
static const char* early_vars[] = {"TIME",
|
|
"DAYS",
|
|
"DAY",
|
|
"MONTH",
|
|
"YEAR",
|
|
"YEARS"};
|
|
|
|
if (smspec_node_equal_MISC( node1, node2) )
|
|
return 0;
|
|
|
|
bool node1_early = false;
|
|
bool node2_early = false;
|
|
|
|
for (int i=0; i < 6; i++) {
|
|
if (util_string_equal( node1->keyword, early_vars[i] ))
|
|
node1_early = true;
|
|
|
|
if (util_string_equal( node2->keyword, early_vars[i] ))
|
|
node2_early = true;
|
|
|
|
}
|
|
if (node1_early && !node2_early)
|
|
return -1;
|
|
|
|
if (!node1_early && node2_early)
|
|
return 1;
|
|
|
|
return strcmp( node1->keyword, node2->keyword);
|
|
}
|
|
|
|
|
|
static int int_cmp(int v1, int v2) {
|
|
if (v1 < v2)
|
|
return -1;
|
|
|
|
if (v1 > v2)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int smspec_node_cmp_LGRIJK( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int i_cmp = int_cmp( node1->lgr_ijk[0] , node2->lgr_ijk[0]);
|
|
if (i_cmp != 0)
|
|
return i_cmp;
|
|
|
|
int j_cmp = int_cmp( node1->lgr_ijk[1] , node2->lgr_ijk[1]);
|
|
if (j_cmp != 0)
|
|
return j_cmp;
|
|
|
|
return int_cmp( node1->lgr_ijk[2] , node2->lgr_ijk[2]);
|
|
}
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD_LGR_LGRIJK( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
int lgr_cmp = strcmp( node1->lgr_name , node2->lgr_name);
|
|
if (lgr_cmp != 0)
|
|
return lgr_cmp;
|
|
|
|
return smspec_node_cmp_LGRIJK( node1, node2);
|
|
}
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD_WGNAME_NUM( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
int wgname_cmp = strcmp( node1->wgname , node2->wgname);
|
|
if (wgname_cmp != 0)
|
|
return wgname_cmp;
|
|
|
|
return int_cmp( node1->num , node2->num);
|
|
}
|
|
|
|
static int smspec_node_cmp_KEYWORD_WGNAME_LGR( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
int wgname_cmp = strcmp( node1->wgname , node2->wgname);
|
|
if (wgname_cmp != 0)
|
|
return wgname_cmp;
|
|
|
|
return strcmp( node1->lgr_name , node2->lgr_name);
|
|
}
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD_WGNAME_LGR_LGRIJK( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
int wgname_cmp = strcmp( node1->wgname , node2->wgname);
|
|
if (wgname_cmp != 0)
|
|
return wgname_cmp;
|
|
|
|
int lgr_cmp = strcmp( node1->lgr_name , node2->lgr_name);
|
|
if (lgr_cmp != 0)
|
|
return lgr_cmp;
|
|
|
|
return smspec_node_cmp_LGRIJK( node1, node2);
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD_WGNAME( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
if (IS_DUMMY_WELL( node1->wgname )) {
|
|
if (IS_DUMMY_WELL( node2->wgname ))
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
if (IS_DUMMY_WELL( node2->wgname ))
|
|
return -1;
|
|
|
|
return strcmp( node1->wgname , node2->wgname);
|
|
}
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD_NUM( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
int keyword_cmp = strcmp( node1->keyword , node2->keyword);
|
|
if (keyword_cmp != 0)
|
|
return keyword_cmp;
|
|
|
|
return int_cmp( node1->num , node2->num);
|
|
}
|
|
|
|
|
|
static int smspec_node_cmp_KEYWORD( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
return strcmp( node1->keyword , node2->keyword );
|
|
}
|
|
|
|
static int smspec_node_cmp_key1( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
if (!node1->gen_key1) {
|
|
if (!node2->gen_key1)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
} else if (!node2->gen_key1) {
|
|
return 1;
|
|
}
|
|
return util_strcmp_int( node1->gen_key1 , node2->gen_key1 );
|
|
}
|
|
|
|
|
|
|
|
int smspec_node_cmp( const smspec_node_type * node1, const smspec_node_type * node2) {
|
|
/* 1: Start with special casing for the MISC variables. */
|
|
if ((node1->var_type == ECL_SMSPEC_MISC_VAR) || (node2->var_type == ECL_SMSPEC_MISC_VAR))
|
|
return smspec_node_cmp_MISC( node1 , node2 );
|
|
|
|
/* 2: Sort according to variable type */
|
|
if (node1->var_type < node2->var_type)
|
|
return -1;
|
|
|
|
if (node1->var_type > node2->var_type)
|
|
return 1;
|
|
|
|
/* 3: Internal sort of variables of the same type. */
|
|
switch (node1->var_type) {
|
|
|
|
case( ECL_SMSPEC_FIELD_VAR):
|
|
return smspec_node_cmp_KEYWORD( node1, node2);
|
|
|
|
case( ECL_SMSPEC_WELL_VAR):
|
|
case( ECL_SMSPEC_GROUP_VAR):
|
|
return smspec_node_cmp_KEYWORD_WGNAME( node1, node2);
|
|
|
|
case( ECL_SMSPEC_BLOCK_VAR):
|
|
case( ECL_SMSPEC_REGION_VAR):
|
|
case( ECL_SMSPEC_REGION_2_REGION_VAR):
|
|
case( ECL_SMSPEC_AQUIFER_VAR):
|
|
return smspec_node_cmp_KEYWORD_NUM( node1, node2);
|
|
|
|
case( ECL_SMSPEC_COMPLETION_VAR):
|
|
case( ECL_SMSPEC_SEGMENT_VAR):
|
|
return smspec_node_cmp_KEYWORD_WGNAME_NUM( node1, node2);
|
|
|
|
case (ECL_SMSPEC_NETWORK_VAR):
|
|
return smspec_node_cmp_key1( node1, node2);
|
|
|
|
case( ECL_SMSPEC_LOCAL_BLOCK_VAR):
|
|
return smspec_node_cmp_KEYWORD_LGR_LGRIJK( node1, node2);
|
|
|
|
case( ECL_SMSPEC_LOCAL_WELL_VAR):
|
|
return smspec_node_cmp_KEYWORD_WGNAME_LGR( node1, node2);
|
|
|
|
case( ECL_SMSPEC_LOCAL_COMPLETION_VAR):
|
|
return smspec_node_cmp_KEYWORD_WGNAME_LGR_LGRIJK( node1, node2);
|
|
|
|
default:
|
|
/* Should not really end up here. */
|
|
return smspec_node_cmp_key1( node1, node2);
|
|
}
|
|
}
|
|
|
|
int smspec_node_cmp__( const void * node1, const void * node2) {
|
|
return smspec_node_cmp( smspec_node_safe_cast_const( node1 ),
|
|
smspec_node_safe_cast_const( node2 ));
|
|
}
|
|
|