mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
* Rename to resdata * Remove development feature for storing grid import type in project file * Clean up comments
683 lines
26 KiB
C++
683 lines
26 KiB
C++
/*
|
|
Copyright (C) 2011 Equinor 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 <math.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include <ert/util/util.h>
|
|
|
|
#include <ert/ecl/ecl_kw.hpp>
|
|
#include <ert/ecl/ecl_util.hpp>
|
|
#include <ert/ecl/ecl_file.hpp>
|
|
#include <ert/ecl/ecl_grid.hpp>
|
|
#include <ert/ecl/ecl_region.hpp>
|
|
#include <ert/ecl/ecl_grav.hpp>
|
|
#include <ert/ecl/ecl_kw_magic.hpp>
|
|
#include <ert/ecl/ecl_grav_common.hpp>
|
|
|
|
#include "detail/ecl/ecl_grid_cache.hpp"
|
|
|
|
/**
|
|
This file contains datastructures for calculating changes in
|
|
gravitational response in reservoirs. The main datastructure is the
|
|
ecl_grav_type structure (which is the only structure which is
|
|
exported).
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define GRAV_CALC_USE_PORV 128
|
|
#define GRAV_CALC_USE_RHO 256 // The GRAV_CALC_USE_RHO value is currently not used.
|
|
|
|
typedef enum {
|
|
GRAV_CALC_RPORV = 1 + GRAV_CALC_USE_PORV + GRAV_CALC_USE_RHO,
|
|
GRAV_CALC_PORMOD = 2 + GRAV_CALC_USE_PORV + GRAV_CALC_USE_RHO,
|
|
GRAV_CALC_FIP = 3,
|
|
GRAV_CALC_RFIP = 4 + GRAV_CALC_USE_RHO
|
|
} grav_calc_type;
|
|
|
|
|
|
typedef struct ecl_grav_phase_struct ecl_grav_phase_type;
|
|
|
|
|
|
/**
|
|
The ecl_grav_struct datastructure is the main structure for
|
|
calculating the gravimetric response from time lapse ECLIPSE
|
|
simulations.
|
|
*/
|
|
|
|
struct ecl_grav_struct {
|
|
const ecl_file_type * init_file; /* The init file - a shared reference owned by calling scope. */
|
|
ecl::ecl_grid_cache * grid_cache; /* An internal specialized structure to facilitate fast grid lookup. */
|
|
bool * aquifer_cell; /* Numerical aquifer cells should be ignored. */
|
|
|
|
std::unordered_map<std::string, ecl_grav_survey_type *> surveys;
|
|
std::unordered_map<std::string, double> default_density;
|
|
std::unordered_map<std::string, std::vector<double>> std_density;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
Data structure representing one gravimetric survey.
|
|
*/
|
|
|
|
#define ECL_GRAV_SURVEY_ID 88517
|
|
struct ecl_grav_survey_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
const ecl::ecl_grid_cache * grid_cache;
|
|
const bool * aquifer_cell;
|
|
char * name; /* Name of the survey - arbitrary string. */
|
|
double * porv; /* Reference shared by the ecl_grav_phase structures - i.e. it must not be updated. */
|
|
std::vector<ecl_grav_phase_type*> phase_list; /* ecl_grav_phase_type objects - one for each phase present in the model. */
|
|
std::unordered_map<std::string, ecl_grav_phase_type*> phase_map; /* The same objects as in the phase_list vector - accessible by the "SWAT", "SGAS" and "SOIL" keys. */
|
|
};
|
|
|
|
|
|
/**
|
|
Data structure representing the results from one phase at one survey.
|
|
*/
|
|
|
|
#define ECL_GRAV_PHASE_TYPE_ID 1066652
|
|
struct ecl_grav_phase_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
const ecl::ecl_grid_cache * grid_cache;
|
|
const bool * aquifer_cell;
|
|
double * fluid_mass; /* The total fluid in place (mass) of this phase - for each active cell.*/
|
|
double * work; /* Temporary used in the summation over all cells. */
|
|
ecl_phase_enum phase;
|
|
};
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
|
|
static const char * get_den_kw( ecl_phase_enum phase , ecl_version_enum ecl_version) {
|
|
if (ecl_version == ECLIPSE100) {
|
|
switch( phase ) {
|
|
case( ECL_OIL_PHASE ):
|
|
return ECLIPSE100_OIL_DEN_KW;
|
|
break;
|
|
case( ECL_GAS_PHASE ):
|
|
return ECLIPSE100_GAS_DEN_KW;
|
|
break;
|
|
case( ECL_WATER_PHASE ):
|
|
return ECLIPSE100_WATER_DEN_KW;
|
|
break;
|
|
default:
|
|
util_abort("%s: unrecognized phase id:%d \n",__func__ , phase);
|
|
return NULL;
|
|
}
|
|
} else if ((ecl_version == ECLIPSE300) || (ecl_version == ECLIPSE300_THERMAL)) {
|
|
switch( phase ) {
|
|
case( ECL_OIL_PHASE ):
|
|
return ECLIPSE300_OIL_DEN_KW;
|
|
break;
|
|
case( ECL_GAS_PHASE ):
|
|
return ECLIPSE300_GAS_DEN_KW;
|
|
break;
|
|
case( ECL_WATER_PHASE ):
|
|
return ECLIPSE300_WATER_DEN_KW;
|
|
break;
|
|
default:
|
|
util_abort("%s: unrecognized phase id:%d \n",__func__ , phase);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
util_abort("%s: unrecognized simulator id:%d \n",__func__ , ecl_version);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static void ecl_grav_phase_ensure_work( ecl_grav_phase_type * grav_phase) {
|
|
if (grav_phase->work == NULL)
|
|
grav_phase->work = (double*)util_calloc( grav_phase->grid_cache->size() , sizeof * grav_phase->work );
|
|
}
|
|
|
|
|
|
static double ecl_grav_phase_eval( ecl_grav_phase_type * base_phase ,
|
|
const ecl_grav_phase_type * monitor_phase,
|
|
ecl_region_type * region ,
|
|
double utm_x , double utm_y , double depth) {
|
|
|
|
ecl_grav_phase_ensure_work( base_phase );
|
|
if ((monitor_phase == NULL) || (base_phase->phase == monitor_phase->phase)) {
|
|
const ecl::ecl_grid_cache& grid_cache = *(base_phase->grid_cache);
|
|
const bool * aquifer = base_phase->aquifer_cell;
|
|
double * mass_diff = base_phase->work;
|
|
double deltag;
|
|
/*
|
|
Initialize a work array to contain the difference in mass for
|
|
every cell.
|
|
*/
|
|
{
|
|
int index;
|
|
if (monitor_phase == NULL) {
|
|
for (index = 0; index < grid_cache.size(); index++)
|
|
mass_diff[index] = - base_phase->fluid_mass[index];
|
|
} else {
|
|
for (index = 0; index < grid_cache.size(); index++)
|
|
mass_diff[index] = monitor_phase->fluid_mass[index] - base_phase->fluid_mass[index];
|
|
}
|
|
}
|
|
|
|
/**
|
|
The Gravitational constant is 6.67E-11 N (m/kg)^2, we
|
|
return the result in microGal, i.e. we scale with 10^2 *
|
|
10^6 => 6.67E-3.
|
|
*/
|
|
deltag = 6.67428E-3 * ecl_grav_common_eval_biot_savart( grid_cache , region , aquifer , mass_diff , utm_x , utm_y , depth);
|
|
|
|
return deltag;
|
|
} else {
|
|
util_abort("%s comparing different phases ... \n",__func__);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static ecl_grav_phase_type * ecl_grav_phase_alloc( ecl_grav_type * ecl_grav ,
|
|
ecl_grav_survey_type * survey ,
|
|
ecl_phase_enum phase ,
|
|
const ecl_file_view_type * restart_file,
|
|
grav_calc_type calc_type) {
|
|
|
|
const ecl_file_type * init_file = ecl_grav->init_file;
|
|
const ecl::ecl_grid_cache * grid_cache = ecl_grav->grid_cache;
|
|
const char * sat_kw_name = ecl_util_get_phase_name( phase );
|
|
{
|
|
ecl_grav_phase_type * grav_phase = new ecl_grav_phase_type();
|
|
const int size = grid_cache->size();
|
|
|
|
UTIL_TYPE_ID_INIT( grav_phase , ECL_GRAV_PHASE_TYPE_ID );
|
|
grav_phase->grid_cache = grid_cache;
|
|
grav_phase->aquifer_cell = ecl_grav->aquifer_cell;
|
|
grav_phase->fluid_mass = (double*)util_calloc( size , sizeof * grav_phase->fluid_mass );
|
|
grav_phase->phase = phase;
|
|
grav_phase->work = NULL;
|
|
|
|
if (calc_type == GRAV_CALC_FIP) {
|
|
ecl_kw_type * pvtnum_kw = ecl_file_iget_named_kw( init_file , PVTNUM_KW , 0 );
|
|
const std::vector<double> std_density = ecl_grav->std_density[std::string(ecl_util_get_phase_name(phase))];
|
|
ecl_kw_type * fip_kw;
|
|
|
|
if ( phase == ECL_OIL_PHASE)
|
|
fip_kw = ecl_file_view_iget_named_kw( restart_file , FIPOIL_KW , 0 );
|
|
else if (phase == ECL_GAS_PHASE)
|
|
fip_kw = ecl_file_view_iget_named_kw( restart_file , FIPGAS_KW , 0 );
|
|
else
|
|
fip_kw = ecl_file_view_iget_named_kw( restart_file , FIPWAT_KW , 0 );
|
|
|
|
{
|
|
int iactive;
|
|
for (iactive=0; iactive < size; iactive++) {
|
|
double fip = ecl_kw_iget_as_double( fip_kw , iactive );
|
|
int pvtnum = ecl_kw_iget_int( pvtnum_kw , iactive );
|
|
grav_phase->fluid_mass[ iactive ] = fip * std_density[pvtnum];
|
|
}
|
|
}
|
|
} else {
|
|
ecl_version_enum ecl_version = ecl_file_get_ecl_version( init_file );
|
|
const char * den_kw_name = get_den_kw( phase , ecl_version );
|
|
const ecl_kw_type * den_kw = ecl_file_view_iget_named_kw( restart_file , den_kw_name , 0 );
|
|
|
|
if (calc_type == GRAV_CALC_RFIP) {
|
|
ecl_kw_type * rfip_kw;
|
|
if ( phase == ECL_OIL_PHASE)
|
|
rfip_kw = ecl_file_view_iget_named_kw( restart_file , RFIPOIL_KW , 0 );
|
|
else if (phase == ECL_GAS_PHASE)
|
|
rfip_kw = ecl_file_view_iget_named_kw( restart_file , RFIPGAS_KW , 0 );
|
|
else
|
|
rfip_kw = ecl_file_view_iget_named_kw( restart_file , RFIPWAT_KW , 0 );
|
|
|
|
{
|
|
int iactive;
|
|
for (iactive=0; iactive < size; iactive++) {
|
|
double rho = ecl_kw_iget_as_double( den_kw , iactive );
|
|
double rfip = ecl_kw_iget_as_double( rfip_kw , iactive );
|
|
grav_phase->fluid_mass[ iactive ] = rho * rfip;
|
|
}
|
|
}
|
|
} else {
|
|
/* (calc_type == GRAV_CALC_RPORV) || (calc_type == GRAV_CALC_PORMOD) */
|
|
ecl_kw_type * sat_kw;
|
|
bool private_sat_kw = false;
|
|
if (ecl_file_view_has_kw( restart_file , sat_kw_name ))
|
|
sat_kw = ecl_file_view_iget_named_kw( restart_file , sat_kw_name , 0 );
|
|
else {
|
|
/* We are targeting the residual phase, e.g. the OIL phase in a three phase system. */
|
|
const ecl_kw_type * swat_kw = ecl_file_view_iget_named_kw( restart_file , "SWAT" , 0 );
|
|
sat_kw = ecl_kw_alloc_copy( swat_kw );
|
|
ecl_kw_scalar_set_float( sat_kw , 1.0 );
|
|
ecl_kw_inplace_sub( sat_kw , swat_kw ); /* sat = 1 - SWAT */
|
|
|
|
if (ecl_file_view_has_kw( restart_file , "SGAS" )) {
|
|
const ecl_kw_type * sgas_kw = ecl_file_view_iget_named_kw( restart_file , "SGAS" , 0 );
|
|
ecl_kw_inplace_sub( sat_kw , sgas_kw ); /* sat -= SGAS */
|
|
}
|
|
private_sat_kw = true;
|
|
}
|
|
|
|
{
|
|
int iactive;
|
|
for (iactive=0; iactive < size; iactive++) {
|
|
double rho = ecl_kw_iget_as_double( den_kw , iactive );
|
|
double sat = ecl_kw_iget_as_double( sat_kw , iactive );
|
|
grav_phase->fluid_mass[ iactive ] = rho * sat * survey->porv[ iactive ];
|
|
}
|
|
}
|
|
|
|
if (private_sat_kw)
|
|
ecl_kw_free( sat_kw );
|
|
}
|
|
}
|
|
|
|
return grav_phase;
|
|
}
|
|
}
|
|
|
|
|
|
static void ecl_grav_phase_free( ecl_grav_phase_type * grav_phase ) {
|
|
free( grav_phase->work );
|
|
free( grav_phase->fluid_mass );
|
|
delete grav_phase;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
static void ecl_grav_survey_add_phase( ecl_grav_survey_type * survey, ecl_phase_enum phase , ecl_grav_phase_type * grav_phase ) {
|
|
survey->phase_list.push_back(grav_phase);
|
|
survey->phase_map[std::string(ecl_util_get_phase_name(phase))] = grav_phase;
|
|
}
|
|
|
|
|
|
static void ecl_grav_survey_add_phases( ecl_grav_type * ecl_grav , ecl_grav_survey_type * survey, const ecl_file_view_type * restart_file , grav_calc_type calc_type) {
|
|
int phases = ecl_file_get_phases( ecl_grav->init_file );
|
|
if (phases & ECL_OIL_PHASE) {
|
|
ecl_grav_phase_type * oil_phase = ecl_grav_phase_alloc( ecl_grav , survey , ECL_OIL_PHASE , restart_file , calc_type);
|
|
ecl_grav_survey_add_phase( survey , ECL_OIL_PHASE , oil_phase );
|
|
}
|
|
|
|
if (phases & ECL_GAS_PHASE) {
|
|
ecl_grav_phase_type * gas_phase = ecl_grav_phase_alloc( ecl_grav , survey , ECL_GAS_PHASE , restart_file , calc_type);
|
|
ecl_grav_survey_add_phase( survey , ECL_GAS_PHASE , gas_phase );
|
|
}
|
|
|
|
if (phases & ECL_WATER_PHASE) {
|
|
ecl_grav_phase_type * water_phase = ecl_grav_phase_alloc( ecl_grav , survey , ECL_WATER_PHASE , restart_file , calc_type);
|
|
ecl_grav_survey_add_phase( survey , ECL_WATER_PHASE , water_phase );
|
|
}
|
|
}
|
|
|
|
|
|
static ecl_grav_survey_type * ecl_grav_survey_alloc_empty(const ecl_grav_type * ecl_grav ,
|
|
const char * name ,
|
|
grav_calc_type calc_type) {
|
|
ecl_grav_survey_type * survey = new ecl_grav_survey_type();
|
|
UTIL_TYPE_ID_INIT( survey , ECL_GRAV_SURVEY_ID );
|
|
survey->grid_cache = ecl_grav->grid_cache;
|
|
survey->aquifer_cell = ecl_grav->aquifer_cell;
|
|
survey->name = util_alloc_string_copy( name );
|
|
|
|
if (calc_type & GRAV_CALC_USE_PORV)
|
|
survey->porv = (double*)util_calloc( ecl_grav->grid_cache->size() , sizeof * survey->porv );
|
|
else
|
|
survey->porv = NULL;
|
|
|
|
return survey;
|
|
}
|
|
|
|
|
|
/**
|
|
Check that the rporv values are in the right ballpark. For ECLIPSE
|
|
version 2008.2 they are way off. Check PORV versus RPORV
|
|
for some random locations in the grid.
|
|
*/
|
|
|
|
static void ecl_grav_survey_assert_RPORV( const ecl_grav_survey_type * survey , const ecl_file_type * init_file ) {
|
|
const ecl::ecl_grid_cache& grid_cache = *(survey->grid_cache);
|
|
int active_size = grid_cache.size();
|
|
const ecl_kw_type * init_porv_kw = ecl_file_iget_named_kw( init_file , PORV_KW , 0);
|
|
int check_points = 100;
|
|
int check_nr = 0;
|
|
const std::vector<int>& global_index = grid_cache.global_index();
|
|
|
|
while (check_nr < check_points) {
|
|
int active_index = rand() % active_size;
|
|
|
|
double init_porv = ecl_kw_iget_as_double( init_porv_kw , global_index[active_index] ); /* NB - this uses global indexing. */
|
|
if (init_porv > 0) {
|
|
double rporv = survey->porv[ active_index ];
|
|
double log_pormod = log10( rporv / init_porv );
|
|
|
|
if (fabs( log_pormod ) > 1) {
|
|
/* Detected as error if the effective pore volume multiplier
|
|
is greater than 10 or less than 0.10. */
|
|
fprintf(stderr,"-----------------------------------------------------------------\n");
|
|
fprintf(stderr,"INIT PORV : %g \n",init_porv);
|
|
fprintf(stderr,"RPORV : %g \n",rporv);
|
|
fprintf(stderr,"Hmmm - the RPORV values extracted from the restart file seem to be \n");
|
|
fprintf(stderr,"veeery different from the initial porv value. This might indicate \n");
|
|
fprintf(stderr,"an ECLIPSE bug in the RPORV handling. Try using another ECLIPSE version,\n");
|
|
fprintf(stderr,"or alternatively the PORMOD approach instead\n");
|
|
fprintf(stderr,"-----------------------------------------------------------------\n");
|
|
exit(1);
|
|
}
|
|
check_nr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
There are currently two main methods to add a survey; differentiated by
|
|
how the mass of various phases in each cell is calculated:
|
|
|
|
1. We can calculate the mass of each phase from the relation:
|
|
|
|
mass = saturation * pore_volume * mass_density.
|
|
|
|
This method requires access to the instantaneous pore volume. This
|
|
can be accessed in two different ways, based either on the RPORV
|
|
keyword or the PORV_MOD keyword. This functionality is available
|
|
through the ecl_grav_survey_alloc_RPORV() and
|
|
ecl_grav_survey_alloc_PORMOD() functions.
|
|
|
|
|
|
2. The mass of each phase can be calculated based on the fluid in place
|
|
values (volume of phase when the matter is brought to standard
|
|
conditions), i.e. the FIPGAS, FIPWAT and FIPOIL keywords, and the
|
|
corresponding densities at surface conditions. This functionality is
|
|
implemented with the ecl_grav_survey_alloc_FIP() function.
|
|
|
|
Observe that use of the FIP based method requires densities entered
|
|
with ecl_grav_new_std_density()/ecl_grav_add_std_density() prior to
|
|
adding the actual survey.
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
Allocate one survey based on using the RPORV keyword from the
|
|
restart file to calculate the instantaneous pore volume in each
|
|
cell.
|
|
|
|
Unfortunately different versions of ECLIPSE have showed a wide
|
|
range of bugs related to the RPORV keyword, including:
|
|
|
|
- Using the pressure values instead of pore volumes - this will be
|
|
cached by the ecl_grav_survey_assert_RPORV() function.
|
|
|
|
- Ignoring the dynamic pore volume changes, and just using
|
|
RPORV == INIT PORV.
|
|
*/
|
|
|
|
|
|
static ecl_grav_survey_type * ecl_grav_survey_alloc_RPORV(ecl_grav_type * ecl_grav ,
|
|
const ecl_file_view_type * restart_file ,
|
|
const char * name ) {
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_empty( ecl_grav , name , GRAV_CALC_RPORV);
|
|
if (ecl_file_view_has_kw( restart_file , RPORV_KW)) {
|
|
ecl_kw_type * rporv_kw = ecl_file_view_iget_named_kw( restart_file , RPORV_KW , 0);
|
|
int iactive;
|
|
for (iactive = 0; iactive < ecl_kw_get_size( rporv_kw ); iactive++)
|
|
survey->porv[ iactive ] = ecl_kw_iget_as_double( rporv_kw , iactive );
|
|
} else
|
|
util_abort("%s: restart file did not contain %s keyword??\n",__func__ , RPORV_KW);
|
|
|
|
{
|
|
const ecl_file_type * init_file = ecl_grav->init_file;
|
|
ecl_grav_survey_assert_RPORV( survey , init_file );
|
|
ecl_grav_survey_add_phases( ecl_grav , survey , restart_file , GRAV_CALC_RPORV);
|
|
}
|
|
return survey;
|
|
}
|
|
|
|
|
|
|
|
static ecl_grav_survey_type * ecl_grav_survey_alloc_PORMOD(ecl_grav_type * ecl_grav ,
|
|
const ecl_file_view_type * restart_file ,
|
|
const char * name ) {
|
|
ecl::ecl_grid_cache& grid_cache = *(ecl_grav->grid_cache);
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_empty( ecl_grav , name , GRAV_CALC_PORMOD);
|
|
ecl_kw_type * init_porv_kw = ecl_file_iget_named_kw( ecl_grav->init_file , PORV_KW , 0 ); /* Global indexing */
|
|
ecl_kw_type * pormod_kw = ecl_file_view_iget_named_kw( restart_file , PORMOD_KW , 0 ); /* Active indexing */
|
|
const int size = grid_cache.size();
|
|
const auto& global_index = grid_cache.global_index();
|
|
int active_index;
|
|
|
|
for (active_index = 0; active_index < size; active_index++)
|
|
survey->porv[ active_index ] = ecl_kw_iget_float( pormod_kw , active_index ) * ecl_kw_iget_float( init_porv_kw , global_index[active_index] );
|
|
|
|
ecl_grav_survey_add_phases( ecl_grav , survey , restart_file , GRAV_CALC_PORMOD);
|
|
|
|
return survey;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Use of the ecl_grav_survey_alloc_FIP() function requires that the densities
|
|
have been added for all phases with the ecl_grav_new_std_density() and
|
|
possibly also the ecl_grav_add_std_density() functions.
|
|
*/
|
|
|
|
static ecl_grav_survey_type * ecl_grav_survey_alloc_FIP(ecl_grav_type * ecl_grav ,
|
|
const ecl_file_view_type * restart_file ,
|
|
const char * name ) {
|
|
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_empty( ecl_grav , name , GRAV_CALC_FIP);
|
|
ecl_grav_survey_add_phases( ecl_grav , survey , restart_file , GRAV_CALC_FIP);
|
|
|
|
return survey;
|
|
}
|
|
|
|
|
|
|
|
static ecl_grav_survey_type * ecl_grav_survey_alloc_RFIP(ecl_grav_type * ecl_grav ,
|
|
const ecl_file_view_type * restart_file ,
|
|
const char * name ) {
|
|
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_empty( ecl_grav , name , GRAV_CALC_RFIP);
|
|
ecl_grav_survey_add_phases( ecl_grav , survey , restart_file , GRAV_CALC_RFIP);
|
|
|
|
return survey;
|
|
}
|
|
|
|
|
|
|
|
static void ecl_grav_survey_free( ecl_grav_survey_type * grav_survey ) {
|
|
free( grav_survey->name );
|
|
free( grav_survey->porv );
|
|
for (auto * phase : grav_survey->phase_list)
|
|
ecl_grav_phase_free( phase );
|
|
|
|
delete grav_survey;
|
|
}
|
|
|
|
|
|
|
|
|
|
static double ecl_grav_survey_eval( const ecl_grav_survey_type * base_survey,
|
|
const ecl_grav_survey_type * monitor_survey ,
|
|
ecl_region_type * region ,
|
|
double utm_x , double utm_y , double depth, int phase_mask) {
|
|
double deltag = 0;
|
|
for (std::size_t phase_nr = 0; phase_nr < base_survey->phase_list.size(); phase_nr++) {
|
|
ecl_grav_phase_type * base_phase = base_survey->phase_list[phase_nr];
|
|
if (base_phase->phase & phase_mask) {
|
|
if (monitor_survey != NULL) {
|
|
const ecl_grav_phase_type * monitor_phase = monitor_survey->phase_list[phase_nr];
|
|
deltag += ecl_grav_phase_eval( base_phase , monitor_phase , region , utm_x , utm_y , depth );
|
|
} else
|
|
deltag += ecl_grav_phase_eval( base_phase , NULL , region , utm_x , utm_y , depth );
|
|
}
|
|
}
|
|
return deltag;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/**
|
|
The grid instance is only used during the construction phase. The
|
|
@init_file object is used by the ecl_grav_add_survey_XXX()
|
|
functions; and calling scope must NOT destroy this object before
|
|
all surveys have been added.
|
|
*/
|
|
|
|
ecl_grav_type * ecl_grav_alloc( const ecl_grid_type * ecl_grid, const ecl_file_type * init_file) {
|
|
ecl_grav_type * ecl_grav = new ecl_grav_type();
|
|
|
|
ecl_grav->init_file = init_file;
|
|
ecl_grav->grid_cache = new ecl::ecl_grid_cache(ecl_grid);
|
|
ecl_grav->aquifer_cell = ecl_grav_common_alloc_aquifer_cell( *(ecl_grav->grid_cache) , ecl_grav->init_file );
|
|
|
|
return ecl_grav;
|
|
}
|
|
|
|
|
|
|
|
static void ecl_grav_add_survey__( ecl_grav_type * grav , const char * name , ecl_grav_survey_type * survey) {
|
|
grav->surveys[name] = survey;
|
|
}
|
|
|
|
|
|
ecl_grav_survey_type * ecl_grav_add_survey_RPORV( ecl_grav_type * grav , const char * name , const ecl_file_view_type * restart_file ) {
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_RPORV( grav , restart_file , name );
|
|
ecl_grav_add_survey__( grav , name , survey );
|
|
return survey;
|
|
}
|
|
|
|
|
|
ecl_grav_survey_type * ecl_grav_add_survey_FIP( ecl_grav_type * grav , const char * name , const ecl_file_view_type * restart_file ) {
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_FIP( grav , restart_file , name );
|
|
ecl_grav_add_survey__( grav , name , survey );
|
|
return survey;
|
|
}
|
|
|
|
ecl_grav_survey_type * ecl_grav_add_survey_RFIP( ecl_grav_type * grav , const char * name , const ecl_file_view_type * restart_file ) {
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_RFIP( grav , restart_file , name );
|
|
ecl_grav_add_survey__( grav , name , survey );
|
|
return survey;
|
|
}
|
|
|
|
|
|
ecl_grav_survey_type * ecl_grav_add_survey_PORMOD( ecl_grav_type * grav , const char * name , const ecl_file_view_type * restart_file ) {
|
|
ecl_grav_survey_type * survey = ecl_grav_survey_alloc_PORMOD( grav , restart_file , name );
|
|
ecl_grav_add_survey__( grav , name , survey );
|
|
return survey;
|
|
}
|
|
|
|
|
|
static ecl_grav_survey_type * ecl_grav_get_survey( const ecl_grav_type * grav , const char * name) {
|
|
if (name == NULL)
|
|
return NULL; // Calling scope must determine if this is OK?
|
|
else {
|
|
if (grav->surveys.count(name) > 0)
|
|
return grav->surveys.at(name);
|
|
else {
|
|
fprintf(stderr,"Survey name:%s not registered. Available surveys are: \n\n " , name);
|
|
|
|
for (const auto& survey_pair : grav->surveys)
|
|
fprintf(stderr,"%s ",survey_pair.first.c_str());
|
|
|
|
fprintf(stderr,"\n\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
double ecl_grav_eval( const ecl_grav_type * grav , const char * base, const char * monitor , ecl_region_type * region , double utm_x, double utm_y , double depth, int phase_mask) {
|
|
ecl_grav_survey_type * base_survey = ecl_grav_get_survey( grav , base );
|
|
ecl_grav_survey_type * monitor_survey = ecl_grav_get_survey( grav , monitor );
|
|
|
|
return ecl_grav_survey_eval( base_survey , monitor_survey , region , utm_x , utm_y , depth , phase_mask);
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* The functions ecl_grav_new_std_density() and ecl_grav_add_std_density() are
|
|
used to "install" standard conditions densities for the various phases
|
|
involved. These functions must be called prior to calling
|
|
ecl_grav_add_survey_FIP() - failure to do so will lead to hard failure.
|
|
*/
|
|
|
|
|
|
/**
|
|
The function ecl_grav_new_std_density() is used to add a default density for
|
|
a new phase.
|
|
*/
|
|
|
|
void ecl_grav_new_std_density( ecl_grav_type * grav , ecl_phase_enum phase , double default_density) {
|
|
const char * phase_key = ecl_util_get_phase_name( phase );
|
|
grav->default_density[std::string(phase_key)] = default_density;
|
|
}
|
|
|
|
/**
|
|
In cases with many PVT regions it is possible to install per PVT
|
|
region densities. The ecl_grav_new_std_density() must be called
|
|
first to install a default density for the phase, and then this
|
|
function can be called afterwards to install density for a
|
|
particular PVT region. In the example below we set the default gas
|
|
density to 0.75, but in PVT regions 2 and 7 the density is
|
|
different:
|
|
|
|
ecl_grav_new_std_density( grav , ECL_GAS_PHASE , 0.75 );
|
|
ecl_grav_add_std_density( grav , ECL_GAS_PHASE , 2 , 0.70 );
|
|
ecl_grav_add_std_density( grav , ECL_GAS_PHASE , 7 , 0.80 );
|
|
*/
|
|
|
|
|
|
void ecl_grav_add_std_density( ecl_grav_type * grav , ecl_phase_enum phase , int pvtnum , double density) {
|
|
std::vector<double>& std_density = grav->std_density[ std::string(ecl_util_get_phase_name(phase)) ];
|
|
if (std_density.size() <= static_cast<std::size_t>(pvtnum))
|
|
std_density.resize(pvtnum + 1, grav->default_density[ std::string(ecl_util_get_phase_name(phase)) ]);
|
|
std_density[pvtnum] = density;
|
|
}
|
|
|
|
|
|
|
|
void ecl_grav_free( ecl_grav_type * ecl_grav ) {
|
|
delete ecl_grav->grid_cache;
|
|
free( ecl_grav->aquifer_cell );
|
|
|
|
for (const auto& survey_pair : ecl_grav->surveys)
|
|
ecl_grav_survey_free( survey_pair.second );
|
|
|
|
delete ecl_grav;
|
|
}
|