Files
ResInsight/ThirdParty/Ert/lib/ecl/well_ts.cpp
Magne Sjaastad 04091ad77d #4266 Update libecl
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020

Excluded multibuild folder, as this caused git issues
2019-05-09 08:40:32 +02:00

321 lines
9.0 KiB
C++

/*
Copyright (C) 2011 Equinor ASA, Norway.
The file 'well_ts.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.
*/
/**
The wells can typically change configuration during a simulation,
new completions can be added, the well can be shut for a period, it
can change purpose from injector to producer and so on.
The well_ts datastructure is used to hold the complete history of
one well; for each new report step a new well_state object is added
to to the well_ts structure. Afterwards you can use the well_ts
object to query for the well_state at different times.
An example timeline for one well can look like this:
well_state0 well_state1 well_state2 well_state3
[-------------x---------------x-------------x--------------]
0030 0060 0070 0090
The well in this example is added at report step 30; after that we
have well_state information from each of the reported report steps
60,70 and 90. If we query the well_ts object for well state
information at a particular report step the well_ts structure will
return the well_state info at the time at or immediately before the
query time:
o If we ask for the well state at step 30 we will get the
well_state0 object; if we ask for the well state at step 75 we
will get the well_state2 object.
o If we ask for the well_state before the well has appeared the
first time we will get NULL.
o The restart files have no meta information of when the
simulation ended, so there is no way to detect it if you ask
for the well state way beyond the end of the simulation. If you
ask for the well state at report step 100 (i.e. beyond the end
of the simulation) you will just get the well_state3 object.
The time direction can be specified by both report step and
simulation time - your choice.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string>
#include <vector>
#include <algorithm>
#include <ert/util/util.h>
#include <ert/util/vector.hpp>
#include <ert/ecl_well/well_ts.hpp>
#include <ert/ecl_well/well_const.hpp>
#include <ert/ecl_well/well_state.hpp>
#define WELL_TS_TYPE_ID 6613005
#define WELL_NODE_TYPE_ID 1114652
typedef struct {
UTIL_TYPE_ID_DECLARATION;
int report_nr;
time_t sim_time;
well_state_type * well_state; // The well_node instance owns the well_state instance.
} well_node_type;
struct well_ts_struct {
UTIL_TYPE_ID_DECLARATION;
std::string well_name;
std::vector<well_node_type*> ts;
};
/******************************************************************/
static well_node_type * well_node_alloc( well_state_type * well_state) {
well_node_type * node = new well_node_type();
UTIL_TYPE_ID_INIT( node , WELL_NODE_TYPE_ID );
node->report_nr = well_state_get_report_nr( well_state );
node->sim_time = well_state_get_sim_time( well_state );
node->well_state = well_state;
return node;
}
static void well_node_free( well_node_type * well_node ) {
well_state_free( well_node->well_state );
delete well_node;
}
static bool well_node_time_lt( const well_node_type * node1 , const well_node_type * node2) {
return (node1->sim_time < node2->sim_time);
}
/*****************************************************************/
static well_ts_type * well_ts_alloc_empty( ) {
well_ts_type * well_ts = new well_ts_type();
UTIL_TYPE_ID_INIT( well_ts , WELL_TS_TYPE_ID );
return well_ts;
}
static UTIL_SAFE_CAST_FUNCTION( well_ts , WELL_TS_TYPE_ID )
well_ts_type * well_ts_alloc( const char * well_name ) {
well_ts_type * well_ts = well_ts_alloc_empty();
well_ts->well_name = well_name;
return well_ts;
}
const char * well_ts_get_name( const well_ts_type * well_ts) {
return well_ts->well_name.c_str();
}
static int well_ts_get_index__( const well_ts_type * well_ts , int report_step , time_t sim_time , bool use_report) {
const int size = well_ts->ts.size();
if (size == 0)
return 0;
else {
const well_node_type * first_node = well_ts->ts[0];
const well_node_type * last_node = well_ts->ts.back();
if (use_report) {
if (report_step < first_node->report_nr)
return -1; // Before the start
if (report_step >= last_node->report_nr)
return size - 1; // After end
} else {
if (sim_time < first_node->sim_time)
return -1; // Before the start
if (sim_time >= last_node->sim_time)
return size - 1; // After end
}
// Binary search
{
int lower_index = 0;
int upper_index = size - 1;
while (true) {
int center_index = (lower_index + upper_index) / 2;
const well_node_type * center_node = well_ts->ts[center_index];
double cmp;
if (use_report)
cmp = center_node->report_nr - report_step;
else
cmp = difftime( center_node->sim_time , sim_time );
if (cmp > 0) {
if ((center_index - lower_index) == 1) // We found an interval of length 1
return lower_index;
else
upper_index = center_index;
} else {
if ((upper_index - center_index) == 1) // We found an interval of length 1
return center_index;
else
lower_index = center_index;
}
}
}
}
}
/*
Index: 0 1 2
|----------------|-----------------|
Value: 0 50 76
*/
static int well_ts_get_index( const well_ts_type * well_ts , int report_step , time_t sim_time , bool use_report) {
int index = well_ts_get_index__( well_ts , report_step , sim_time , use_report );
// Inline check that the index is correct
{
bool OK = true;
const well_node_type * node = well_ts->ts[index];
well_node_type * next_node = NULL;
if (index < (static_cast<int>(well_ts->ts.size()) - 1) )
next_node = well_ts->ts[index + 1];
if (use_report) {
if (index < 0) {
if (report_step >= node->report_nr)
OK = false;
} else {
if (report_step < node->report_nr)
OK = false;
else {
if (next_node != NULL)
if (next_node->report_nr <= report_step)
OK = false;
}
}
} else {
if (index < 0) {
if (sim_time >= node->sim_time)
OK = false;
} else {
if (sim_time < node->sim_time)
OK = false;
else {
if (next_node != NULL)
if (next_node->sim_time <= sim_time)
OK = false;
}
}
if (!OK)
util_abort("%s: holy rider - internal error \n",__func__);
}
}
return index;
}
void well_ts_add_well( well_ts_type * well_ts , well_state_type * well_state ) {
well_node_type * new_node = well_node_alloc( well_state );
well_ts->ts.push_back( new_node );
if (well_ts->ts.size() > 1) {
const well_node_type * last_node = well_ts->ts.back();
if (new_node->sim_time < last_node->sim_time)
// The new node is chronologically before the previous node;
// i.e. we must sort the nodes in time. This should probably happen
// quite seldom:
std::sort( well_ts->ts.begin(), well_ts->ts.end(), well_node_time_lt );
}
}
void well_ts_free( well_ts_type * well_ts ){
for (size_t i = 0; i < well_ts->ts.size(); i++)
well_node_free( well_ts->ts[i] );
delete well_ts;
}
void well_ts_free__( void * arg ) {
well_ts_type * well_ts = well_ts_safe_cast( arg );
well_ts_free( well_ts );
}
int well_ts_get_size( const well_ts_type * well_ts) {
return well_ts->ts.size();
}
well_state_type * well_ts_get_first_state( const well_ts_type * well_ts) {
return well_ts_iget_state( well_ts , 0 );
}
well_state_type * well_ts_get_last_state( const well_ts_type * well_ts) {
return well_ts_iget_state( well_ts , well_ts->ts.size() - 1);
}
well_state_type * well_ts_iget_state( const well_ts_type * well_ts , int index) {
well_node_type * node = well_ts->ts[index];
return node->well_state;
}
well_state_type * well_ts_get_state_from_report( const well_ts_type * well_ts , int report_step) {
int index = well_ts_get_index( well_ts , report_step , -1 , true );
if (index < 0)
return NULL;
else
return well_ts_iget_state( well_ts , index );
}
well_state_type * well_ts_get_state_from_sim_time( const well_ts_type * well_ts , time_t sim_time) {
int index = well_ts_get_index( well_ts , -1 , sim_time , false );
if (index < 0)
return NULL;
else
return well_ts_iget_state( well_ts , index );
}