mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-30 11:06:55 -06:00
70a6a2ebf8
The average well block pressure is used instead of the well cell pressure when the well properties are evaluated. Temperature, rs, rv, phase conditions are still well cells values. Perforation pressures are stored in the well state
213 lines
8.8 KiB
C++
213 lines
8.8 KiB
C++
/*
|
|
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
|
|
|
This file is part of the Open Porous Media project (OPM).
|
|
|
|
OPM 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.
|
|
|
|
OPM 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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
|
#define OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
|
|
|
|
|
#include <opm/core/wells.h>
|
|
#include <opm/core/well_controls.h>
|
|
#include <opm/core/simulator/WellState.hpp>
|
|
#include <opm/core/utility/ErrorMacros.hpp>
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <map>
|
|
#include <algorithm>
|
|
#include <array>
|
|
|
|
namespace Opm
|
|
{
|
|
|
|
/// The state of a set of wells, tailored for use by the fully
|
|
/// implicit blackoil simulator.
|
|
class WellStateFullyImplicitBlackoil
|
|
: public WellState
|
|
{
|
|
typedef WellState BaseType;
|
|
public:
|
|
typedef std::array< int, 3 > mapentry_t;
|
|
typedef std::map< std::string, mapentry_t > WellMapType;
|
|
|
|
using BaseType :: wellRates;
|
|
using BaseType :: bhp;
|
|
using BaseType :: perfPress;
|
|
|
|
/// Allocate and initialize if wells is non-null. Also tries
|
|
/// to give useful initial values to the bhp(), wellRates()
|
|
/// and perfPhaseRates() fields, depending on controls
|
|
template <class State, class PrevState>
|
|
void init(const Wells* wells, const State& state, const PrevState& prevState)
|
|
{
|
|
// clear old name mapping
|
|
wellMap_.clear();
|
|
|
|
if (wells == 0) {
|
|
return;
|
|
}
|
|
|
|
const int nw = wells->number_of_wells;
|
|
if( nw == 0 ) return ;
|
|
|
|
// We use the WellState::init() function to do bhp and well rates init.
|
|
// The alternative would be to copy that function wholesale.
|
|
BaseType :: init(wells, state);
|
|
|
|
// Initialize perfphaserates_, which must be done here.
|
|
const int np = wells->number_of_phases;
|
|
const int nperf = wells->well_connpos[nw];
|
|
// Ensure that we start out with zero rates by default.
|
|
perfphaserates_.clear();
|
|
perfphaserates_.resize(nperf * np, 0.0);
|
|
for (int w = 0; w < nw; ++w) {
|
|
assert((wells->type[w] == INJECTOR) || (wells->type[w] == PRODUCER));
|
|
const WellControls* ctrl = wells->ctrls[w];
|
|
std::string name( wells->name[ w ] );
|
|
assert( name.size() > 0 );
|
|
mapentry_t& wellMapEntry = wellMap_[name];
|
|
wellMapEntry[ 0 ] = w;
|
|
wellMapEntry[ 1 ] = wells->well_connpos[w];
|
|
// also store the number of perforations in this well
|
|
const int num_perf_this_well = wells->well_connpos[w + 1] - wells->well_connpos[w];
|
|
wellMapEntry[ 2 ] = num_perf_this_well;
|
|
|
|
if (well_controls_well_is_stopped(ctrl)) {
|
|
// Shut well: perfphaserates_ are all zero.
|
|
} else {
|
|
// Open well: Initialize perfphaserates_ to well
|
|
// rates divided by the number of perforations.
|
|
for (int perf = wells->well_connpos[w]; perf < wells->well_connpos[w + 1]; ++perf) {
|
|
for (int p = 0; p < np; ++p) {
|
|
perfphaserates_[np*perf + p] = wellRates()[np*w + p] / double(num_perf_this_well);
|
|
}
|
|
perfPress()[perf] = state.pressure()[wells->well_cells[perf]];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize current_controls_.
|
|
// The controls set in the Wells object are treated as defaults,
|
|
// and also used for initial values.
|
|
current_controls_.resize(nw);
|
|
for (int w = 0; w < nw; ++w) {
|
|
current_controls_[w] = well_controls_get_current(wells->ctrls[w]);
|
|
}
|
|
|
|
// intialize wells that have been there before
|
|
// order may change so the mapping is based on the well name
|
|
if( ! prevState.wellMap().empty() )
|
|
{
|
|
typedef typename WellMapType :: const_iterator const_iterator;
|
|
const_iterator end = prevState.wellMap().end();
|
|
for (int w = 0; w < nw; ++w) {
|
|
std::string name( wells->name[ w ] );
|
|
const_iterator it = prevState.wellMap().find( name );
|
|
if( it != end )
|
|
{
|
|
const int oldIndex = (*it).second[ 0 ];
|
|
const int newIndex = w;
|
|
|
|
// bhp
|
|
bhp()[ newIndex ] = prevState.bhp()[ oldIndex ];
|
|
|
|
// wellrates
|
|
for( int i=0, idx=newIndex*np, oldidx=oldIndex*np; i<np; ++i, ++idx, ++oldidx )
|
|
{
|
|
wellRates()[ idx ] = prevState.wellRates()[ oldidx ];
|
|
}
|
|
|
|
// perfPhaseRates
|
|
int oldPerf_idx = (*it).second[ 1 ];
|
|
const int num_perf_old_well = (*it).second[ 2 ];
|
|
const int num_perf_this_well = wells->well_connpos[newIndex + 1] - wells->well_connpos[newIndex];
|
|
// copy perforation rates when the number of perforations is equal,
|
|
// otherwise initialize perfphaserates to well rates divided by the number of perforations.
|
|
if( num_perf_old_well == num_perf_this_well )
|
|
{
|
|
int oldPerf = oldPerf_idx *np;
|
|
for (int perf = wells->well_connpos[ newIndex ]*np;
|
|
perf < wells->well_connpos[ newIndex + 1]*np; ++perf, ++oldPerf )
|
|
{
|
|
perfPhaseRates()[ perf ] = prevState.perfPhaseRates()[ oldPerf ];
|
|
}
|
|
} else {
|
|
for (int perf = wells->well_connpos[newIndex]; perf < wells->well_connpos[newIndex + 1]; ++perf) {
|
|
for (int p = 0; p < np; ++p) {
|
|
perfPhaseRates()[np*perf + p] = wellRates()[np*newIndex + p] / double(num_perf_this_well);
|
|
}
|
|
}
|
|
}
|
|
// perfPressures
|
|
if( num_perf_old_well == num_perf_this_well )
|
|
{
|
|
for (int perf = wells->well_connpos[ newIndex ];
|
|
perf < wells->well_connpos[ newIndex + 1]; ++perf, ++oldPerf_idx )
|
|
{
|
|
perfPress()[ perf ] = prevState.perfPress()[ oldPerf_idx ];
|
|
}
|
|
}
|
|
|
|
// currentControls
|
|
const int old_control_index = prevState.currentControls()[ oldIndex ];
|
|
if (old_control_index < well_controls_get_num(wells->ctrls[w])) {
|
|
// If the set of controls have changed, this may not be identical
|
|
// to the last control, but it must be a valid control.
|
|
currentControls()[ newIndex ] = old_control_index;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// One rate per phase and well connection.
|
|
std::vector<double>& perfPhaseRates() { return perfphaserates_; }
|
|
const std::vector<double>& perfPhaseRates() const { return perfphaserates_; }
|
|
|
|
/// One current control per well.
|
|
std::vector<int>& currentControls() { return current_controls_; }
|
|
const std::vector<int>& currentControls() const { return current_controls_; }
|
|
|
|
/// The number of wells present.
|
|
int numWells() const
|
|
{
|
|
return bhp().size();
|
|
}
|
|
|
|
/// The number of phases present.
|
|
int numPhases() const
|
|
{
|
|
return wellRates().size() / numWells();
|
|
}
|
|
|
|
const WellMapType& wellMap() const { return wellMap_; }
|
|
WellMapType& wellMap() { return wellMap_; }
|
|
|
|
private:
|
|
std::vector<double> perfphaserates_;
|
|
std::vector<int> current_controls_;
|
|
WellMapType wellMap_;
|
|
};
|
|
|
|
} // namespace Opm
|
|
|
|
|
|
#endif // OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|