Prepare for extended models.

Let the code loop over number of components instead of phase
Pass TypeTag as template parameter instead of all the properties.
This commit is contained in:
Tor Harald Sandve 2017-05-03 13:34:15 +02:00
parent 4aa9dc5375
commit 6084721812
10 changed files with 443 additions and 447 deletions

View File

@ -118,7 +118,7 @@ namespace Opm {
typedef BlackoilModelParameters ModelParameters; typedef BlackoilModelParameters ModelParameters;
typedef typename TTAG(EclFlowProblem) TypeTag; typedef typename TTAG(EclFlowProblem) TypeTag;
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator ; typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid;
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector ; typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector ;
@ -129,9 +129,9 @@ namespace Opm {
typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams;
typedef double Scalar; typedef double Scalar;
static const int blocksize = 3; static const int numEq = BlackoilIndices::numEq;
typedef Dune::FieldVector<Scalar, blocksize > VectorBlockType; typedef Dune::FieldVector<Scalar, numEq > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, blocksize, blocksize > MatrixBlockType; typedef Dune::FieldMatrix<Scalar, numEq, numEq > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat; typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector; typedef Dune::BlockVector<VectorBlockType> BVector;
@ -162,7 +162,7 @@ namespace Opm {
const ModelParameters& param, const ModelParameters& param,
const BlackoilPropsAdFromDeck& fluid, const BlackoilPropsAdFromDeck& fluid,
const DerivedGeology& geo , const DerivedGeology& geo ,
const StandardWellsDense<FluidSystem, BlackoilIndices, ElementContext, MaterialLaw>& well_model, const StandardWellsDense<TypeTag>& well_model,
const NewtonIterationBlackoilInterface& linsolver, const NewtonIterationBlackoilInterface& linsolver,
const bool terminal_output) const bool terminal_output)
: ebosSimulator_(ebosSimulator) : ebosSimulator_(ebosSimulator)
@ -443,7 +443,7 @@ namespace Opm {
{ {
const int nc = Opm::AutoDiffGrid::numCells(grid_); const int nc = Opm::AutoDiffGrid::numCells(grid_);
const int nw = numWells(); const int nw = numWells();
return numPhases() * (nc + nw); return numComponents() * (nc + nw);
} }
/// Number of linear iterations used in last call to solveJacobianSystem(). /// Number of linear iterations used in last call to solveJacobianSystem().
@ -766,7 +766,7 @@ namespace Opm {
template <class CollectiveCommunication> template <class CollectiveCommunication>
double convergenceReduction(const CollectiveCommunication& comm, double convergenceReduction(const CollectiveCommunication& comm,
const long int ncGlobal, const long int ncGlobal,
const int np, const int numComp,
const std::vector< std::vector< Scalar > >& B, const std::vector< std::vector< Scalar > >& B,
const std::vector< std::vector< Scalar > >& tempV, const std::vector< std::vector< Scalar > >& tempV,
const std::vector< std::vector< Scalar > >& R, const std::vector< std::vector< Scalar > >& R,
@ -777,14 +777,14 @@ namespace Opm {
std::vector< Scalar >& B_avg, std::vector< Scalar >& B_avg,
std::vector< Scalar >& maxNormWell ) std::vector< Scalar >& maxNormWell )
{ {
const int nw = residual_well.size() / np; const int nw = residual_well.size() / numComp;
assert(nw * np == int(residual_well.size())); assert(nw * numComp == int(residual_well.size()));
// Do the global reductions // Do the global reductions
B_avg.resize(np); B_avg.resize(numComp);
maxCoeff.resize(np); maxCoeff.resize(numComp);
R_sum.resize(np); R_sum.resize(numComp);
maxNormWell.resize(np); maxNormWell.resize(numComp);
const std::vector<double>* mask = nullptr; const std::vector<double>* mask = nullptr;
@ -801,20 +801,20 @@ namespace Opm {
#endif #endif
// computation // computation
for ( int idx = 0; idx < np; ++idx ) for ( int compIdx = 0; compIdx < numComp; ++compIdx )
{ {
B_avg[idx] = std::accumulate( B[ idx ].begin(), B[ idx ].end(), B_avg[compIdx] = std::accumulate( B[ compIdx ].begin(), B[ compIdx ].end(),
0.0 ) / double(ncGlobal); 0.0 ) / double(ncGlobal);
R_sum[idx] = std::accumulate( R[ idx ].begin(), R[ idx ].end(), R_sum[compIdx] = std::accumulate( R[ compIdx ].begin(), R[ compIdx ].end(),
0.0 ); 0.0 );
maxCoeff[idx] = *(std::max_element( tempV[ idx ].begin(), tempV[ idx ].end() )); maxCoeff[compIdx] = *(std::max_element( tempV[ compIdx ].begin(), tempV[ compIdx ].end() ));
assert(np >= np); assert(numComp >= numComp);
if (idx < np) { if (compIdx < numComp) {
maxNormWell[idx] = 0.0; maxNormWell[compIdx] = 0.0;
for ( int w = 0; w < nw; ++w ) { for ( int w = 0; w < nw; ++w ) {
maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_well[nw*idx + w])); maxNormWell[compIdx] = std::max(maxNormWell[compIdx], std::abs(residual_well[nw*compIdx + w]));
} }
} }
} }
@ -829,12 +829,12 @@ namespace Opm {
std::vector< Scalar > maxBuffer; std::vector< Scalar > maxBuffer;
sumBuffer.reserve( B_avg.size() + R_sum.size() + 1 ); sumBuffer.reserve( B_avg.size() + R_sum.size() + 1 );
maxBuffer.reserve( maxCoeff.size() + maxNormWell.size() ); maxBuffer.reserve( maxCoeff.size() + maxNormWell.size() );
for( int idx = 0; idx < np; ++idx ) for( int compIdx = 0; compIdx < numComp; ++compIdx )
{ {
sumBuffer.push_back( B_avg[ idx ] ); sumBuffer.push_back( B_avg[ compIdx ] );
sumBuffer.push_back( R_sum[ idx ] ); sumBuffer.push_back( R_sum[ compIdx ] );
maxBuffer.push_back( maxCoeff[ idx ] ); maxBuffer.push_back( maxCoeff[ compIdx ] );
maxBuffer.push_back( maxNormWell[ idx ] ); maxBuffer.push_back( maxNormWell[ compIdx ] );
} }
// Compute total pore volume // Compute total pore volume
@ -847,14 +847,14 @@ namespace Opm {
comm.max( maxBuffer.data(), maxBuffer.size() ); comm.max( maxBuffer.data(), maxBuffer.size() );
// restore values to local variables // restore values to local variables
for( int idx = 0, buffIdx = 0; idx < np; ++idx, ++buffIdx ) for( int compIdx = 0, buffIdx = 0; compIdx < numComp; ++compIdx, ++buffIdx )
{ {
B_avg[ idx ] = sumBuffer[ buffIdx ]; B_avg[ compIdx ] = sumBuffer[ buffIdx ];
maxCoeff[ idx ] = maxBuffer[ buffIdx ]; maxCoeff[ compIdx ] = maxBuffer[ buffIdx ];
++buffIdx; ++buffIdx;
R_sum[ idx ] = sumBuffer[ buffIdx ]; R_sum[ compIdx ] = sumBuffer[ buffIdx ];
maxNormWell[ idx ] = maxBuffer[ buffIdx ]; maxNormWell[ compIdx ] = maxBuffer[ buffIdx ];
} }
// restore global pore volume // restore global pore volume
@ -880,23 +880,23 @@ namespace Opm {
const double tol_wells = param_.tolerance_wells_; const double tol_wells = param_.tolerance_wells_;
const int nc = Opm::AutoDiffGrid::numCells(grid_); const int nc = Opm::AutoDiffGrid::numCells(grid_);
const int np = numPhases();
const auto& pv = geo_.poreVolume(); const auto& pv = geo_.poreVolume();
Vector R_sum(np); const int numComp = numComponents();
Vector B_avg(np); Vector R_sum(numComp);
Vector maxCoeff(np); Vector B_avg(numComp);
Vector maxNormWell(np); Vector maxCoeff(numComp);
Vector maxNormWell(numComp);
// As we will not initialize values in the following arrays // As we will not initialize values in the following arrays
// for the non-interior elements, we have to make sure // for the non-interior elements, we have to make sure
// (at least for tempV) that the values there do not influence // (at least for tempV) that the values there do not influence
// our reduction. // our reduction.
std::vector< Vector > B( np, Vector( nc, 0.0) ); std::vector< Vector > B( numComp, Vector( nc, 0.0) );
//std::vector< Vector > R( np, Vector( nc, 0.0) ) ); //std::vector< Vector > R( numComp, Vector( nc, 0.0) ) );
std::vector< Vector > R2( np, Vector( nc, 0.0 ) ); std::vector< Vector > R2( numComp, Vector( nc, 0.0 ) );
std::vector< Vector > tempV( np, Vector( nc, std::numeric_limits<double>::lowest() ) ); std::vector< Vector > tempV( numComp, Vector( nc, std::numeric_limits<double>::lowest() ) );
const auto& ebosResid = ebosSimulator_.model().linearizer().residual(); const auto& ebosResid = ebosSimulator_.model().linearizer().residual();
@ -915,23 +915,23 @@ namespace Opm {
const auto& intQuants = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); const auto& intQuants = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0);
const auto& fs = intQuants.fluidState(); const auto& fs = intQuants.fluidState();
for ( int idx = 0; idx < np; ++idx ) for ( int compIdx = 0; compIdx < numComp; ++compIdx )
{ {
Vector& R2_idx = R2[ idx ]; Vector& R2_idx = R2[ compIdx ];
Vector& B_idx = B[ idx ]; Vector& B_idx = B[ compIdx ];
const int ebosPhaseIdx = flowPhaseToEbosPhaseIdx(idx); const int ebosPhaseIdx = flowPhaseToEbosPhaseIdx(compIdx);
const int ebosCompIdx = flowPhaseToEbosCompIdx(idx); const int ebosCompIdx = flowPhaseToEbosCompIdx(compIdx);
B_idx [cell_idx] = 1.0 / fs.invB(ebosPhaseIdx).value(); B_idx [cell_idx] = 1.0 / fs.invB(ebosPhaseIdx).value();
R2_idx[cell_idx] = ebosResid[cell_idx][ebosCompIdx]; R2_idx[cell_idx] = ebosResid[cell_idx][ebosCompIdx];
} }
} }
for ( int idx = 0; idx < np; ++idx ) for ( int compIdx = 0; compIdx < numComp; ++compIdx )
{ {
//tempV.col(idx) = R2.col(idx).abs()/pv; //tempV.col(compIdx) = R2.col(compIdx).abs()/pv;
Vector& tempV_idx = tempV[ idx ]; Vector& tempV_idx = tempV[ compIdx ];
Vector& R2_idx = R2[ idx ]; Vector& R2_idx = R2[ compIdx ];
for( int cell_idx = 0; cell_idx < nc; ++cell_idx ) for( int cell_idx = 0; cell_idx < nc; ++cell_idx )
{ {
tempV_idx[ cell_idx ] = std::abs( R2_idx[ cell_idx ] ) / pv[ cell_idx ]; tempV_idx[ cell_idx ] = std::abs( R2_idx[ cell_idx ] ) / pv[ cell_idx ];
@ -941,32 +941,30 @@ namespace Opm {
Vector pv_vector (geo_.poreVolume().data(), geo_.poreVolume().data() + geo_.poreVolume().size()); Vector pv_vector (geo_.poreVolume().data(), geo_.poreVolume().data() + geo_.poreVolume().size());
Vector wellResidual = wellModel().residual(); Vector wellResidual = wellModel().residual();
const double pvSum = convergenceReduction(grid_.comm(), global_nc_, np, const double pvSum = convergenceReduction(grid_.comm(), global_nc_, numComp,
B, tempV, R2, pv_vector, wellResidual, B, tempV, R2, pv_vector, wellResidual,
R_sum, maxCoeff, B_avg, maxNormWell ); R_sum, maxCoeff, B_avg, maxNormWell );
Vector CNV(np); Vector CNV(numComp);
Vector mass_balance_residual(np); Vector mass_balance_residual(numComp);
Vector well_flux_residual(np); Vector well_flux_residual(numComp);
bool converged_MB = true; bool converged_MB = true;
bool converged_CNV = true; bool converged_CNV = true;
bool converged_Well = true; bool converged_Well = true;
// Finish computation // Finish computation
for ( int idx = 0; idx < np; ++idx ) for ( int compIdx = 0; compIdx < numComp; ++compIdx )
{ {
CNV[idx] = B_avg[idx] * dt * maxCoeff[idx]; CNV[compIdx] = B_avg[compIdx] * dt * maxCoeff[compIdx];
mass_balance_residual[idx] = std::abs(B_avg[idx]*R_sum[idx]) * dt / pvSum; mass_balance_residual[compIdx] = std::abs(B_avg[compIdx]*R_sum[compIdx]) * dt / pvSum;
converged_MB = converged_MB && (mass_balance_residual[idx] < tol_mb); converged_MB = converged_MB && (mass_balance_residual[compIdx] < tol_mb);
converged_CNV = converged_CNV && (CNV[idx] < tol_cnv); converged_CNV = converged_CNV && (CNV[compIdx] < tol_cnv);
// Well flux convergence is only for fluid phases, not other materials // Well flux convergence is only for fluid phases, not other materials
// in our current implementation. // in our current implementation.
assert(np >= np); well_flux_residual[compIdx] = B_avg[compIdx] * maxNormWell[compIdx];
if (idx < np) { converged_Well = converged_Well && (well_flux_residual[compIdx] < tol_wells);
well_flux_residual[idx] = B_avg[idx] * maxNormWell[idx];
converged_Well = converged_Well && (well_flux_residual[idx] < tol_wells); residual_norms.push_back(CNV[compIdx]);
}
residual_norms.push_back(CNV[idx]);
} }
const bool converged = converged_MB && converged_CNV && converged_Well; const bool converged = converged_MB && converged_CNV && converged_Well;
@ -977,20 +975,20 @@ namespace Opm {
if (iteration == 0) { if (iteration == 0) {
std::string msg = "Iter"; std::string msg = "Iter";
std::vector< std::string > key( np ); std::vector< std::string > key( numComp );
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) { for (int phaseIdx = 0; phaseIdx < numPhases(); ++phaseIdx) {
const std::string& phaseName = FluidSystem::phaseName(flowPhaseToEbosPhaseIdx(phaseIdx)); const std::string& phaseName = FluidSystem::phaseName(flowPhaseToEbosPhaseIdx(phaseIdx));
key[ phaseIdx ] = std::toupper( phaseName.front() ); key[ phaseIdx ] = std::toupper( phaseName.front() );
} }
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
msg += " MB(" + key[ phaseIdx ] + ") "; msg += " MB(" + key[ compIdx ] + ") ";
} }
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
msg += " CNV(" + key[ phaseIdx ] + ") "; msg += " CNV(" + key[ compIdx ] + ") ";
} }
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
msg += " W-FLUX(" + key[ phaseIdx ] + ")"; msg += " W-FLUX(" + key[ compIdx ] + ")";
} }
OpmLog::note(msg); OpmLog::note(msg);
} }
@ -998,31 +996,31 @@ namespace Opm {
const std::streamsize oprec = ss.precision(3); const std::streamsize oprec = ss.precision(3);
const std::ios::fmtflags oflags = ss.setf(std::ios::scientific); const std::ios::fmtflags oflags = ss.setf(std::ios::scientific);
ss << std::setw(4) << iteration; ss << std::setw(4) << iteration;
for (int idx = 0; idx < np; ++idx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
ss << std::setw(11) << mass_balance_residual[idx]; ss << std::setw(11) << mass_balance_residual[compIdx];
} }
for (int idx = 0; idx < np; ++idx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
ss << std::setw(11) << CNV[idx]; ss << std::setw(11) << CNV[compIdx];
} }
for (int idx = 0; idx < np; ++idx) { for (int compIdx = 0; compIdx < numComp; ++compIdx) {
ss << std::setw(11) << well_flux_residual[idx]; ss << std::setw(11) << well_flux_residual[compIdx];
} }
ss.precision(oprec); ss.precision(oprec);
ss.flags(oflags); ss.flags(oflags);
OpmLog::note(ss.str()); OpmLog::note(ss.str());
} }
for (int phaseIdx = 0; phaseIdx < np; ++phaseIdx) { for (int phaseIdx = 0; phaseIdx < numPhases(); ++phaseIdx) {
const auto& phaseName = FluidSystem::phaseName(flowPhaseToEbosPhaseIdx(phaseIdx)); const auto& phaseName = FluidSystem::phaseName(flowPhaseToEbosPhaseIdx(phaseIdx));
if (std::isnan(mass_balance_residual[phaseIdx]) if (std::isnan(mass_balance_residual[phaseIdx])
|| std::isnan(CNV[phaseIdx]) || std::isnan(CNV[phaseIdx])
|| (phaseIdx < np && std::isnan(well_flux_residual[phaseIdx]))) { || (phaseIdx < numPhases() && std::isnan(well_flux_residual[phaseIdx]))) {
OPM_THROW(Opm::NumericalProblem, "NaN residual for phase " << phaseName); OPM_THROW(Opm::NumericalProblem, "NaN residual for phase " << phaseName);
} }
if (mass_balance_residual[phaseIdx] > maxResidualAllowed() if (mass_balance_residual[phaseIdx] > maxResidualAllowed()
|| CNV[phaseIdx] > maxResidualAllowed() || CNV[phaseIdx] > maxResidualAllowed()
|| (phaseIdx < np && well_flux_residual[phaseIdx] > maxResidualAllowed())) { || (phaseIdx < numPhases() && well_flux_residual[phaseIdx] > maxResidualAllowed())) {
OPM_THROW(Opm::NumericalProblem, "Too large residual for phase " << phaseName); OPM_THROW(Opm::NumericalProblem, "Too large residual for phase " << phaseName);
} }
} }
@ -1037,6 +1035,14 @@ namespace Opm {
return fluid_.numPhases(); return fluid_.numPhases();
} }
int numComponents() const
{
if (numPhases() == 2) {
return 2;
}
return FluidSystem::numComponents;
}
/// Wrapper required due to not following generic API /// Wrapper required due to not following generic API
template<class T> template<class T>
std::vector<std::vector<double> > std::vector<std::vector<double> >
@ -1403,13 +1409,8 @@ namespace Opm {
intQuants.pvtRegionIndex()).value(); intQuants.pvtRegionIndex()).value();
} }
} }
const size_t max_num_cells_faillog = 20; const size_t max_num_cells_faillog = 20;
if (failed_cells_pb.size() > 0) { if (failed_cells_pb.size() > 0) {
std::stringstream errlog; std::stringstream errlog;
@ -1480,7 +1481,7 @@ namespace Opm {
SimulatorReport failureReport_; SimulatorReport failureReport_;
// Well Model // Well Model
StandardWellsDense<FluidSystem, BlackoilIndices, ElementContext, MaterialLaw> well_model_; StandardWellsDense<TypeTag> well_model_;
/// \brief Whether we print something to std::cout /// \brief Whether we print something to std::cout
bool terminal_output_; bool terminal_output_;
@ -1498,9 +1499,9 @@ namespace Opm {
public: public:
/// return the StandardWells object /// return the StandardWells object
StandardWellsDense<FluidSystem, BlackoilIndices, ElementContext, MaterialLaw>& StandardWellsDense<TypeTag>&
wellModel() { return well_model_; } wellModel() { return well_model_; }
const StandardWellsDense<FluidSystem, BlackoilIndices, ElementContext, MaterialLaw>& const StandardWellsDense<TypeTag>&
wellModel() const { return well_model_; } wellModel() const { return well_model_; }
/// return the Well struct in the StandardWells /// return the Well struct in the StandardWells
@ -1603,12 +1604,14 @@ namespace Opm {
public: public:
int ebosCompToFlowPhaseIdx( const int compIdx ) const int ebosCompToFlowPhaseIdx( const int compIdx ) const
{ {
assert(compIdx < 3);
const int compToPhase[ 3 ] = { Oil, Water, Gas }; const int compToPhase[ 3 ] = { Oil, Water, Gas };
return compToPhase[ compIdx ]; return compToPhase[ compIdx ];
} }
int flowToEbosPvIdx( const int flowPv ) const int flowToEbosPvIdx( const int flowPv ) const
{ {
assert(flowPv < 3);
const int flowToEbos[ 3 ] = { const int flowToEbos[ 3 ] = {
BlackoilIndices::pressureSwitchIdx, BlackoilIndices::pressureSwitchIdx,
BlackoilIndices::waterSaturationIdx, BlackoilIndices::waterSaturationIdx,
@ -1619,6 +1622,7 @@ namespace Opm {
int flowPhaseToEbosCompIdx( const int phaseIdx ) const int flowPhaseToEbosCompIdx( const int phaseIdx ) const
{ {
assert(phaseIdx < 3);
const int phaseToComp[ 3 ] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx }; const int phaseToComp[ 3 ] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx };
return phaseToComp[ phaseIdx ]; return phaseToComp[ phaseIdx ];
} }
@ -1671,7 +1675,7 @@ namespace Opm {
const int ebosPhaseIdx = flowPhaseToEbosPhaseIdx(canonicalFlowPhaseIdx); const int ebosPhaseIdx = flowPhaseToEbosPhaseIdx(canonicalFlowPhaseIdx);
const int ebosCompIdx = flowPhaseToEbosCompIdx(canonicalFlowPhaseIdx); const int ebosCompIdx = flowPhaseToEbosCompIdx(canonicalFlowPhaseIdx);
const double refDens = FluidSystem::referenceDensity(ebosPhaseIdx, pvtRegionIdx); const double refDens = FluidSystem::referenceDensity(ebosPhaseIdx, pvtRegionIdx);
for( int pvIdx=0; pvIdx<numFlowPhases; ++pvIdx ) for( int pvIdx = 0; pvIdx < numEq; ++pvIdx )
{ {
(*col)[ebosCompIdx][flowToEbosPvIdx(pvIdx)] /= refDens; (*col)[ebosCompIdx][flowToEbosPvIdx(pvIdx)] /= refDens;
(*col)[ebosCompIdx][flowToEbosPvIdx(pvIdx)] *= cellVolume; (*col)[ebosCompIdx][flowToEbosPvIdx(pvIdx)] *= cellVolume;

View File

@ -1040,7 +1040,7 @@ namespace Opm
// 2. Compute densities // 2. Compute densities
std::vector<double> cd = std::vector<double> cd =
WellDensitySegmented::computeConnectionDensities( WellDensitySegmented::computeConnectionDensities(
wells(), xw, fluid_->phaseUsage(), wells(), fluid_->phaseUsage(), xw.perfPhaseRates(),
b_perf, rsmax_perf, rvmax_perf, surf_dens_perf); b_perf, rsmax_perf, rvmax_perf, surf_dens_perf);
// 3. Compute pressure deltas // 3. Compute pressure deltas

View File

@ -57,6 +57,7 @@ public:
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
typedef typename GET_PROP_TYPE(TypeTag, Indices) BlackoilIndices; typedef typename GET_PROP_TYPE(TypeTag, Indices) BlackoilIndices;
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
@ -66,7 +67,7 @@ public:
typedef BlackoilModelEbos Model; typedef BlackoilModelEbos Model;
typedef BlackoilModelParameters ModelParameters; typedef BlackoilModelParameters ModelParameters;
typedef NonlinearSolver<Model> Solver; typedef NonlinearSolver<Model> Solver;
typedef StandardWellsDense<FluidSystem, BlackoilIndices,ElementContext,MaterialLaw> WellModel; typedef StandardWellsDense<TypeTag> WellModel;
/// Initialise from parameters and objects to observe. /// Initialise from parameters and objects to observe.

View File

@ -2,7 +2,7 @@
Copyright 2016 SINTEF ICT, Applied Mathematics. Copyright 2016 SINTEF ICT, Applied Mathematics.
Copyright 2016 - 2017 Statoil ASA. Copyright 2016 - 2017 Statoil ASA.
Copyright 2017 Dr. Blatt - HPC-Simulation-Software & Services Copyright 2017 Dr. Blatt - HPC-Simulation-Software & Services
Copyright 2016 IRIS AS Copyright 2016 - 2017 IRIS AS
This file is part of the Open Porous Media project (OPM). This file is part of the Open Porous Media project (OPM).
@ -67,20 +67,33 @@ enum WellVariablePositions {
/// Class for handling the standard well model. /// Class for handling the standard well model.
template<typename FluidSystem, typename BlackoilIndices, typename ElementContext, typename MaterialLaw> template<typename TypeTag>
class StandardWellsDense { class StandardWellsDense {
public: public:
// --------- Types --------- // --------- Types ---------
typedef WellStateFullyImplicitBlackoilDense WellState; typedef WellStateFullyImplicitBlackoilDense WellState;
typedef BlackoilModelParameters ModelParameters; typedef BlackoilModelParameters ModelParameters;
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
typedef typename GET_PROP_TYPE(TypeTag, Indices) BlackoilIndices;
typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
typedef double Scalar; typedef double Scalar;
static const int blocksize = 3; static const int numEq = BlackoilIndices::numEq;
typedef Dune::FieldVector<Scalar, blocksize > VectorBlockType; static const int numWellEq = numEq; //number of wellEq is the same as numEq in the model
typedef Dune::FieldMatrix<Scalar, blocksize, blocksize > MatrixBlockType; typedef Dune::FieldVector<Scalar, numEq > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, numEq, numEq > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat; typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector; typedef Dune::BlockVector<VectorBlockType> BVector;
typedef DenseAd::Evaluation<double, /*size=*/blocksize*2> EvalWell; typedef DenseAd::Evaluation<double, /*size=*/numEq + numWellEq> EvalWell;
typedef DenseAd::Evaluation<double, /*size=*/numEq> Eval;
// For the conversion between the surface volume rate and resrevoir voidage rate // For the conversion between the surface volume rate and resrevoir voidage rate
using RateConverterType = RateConverter:: using RateConverterType = RateConverter::
@ -102,27 +115,33 @@ enum WellVariablePositions {
long int global_nc); long int global_nc);
template <typename Simulator> /// The number of components in the model.
int numComponents() const
{
if (phase_usage_.num_phases == 2) {
return 2;
}
return FluidSystem::numComponents;
}
SimulatorReport assemble(Simulator& ebosSimulator, SimulatorReport assemble(Simulator& ebosSimulator,
const int iterationIdx, const int iterationIdx,
const double dt, const double dt,
WellState& well_state); WellState& well_state);
template <typename Simulator>
void assembleWellEq(Simulator& ebosSimulator, void assembleWellEq(Simulator& ebosSimulator,
const double dt, const double dt,
WellState& well_state, WellState& well_state,
bool only_wells); bool only_wells);
template <typename Simulator>
void void
getMobility(const Simulator& ebosSimulator, getMobility(const Simulator& ebosSimulator,
const int perf, const int perf,
const int cell_idx, const int cell_idx,
std::vector<EvalWell>& mob) const; std::vector<EvalWell>& mob) const;
template <typename Simulator> bool allow_cross_flow(const int w, const Simulator& ebosSimulator) const;
bool allow_cross_flow(const int w, Simulator& ebosSimulator) const;
void localInvert(Mat& istlA) const; void localInvert(Mat& istlA) const;
@ -177,8 +196,6 @@ enum WellVariablePositions {
/// Diff to bhp for each well perforation. /// Diff to bhp for each well perforation.
const std::vector<double>& wellPerforationPressureDiffs() const; const std::vector<double>& wellPerforationPressureDiffs() const;
typedef DenseAd::Evaluation<double, /*size=*/blocksize> Eval;
EvalWell extendEval(Eval in) const; EvalWell extendEval(Eval in) const;
void setWellVariables(const WellState& xw); void setWellVariables(const WellState& xw);
@ -187,12 +204,9 @@ enum WellVariablePositions {
void computeAccumWells(); void computeAccumWells();
template<typename FluidState> void computeWellFlux(const int& w, const double& Tw, const IntensiveQuantities& intQuants, const std::vector<EvalWell>& mob_perfcells_dense,
void const EvalWell& bhp, const double& cdp, const bool& allow_cf, std::vector<EvalWell>& cq_s) const;
computeWellFlux(const int& w, const double& Tw, const FluidState& fs, const std::vector<EvalWell>& mob_perfcells_dense,
const EvalWell& bhp, const double& cdp, const bool& allow_cf, std::vector<EvalWell>& cq_s) const;
template <typename Simulator>
SimulatorReport solveWellEq(Simulator& ebosSimulator, SimulatorReport solveWellEq(Simulator& ebosSimulator,
const double dt, const double dt,
WellState& well_state); WellState& well_state);
@ -201,23 +215,18 @@ enum WellVariablePositions {
std::vector<double> residual() const; std::vector<double> residual() const;
template <typename Simulator>
bool getWellConvergence(Simulator& ebosSimulator, bool getWellConvergence(Simulator& ebosSimulator,
const int iteration) const; const int iteration) const;
template<typename Simulator> void computeWellConnectionPressures(const Simulator& ebosSimulator,
void const WellState& xw);
computeWellConnectionPressures(const Simulator& ebosSimulator,
const WellState& xw);
template<typename Simulator> void computePropertiesForWellConnectionPressures(const Simulator& ebosSimulator,
void const WellState& xw,
computePropertiesForWellConnectionPressures(const Simulator& ebosSimulator, std::vector<double>& b_perf,
const WellState& xw, std::vector<double>& rsmax_perf,
std::vector<double>& b_perf, std::vector<double>& rvmax_perf,
std::vector<double>& rsmax_perf, std::vector<double>& surf_dens_perf) const;
std::vector<double>& rvmax_perf,
std::vector<double>& surf_dens_perf) const;
void updateWellState(const BVector& dwells, void updateWellState(const BVector& dwells,
WellState& well_state) const; WellState& well_state) const;
@ -227,12 +236,11 @@ enum WellVariablePositions {
void updateWellControls(WellState& xw) const; void updateWellControls(WellState& xw) const;
/// upate the dynamic lists related to economic limits /// upate the dynamic lists related to economic limits
void void updateListEconLimited(const Schedule& schedule,
updateListEconLimited(const Schedule& schedule, const int current_step,
const int current_step, const Wells* wells_struct,
const Wells* wells_struct, const WellState& well_state,
const WellState& well_state, DynamicListEconLimited& list_econ_limited) const;
DynamicListEconLimited& list_econ_limited) const;
void computeWellConnectionDensitesPressures(const WellState& xw, void computeWellConnectionDensitesPressures(const WellState& xw,
const std::vector<double>& b_perf, const std::vector<double>& b_perf,
@ -245,15 +253,12 @@ enum WellVariablePositions {
// Calculating well potentials for each well // Calculating well potentials for each well
// TODO: getBhp() will be refactored to reduce the duplication of the code calculating the bhp from THP. // TODO: getBhp() will be refactored to reduce the duplication of the code calculating the bhp from THP.
template<typename Simulator> void computeWellPotentials(const Simulator& ebosSimulator,
void const WellState& well_state,
computeWellPotentials(const Simulator& ebosSimulator, std::vector<double>& well_potentials) const;
const WellState& well_state,
std::vector<double>& well_potentials) const;
// TODO: some preparation work, mostly related to group control and RESV, // TODO: some preparation work, mostly related to group control and RESV,
// at the beginning of each time step (Not report step) // at the beginning of each time step (Not report step)
template<typename Simulator>
void prepareTimeStep(const Simulator& ebos_simulator, void prepareTimeStep(const Simulator& ebos_simulator,
WellState& well_state); WellState& well_state);
@ -320,14 +325,14 @@ enum WellVariablePositions {
// protected methods // protected methods
EvalWell getBhp(const int wellIdx) const; EvalWell getBhp(const int wellIdx) const;
EvalWell getQs(const int wellIdx, const int phaseIdx) const; EvalWell getQs(const int wellIdx, const int compIdx) const;
EvalWell wellVolumeFraction(const int wellIdx, const int phaseIdx) const; EvalWell wellVolumeFraction(const int wellIdx, const int compIdx) const;
EvalWell wellVolumeFractionScaled(const int wellIdx, const int phaseIdx) const; EvalWell wellVolumeFractionScaled(const int wellIdx, const int compIdx) const;
// Q_p / (Q_w + Q_g + Q_o) for three phase cases. // Q_p / (Q_w + Q_g + Q_o) for three phase cases.
EvalWell wellSurfaceVolumeFraction(const int well_index, const int phase) const; EvalWell wellSurfaceVolumeFraction(const int well_index, const int compIdx) const;
bool checkRateEconLimits(const WellEconProductionLimits& econ_production_limits, bool checkRateEconLimits(const WellEconProductionLimits& econ_production_limits,
const WellState& well_state, const WellState& well_state,
@ -367,17 +372,14 @@ enum WellVariablePositions {
// TODO: maybe we should provide a light version of computeWellFlux, which does not include the // TODO: maybe we should provide a light version of computeWellFlux, which does not include the
// calculation of the derivatives // calculation of the derivatives
template<typename Simulator> void computeWellRatesWithBhp(const Simulator& ebosSimulator,
void const EvalWell& bhp,
computeWellRatesWithBhp(const Simulator& ebosSimulator, const int well_index,
const EvalWell& bhp, std::vector<double>& well_flux) const;
const int well_index,
std::vector<double>& well_flux) const;
double mostStrictBhpFromBhpLimits(const int well_index) const; double mostStrictBhpFromBhpLimits(const int well_index) const;
// TODO: maybe it should be improved to be calculate general rates for THP control later // TODO: maybe it should be improved to be calculate general rates for THP control later
template<typename Simulator>
std::vector<double> std::vector<double>
computeWellPotentialWithTHP(const Simulator& ebosSimulator, computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const int well_index, const int well_index,

File diff suppressed because it is too large Load Diff

View File

@ -315,7 +315,7 @@ namespace Opm
// Compute densities // Compute densities
std::vector<double> cd = std::vector<double> cd =
WellDensitySegmented::computeConnectionDensities( WellDensitySegmented::computeConnectionDensities(
wells(), xw, fluid_->phaseUsage(), wells(), fluid_->phaseUsage(), xw.perfPhaseRates(),
b_perf, rsmax_perf, rvmax_perf, surf_dens_perf); b_perf, rsmax_perf, rvmax_perf, surf_dens_perf);
const int nperf = wells().well_connpos[wells().number_of_wells]; const int nperf = wells().well_connpos[wells().number_of_wells];

View File

@ -28,12 +28,10 @@
std::vector<double> std::vector<double>
Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells, Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells,
const WellStateFullyImplicitBlackoil& wstate,
const PhaseUsage& phase_usage, const PhaseUsage& phase_usage,
const std::vector<double>& perfComponentRates,
const std::vector<double>& b_perf, const std::vector<double>& b_perf,
const std::vector<double>& rsmax_perf, const std::vector<double>& rsmax_perf,
const std::vector<double>& rvmax_perf, const std::vector<double>& rvmax_perf,
@ -43,16 +41,17 @@ Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells,
const int np = wells.number_of_phases; const int np = wells.number_of_phases;
const int nw = wells.number_of_wells; const int nw = wells.number_of_wells;
const int nperf = wells.well_connpos[nw]; const int nperf = wells.well_connpos[nw];
const int numComponents = perfComponentRates.size() / nperf;
if (wells.number_of_phases != phase_usage.num_phases) { if (wells.number_of_phases != phase_usage.num_phases) {
OPM_THROW(std::logic_error, "Inconsistent input: wells vs. phase_usage."); OPM_THROW(std::logic_error, "Inconsistent input: wells vs. phase_usage.");
} }
if (nperf*np != int(surf_dens_perf.size())) { if (nperf*numComponents != int(surf_dens_perf.size())) {
OPM_THROW(std::logic_error, "Inconsistent input: wells vs. surf_dens."); OPM_THROW(std::logic_error, "Inconsistent input: wells vs. surf_dens.");
} }
if (nperf*np != int(wstate.perfPhaseRates().size())) { if (nperf*numComponents != int(perfComponentRates.size())) {
OPM_THROW(std::logic_error, "Inconsistent input: wells vs. wstate."); OPM_THROW(std::logic_error, "Inconsistent input: wells vs. wstate.");
} }
if (nperf*np != int(b_perf.size())) { if (nperf*numComponents != int(b_perf.size())) {
OPM_THROW(std::logic_error, "Inconsistent input: wells vs. b_perf."); OPM_THROW(std::logic_error, "Inconsistent input: wells vs. b_perf.");
} }
if ((!rsmax_perf.empty()) || (!rvmax_perf.empty())) { if ((!rsmax_perf.empty()) || (!rvmax_perf.empty())) {
@ -69,20 +68,20 @@ Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells,
// component) exiting up the wellbore from each perforation, // component) exiting up the wellbore from each perforation,
// taking into account flow from lower in the well, and // taking into account flow from lower in the well, and
// in/out-flow at each perforation. // in/out-flow at each perforation.
std::vector<double> q_out_perf(nperf*np); std::vector<double> q_out_perf(nperf*numComponents);
for (int w = 0; w < nw; ++w) { for (int w = 0; w < nw; ++w) {
// Iterate over well perforations from bottom to top. // Iterate over well perforations from bottom to top.
for (int perf = wells.well_connpos[w+1] - 1; perf >= wells.well_connpos[w]; --perf) { for (int perf = wells.well_connpos[w+1] - 1; perf >= wells.well_connpos[w]; --perf) {
for (int phase = 0; phase < np; ++phase) { for (int component = 0; component < numComponents; ++component) {
if (perf == wells.well_connpos[w+1] - 1) { if (perf == wells.well_connpos[w+1] - 1) {
// This is the bottom perforation. No flow from below. // This is the bottom perforation. No flow from below.
q_out_perf[perf*np + phase] = 0.0; q_out_perf[perf*numComponents + component] = 0.0;
} else { } else {
// Set equal to flow from below. // Set equal to flow from below.
q_out_perf[perf*np + phase] = q_out_perf[(perf+1)*np + phase]; q_out_perf[perf*numComponents + component] = q_out_perf[(perf+1)*numComponents + component];
} }
// Subtract outflow through perforation. // Subtract outflow through perforation.
q_out_perf[perf*np + phase] -= wstate.perfPhaseRates()[perf*np + phase]; q_out_perf[perf*numComponents + component] -= perfComponentRates[perf*numComponents + component];
} }
} }
} }
@ -93,22 +92,25 @@ Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells,
// Finally compute densities for the segments associated with each perforation. // Finally compute densities for the segments associated with each perforation.
const int gaspos = phase_usage.phase_pos[BlackoilPhases::Vapour]; const int gaspos = phase_usage.phase_pos[BlackoilPhases::Vapour];
const int oilpos = phase_usage.phase_pos[BlackoilPhases::Liquid]; const int oilpos = phase_usage.phase_pos[BlackoilPhases::Liquid];
std::vector<double> mix(np); std::vector<double> mix(numComponents,0.0);
std::vector<double> x(np); std::vector<double> x(numComponents);
std::vector<double> surf_dens(np); std::vector<double> surf_dens(numComponents);
std::vector<double> dens(nperf); std::vector<double> dens(nperf);
for (int w = 0; w < nw; ++w) { for (int w = 0; w < nw; ++w) {
for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w+1]; ++perf) { for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w+1]; ++perf) {
// Find component mix. // Find component mix.
const double tot_surf_rate = std::accumulate(q_out_perf.begin() + np*perf, const double tot_surf_rate = std::accumulate(q_out_perf.begin() + numComponents*perf,
q_out_perf.begin() + np*(perf+1), 0.0); q_out_perf.begin() + numComponents*(perf+1), 0.0);
if (tot_surf_rate != 0.0) { if (tot_surf_rate != 0.0) {
for (int phase = 0; phase < np; ++phase) { for (int component = 0; component < numComponents; ++component) {
mix[phase] = std::fabs(q_out_perf[perf*np + phase]/tot_surf_rate); mix[component] = std::fabs(q_out_perf[perf*numComponents + component]/tot_surf_rate);
} }
} else { } else {
// No flow => use well specified fractions for mix. // No flow => use well specified fractions for mix.
std::copy(wells.comp_frac + w*np, wells.comp_frac + (w+1)*np, mix.begin()); for (int phase = 0; phase < np; ++phase) {
mix[phase] = wells.comp_frac[w*np + phase];
}
// intialize 0.0 for comIdx >= np;
} }
// Compute volume ratio. // Compute volume ratio.
x = mix; x = mix;
@ -129,11 +131,11 @@ Opm::WellDensitySegmented::computeConnectionDensities(const Wells& wells,
x[oilpos] = (mix[oilpos] - mix[gaspos]*rv)/(1.0 - rs*rv);; x[oilpos] = (mix[oilpos] - mix[gaspos]*rv)/(1.0 - rs*rv);;
} }
double volrat = 0.0; double volrat = 0.0;
for (int phase = 0; phase < np; ++phase) { for (int component = 0; component < numComponents; ++component) {
volrat += x[phase] / b_perf[perf*np + phase]; volrat += x[component] / b_perf[perf*numComponents + component];
} }
for (int phase = 0; phase < np; ++phase) { for (int component = 0; component < numComponents; ++component) {
surf_dens[phase] = surf_dens_perf[perf*np + phase]; surf_dens[component] = surf_dens_perf[perf*numComponents + component];
} }
// Compute segment density. // Compute segment density.

View File

@ -41,17 +41,17 @@ namespace Opm
{ {
public: public:
/// Compute well segment densities /// Compute well segment densities
/// Notation: N = number of perforations, P = number of phases. /// Notation: N = number of perforations, C = number of components.
/// \param[in] wells struct with static well info /// \param[in] wells struct with static well info
/// \param[in] wstate dynamic well solution information, only perfRates() is used /// \param[in] well_rates well rates for actiev components, size NC, P values per perforation
/// \param[in] phase_usage specifies which phases are active and not /// \param[in] phase_usage specifies which phases are active and not
/// \param[in] b_perf inverse ('little b') formation volume factor, size NP, P values per perforation /// \param[in] b_perf inverse ('little b') formation volume factor, size NC, P values per perforation
/// \param[in] rsmax_perf saturation point for rs (gas in oil) at each perforation, size N /// \param[in] rsmax_perf saturation point for rs (gas in oil) at each perforation, size N
/// \param[in] rvmax_perf saturation point for rv (oil in gas) at each perforation, size N /// \param[in] rvmax_perf saturation point for rv (oil in gas) at each perforation, size N
/// \param[in] surf_dens surface densities for active components, size NP, P values per perforation /// \param[in] surf_dens surface densities for active components, size NC, C values per perforation
static std::vector<double> computeConnectionDensities(const Wells& wells, static std::vector<double> computeConnectionDensities(const Wells& wells,
const WellStateFullyImplicitBlackoil& wstate,
const PhaseUsage& phase_usage, const PhaseUsage& phase_usage,
const std::vector<double>& perfComponentRates,
const std::vector<double>& b_perf, const std::vector<double>& b_perf,
const std::vector<double>& rsmax_perf, const std::vector<double>& rsmax_perf,
const std::vector<double>& rvmax_perf, const std::vector<double>& rvmax_perf,
@ -80,7 +80,7 @@ namespace Opm
/// Compute pressure deltas. /// Compute pressure deltas.
/// Notation: N = number of perforations, P = number of phases. /// Notation: N = number of perforations
/// \param[in] wells struct with static well info /// \param[in] wells struct with static well info
/// \param[in] z_perf depth values for each perforation, size N /// \param[in] z_perf depth values for each perforation, size N
/// \param[in] dens_perf densities for each perforation, size N (typically computed using computeConnectionDensities) /// \param[in] dens_perf densities for each perforation, size N (typically computed using computeConnectionDensities)

View File

@ -89,7 +89,6 @@ namespace Opm
return; return;
} }
const int np = wells_->number_of_phases; const int np = wells_->number_of_phases;
well_solutions_.clear(); well_solutions_.clear();
well_solutions_.resize(nw * np, 0.0); well_solutions_.resize(nw * np, 0.0);
std::vector<double> g = {1.0,1.0,0.01}; std::vector<double> g = {1.0,1.0,0.01};
@ -130,7 +129,7 @@ namespace Opm
const int waterpos = pu.phase_pos[Water]; const int waterpos = pu.phase_pos[Water];
const int gaspos = pu.phase_pos[Gas]; const int gaspos = pu.phase_pos[Gas];
assert(np == 3 || (np == 2 && !pu.phase_used[Gas])); assert(np > 2 || (np == 2 && !pu.phase_used[Gas]));
// assumes the gas fractions are stored after water fractions // assumes the gas fractions are stored after water fractions
if(std::abs(total_rates) > 0) { if(std::abs(total_rates) > 0) {
if( pu.phase_used[Water] ) { if( pu.phase_used[Water] ) {
@ -139,6 +138,8 @@ namespace Opm
if( pu.phase_used[Gas] ) { if( pu.phase_used[Gas] ) {
wellSolutions()[2*nw + w] = g[Gas] * wellRates()[np*w + gaspos] / total_rates ; wellSolutions()[2*nw + w] = g[Gas] * wellRates()[np*w + gaspos] / total_rates ;
} }
} else { } else {
if( pu.phase_used[Water] ) { if( pu.phase_used[Water] ) {
wellSolutions()[nw + w] = wells_->comp_frac[np*w + waterpos]; wellSolutions()[nw + w] = wells_->comp_frac[np*w + waterpos];

View File

@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(TestPressureDeltas)
std::vector<double> cd = std::vector<double> cd =
WellDensitySegmented::computeConnectionDensities( WellDensitySegmented::computeConnectionDensities(
*wells, wellstate, pu, *wells, pu, rates,
b_perf, rsmax_perf, rvmax_perf, surf_dens); b_perf, rsmax_perf, rvmax_perf, surf_dens);
std::vector<double> dp = std::vector<double> dp =
WellDensitySegmented::computeConnectionPressureDelta( WellDensitySegmented::computeConnectionPressureDelta(