Hook New WBPn Calculation Up to Well Model

This commit activates the support for calculating WBPn summary
result values per well in parallel.  To affect the calculation we
add two new data members in BlackoilWellModelGeneric:

  - conn_idx_map_:
    Maps well's connection index (0..getConnections().size() - 1) to
    connections on current rank.  Its local() connections are
    negative 1 (-1) if the connection is not on current rank, and a
    non-negative value otherwise.  The global() function maps well
    connections on current rank to global connection ID for each
    well.  Effectively the reverse of local().  Finally, the open()
    function maps well connections on current rank to open/flowing
    connections on current rank.  Negative 1 if connection is not
    flowing.

  - wbpCalculationService:
    Parallel collection of WBPn calculation objects that knows how
    to exchange source and result information between all ranks in a
    communicator.  Also handles distributed wells.

We furthermore need a way to compute connection-level fluid mixture
density values.  For the standard well class we add a way to access
the StandardWellConnection's 'perf_densities_' values.  However,
since these are defined for open/flowing connections only, this
means we're not able to fully meet the requirements of the

  WELL/ALL

WPAVE depth correction procedure for standard wells.  The
multi-segmented well type, on the other hand, uses the fluid mixture
density in the associated well segment and is therefore well defined
for ALL connections.  OPEN well connections are supported for both
well types.
This commit is contained in:
Bård Skaflestad 2023-06-06 21:31:17 +02:00
parent ff9e6ca18a
commit 7f89276fe8
11 changed files with 457 additions and 35 deletions

View File

@ -210,7 +210,7 @@ public:
simulator_.vanguard().setupTime();
const auto localWellData = simulator_.problem().wellModel().wellData();
const auto localWBP = data::WellBlockAveragePressures{};
const auto localWBP = simulator_.problem().wellModel().wellBlockAveragePressures();
const auto localGroupAndNetworkData = simulator_.problem().wellModel()
.groupAndNetworkData(reportStepNum);

View File

@ -38,35 +38,39 @@
#include <unordered_map>
#include <vector>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/input/eclipse/Schedule/Group/GuideRate.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
#include <opm/input/eclipse/Schedule/Group/GuideRate.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/simulators/timestepping/SimulatorReport.hpp>
#include <opm/simulators/flow/countGlobalCells.hpp>
#include <opm/simulators/flow/SubDomain.hpp>
#include <opm/simulators/wells/BlackoilWellModelGeneric.hpp>
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
#include <opm/simulators/wells/GasLiftGroupInfo.hpp>
#include <opm/simulators/wells/GasLiftSingleWell.hpp>
#include <opm/simulators/wells/GasLiftWellState.hpp>
#include <opm/simulators/wells/GasLiftSingleWellGeneric.hpp>
#include <opm/simulators/wells/GasLiftStage2.hpp>
#include <opm/simulators/wells/GasLiftGroupInfo.hpp>
#include <opm/simulators/wells/GasLiftWellState.hpp>
#include <opm/simulators/wells/MultisegmentWell.hpp>
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
#include <opm/simulators/wells/ParallelWellInfo.hpp>
#include <opm/simulators/wells/PerforationData.hpp>
#include <opm/simulators/wells/VFPInjProperties.hpp>
#include <opm/simulators/wells/VFPProdProperties.hpp>
#include <opm/simulators/wells/WellState.hpp>
#include <opm/simulators/wells/WGState.hpp>
#include <opm/simulators/wells/RateConverter.hpp>
#include <opm/simulators/wells/RegionAverageCalculator.hpp>
#include <opm/simulators/wells/WellInterface.hpp>
#include <opm/simulators/wells/StandardWell.hpp>
#include <opm/simulators/wells/MultisegmentWell.hpp>
#include <opm/simulators/wells/VFPInjProperties.hpp>
#include <opm/simulators/wells/VFPProdProperties.hpp>
#include <opm/simulators/wells/WGState.hpp>
#include <opm/simulators/wells/WellGroupHelpers.hpp>
#include <opm/simulators/wells/WellInterface.hpp>
#include <opm/simulators/wells/WellProdIndexCalculator.hpp>
#include <opm/simulators/wells/ParallelWellInfo.hpp>
#include <opm/simulators/wells/WellState.hpp>
#include <opm/simulators/timestepping/SimulatorReport.hpp>
#include <opm/simulators/timestepping/gatherConvergenceReport.hpp>
#include <dune/common/fmatrix.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/matrixmatrix.hh>
@ -266,6 +270,11 @@ namespace Opm {
return wsrpt;
}
data::WellBlockAveragePressures wellBlockAveragePressures() const
{
return this->computeWellBlockAveragePressures();
}
// subtract Binv(D)rw from r;
void apply( BVector& r) const;
@ -387,6 +396,13 @@ namespace Opm {
std::unique_ptr<RateConverterType> rateConverter_{};
std::map<std::string, std::unique_ptr<AverageRegionalPressureType>> regionalAveragePressureCalculator_{};
struct WBPCalcID
{
std::optional<typename std::vector<WellInterfacePtr>::size_type> openWellIdx_{};
std::size_t wbpCalcIdx_{};
};
std::vector<WBPCalcID> wbpCalcMap_{};
SimulatorReportSingle last_report_{};
@ -447,6 +463,16 @@ namespace Opm {
// setting the well_solutions_ based on well_state.
void updatePrimaryVariables(DeferredLogger& deferred_logger);
void initializeWBPCalculationService();
data::WellBlockAveragePressures
computeWellBlockAveragePressures() const;
ParallelWBPCalculation::EvaluatorFactory
makeWellSourceEvaluatorFactory(const std::vector<Well>::size_type wellIdx) const;
void registerOpenWellsForWBPCalculation();
void updateAverageFormationFactor();
void computePotentials(const std::size_t widx,

View File

@ -49,6 +49,7 @@
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
#include <opm/simulators/wells/BlackoilWellModelRestart.hpp>
#include <opm/simulators/wells/GasLiftStage2.hpp>
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
#include <opm/simulators/wells/VFPProperties.hpp>
#include <opm/simulators/wells/WellFilterCake.hpp>
#include <opm/simulators/wells/WellGroupHelpers.hpp>
@ -81,6 +82,7 @@ BlackoilWellModelGeneric(Schedule& schedule,
, eclState_(eclState)
, comm_(comm)
, phase_usage_(phase_usage)
, wbpCalculationService_ { eclState.gridDims(), comm_ }
, guideRate_(schedule)
, active_wgstate_(phase_usage)
, last_valid_wgstate_(phase_usage)
@ -287,57 +289,89 @@ BlackoilWellModelGeneric::
initializeWellPerfData()
{
well_perf_data_.resize(wells_ecl_.size());
this->conn_idx_map_.clear();
this->conn_idx_map_.reserve(wells_ecl_.size());
int well_index = 0;
for (const auto& well : wells_ecl_) {
int connection_index = 0;
// INVALID_ECL_INDEX marks no above perf available
int connection_index_above = ParallelWellInfo::INVALID_ECL_INDEX;
well_perf_data_[well_index].clear();
well_perf_data_[well_index].reserve(well.getConnections().size());
CheckDistributedWellConnections checker(well, local_parallel_well_info_[well_index].get());
auto& connIdxMap = this->conn_idx_map_
.emplace_back(well.getConnections().size());
CheckDistributedWellConnections checker {
well, this->local_parallel_well_info_[well_index].get()
};
bool hasFirstConnection = false;
bool firstOpenConnection = true;
auto& parallelWellInfo = this->local_parallel_well_info_[well_index].get();
parallelWellInfo.beginReset();
for (const auto& connection : well.getConnections()) {
const int active_index = compressedIndexForInterior(connection.global_index());
if (connection.state() == Connection::State::OPEN) {
const auto active_index =
this->compressedIndexForInterior(connection.global_index());
const auto connIsOpen =
connection.state() == Connection::State::OPEN;
if (active_index >= 0) {
connIdxMap.addActiveConnection(connection_index, connIsOpen);
}
if ((connIsOpen && (active_index >= 0)) || !connIsOpen) {
checker.connectionFound(connection_index);
}
if (connIsOpen) {
if (active_index >= 0) {
if (firstOpenConnection)
{
if (firstOpenConnection) {
hasFirstConnection = true;
}
checker.connectionFound(connection_index);
PerforationData pd;
auto pd = PerforationData{};
pd.cell_index = active_index;
pd.connection_transmissibility_factor = connection.CF();
pd.satnum_id = connection.satTableId();
pd.ecl_index = connection_index;
well_perf_data_[well_index].push_back(pd);
parallelWellInfo.pushBackEclIndex(connection_index_above,
connection_index);
}
firstOpenConnection = false;
// Next time this index is the one above as each open connection is
// is stored somehwere.
// Next time this index is the one above as each open
// connection is stored somewhere.
connection_index_above = connection_index;
} else {
checker.connectionFound(connection_index);
if (connection.state() != Connection::State::SHUT) {
OPM_THROW(std::runtime_error,
"Connection state: " +
Connection::State2String(connection.state()) +
" not handled");
}
}
// Note: we rely on the connections being filtered! I.e. there are only connections
// to active cells in the global grid.
else if (connection.state() != Connection::State::SHUT) {
OPM_THROW(std::runtime_error,
fmt::format("Connection state '{}' not handled",
Connection::State2String(connection.state())));
}
// Note: we rely on the connections being filtered! I.e., there
// are only connections to active cells in the global grid.
++connection_index;
}
parallelWellInfo.endReset();
checker.checkAllConnectionsFound();
parallelWellInfo.communicateFirstPerforation(hasFirstConnection);
++well_index;
}
}

View File

@ -25,20 +25,28 @@
#include <opm/output/data/GuideRateValue.hpp>
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
#include <opm/input/eclipse/Schedule/Group/GuideRate.hpp>
#include <opm/input/eclipse/Schedule/Well/PAvg.hpp>
#include <opm/input/eclipse/Schedule/Well/PAvgCalculator.hpp>
#include <opm/input/eclipse/Schedule/Well/PAvgCalculatorCollection.hpp>
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
#include <opm/simulators/wells/ParallelPAvgDynamicSourceData.hpp>
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
#include <opm/simulators/wells/PerforationData.hpp>
#include <opm/simulators/wells/WellFilterCake.hpp>
#include <opm/simulators/wells/WellProdIndexCalculator.hpp>
#include <opm/simulators/wells/WGState.hpp>
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@ -419,6 +427,94 @@ protected:
std::vector<Well> wells_ecl_;
std::vector<std::vector<PerforationData>> well_perf_data_;
/// Connection index mappings
class ConnectionIndexMap
{
public:
/// Constructor.
///
/// \param[in] numConns Total number of well connections, both open
/// and closed/shut. Typically \code WellConnections::size() \endcode.
explicit ConnectionIndexMap(const std::size_t numConns)
: local_(numConns, -1)
{
this->global_.reserve(numConns);
this->open_.reserve(numConns);
}
/// Enumerate/map new active connection.
///
/// \param[in] connIdx Global well connection index. Must be an
/// integer in the range 0..numConns-1.
///
/// \param[in] connIsOpen Whether or not the connection is
/// open/flowing.
void addActiveConnection(const int connIdx,
const bool connIsOpen)
{
this->local_[connIdx] =
static_cast<int>(this->global_.size());
this->global_.push_back(connIdx);
const auto open_conn_idx = connIsOpen
? this->num_open_conns_++
: -1;
this->open_.push_back(open_conn_idx);
}
/// Get local connection IDs/indices of every existing well
/// connection.
///
/// Negative value (-1) for connections that don't intersect the
/// current rank.
const std::vector<int>& local() const
{
return this->local_;
}
/// Get global connection ID of local (on-rank) connection.
///
/// \param[in] connIdx Local connection index.
///
/// \return Global connection ID of \p connIdx.
int global(const int connIdx) const
{
return this->global_[connIdx];
}
/// Get open connection ID of local (on-rank) connection.
///
/// \param[in] connIdx Local connection index.
///
/// \return Open connection ID of \p connIdx. Integer in the range
/// 0..#open connections - 1 if the connection is open or negative
/// value (-1) otherwise.
int open(const int connIdx) const
{
return this->open_[connIdx];
}
private:
/// Local connection IDs/indices of every existing well connection.
/// Negative value (-1) for connections that don't intersect the
/// current rank.
std::vector<int> local_{};
/// Global connection index of each on-rank reservoir connection.
/// Reverse/transpose mapping of \c local_.
std::vector<int> global_{};
/// Open connection index of each on-rank reservoir connection.
std::vector<int> open_{};
/// Number of open connections on this rank.
int num_open_conns_{0};
};
std::vector<ConnectionIndexMap> conn_idx_map_{};
std::function<bool(const Well&)> not_on_process_{};
// a vector of all the wells.
@ -430,6 +526,7 @@ protected:
std::vector<std::reference_wrapper<ParallelWellInfo>> local_parallel_well_info_;
std::vector<WellProdIndexCalculator> prod_index_calc_;
mutable ParallelWBPCalculation wbpCalculationService_;
std::vector<int> pvt_region_idx_;

View File

@ -27,8 +27,11 @@
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
#include <opm/simulators/wells/ParallelPAvgDynamicSourceData.hpp>
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
#include <opm/simulators/wells/VFPProperties.hpp>
#include <opm/simulators/utils/MPIPacker.hpp>
#include <opm/simulators/linalg/bda/WellContributions.hpp>
@ -73,6 +76,48 @@ namespace Opm {
this->alternative_well_rate_init_ =
EWOMS_GET_PARAM(TypeTag, bool, AlternativeWellRateInit);
this->wbpCalculationService_
.localCellIndex([this](const std::size_t globalIndex)
{ return this->compressedIndexForInterior(globalIndex); })
.evalCellSource([this](const int localCell,
PAvgDynamicSourceData::SourceDataSpan<double> sourceTerms)
{
using Item = PAvgDynamicSourceData::SourceDataSpan<double>::Item;
const auto* intQuants = this->ebosSimulator_.model()
.cachedIntensiveQuantities(localCell, /*timeIndex = */0);
const auto& fs = intQuants->fluidState();
sourceTerms.set(Item::PoreVol, intQuants->porosity().value() *
this->ebosSimulator_.model().dofTotalVolume(localCell));
constexpr auto io = FluidSystem::oilPhaseIdx;
constexpr auto ig = FluidSystem::gasPhaseIdx;
constexpr auto iw = FluidSystem::waterPhaseIdx;
// Ideally, these would be 'constexpr'.
const auto haveOil = FluidSystem::phaseIsActive(io);
const auto haveGas = FluidSystem::phaseIsActive(ig);
const auto haveWat = FluidSystem::phaseIsActive(iw);
auto weightedPhaseDensity = [&fs](const auto ip)
{
return fs.saturation(ip).value() * fs.density(ip).value();
};
if (haveOil) { sourceTerms.set(Item::Pressure, fs.pressure(io).value()); }
else if (haveGas) { sourceTerms.set(Item::Pressure, fs.pressure(ig).value()); }
else { sourceTerms.set(Item::Pressure, fs.pressure(iw).value()); }
// Strictly speaking, assumes SUM(s[p]) == 1.
auto rho = 0.0;
if (haveOil) { rho += weightedPhaseDensity(io); }
if (haveGas) { rho += weightedPhaseDensity(ig); }
if (haveWat) { rho += weightedPhaseDensity(iw); }
sourceTerms.set(Item::MixtureDensity, rho);
});
}
template<typename TypeTag>
@ -209,6 +254,7 @@ namespace Opm {
// We must therefore provide it with updated cell pressures
this->initializeWellPerfData();
this->initializeWellState(timeStepIdx, summaryState);
this->initializeWBPCalculationService();
// handling MS well related
if (param_.use_multisegment_well_&& anyMSWellOpenLocal()) { // if we use MultisegmentWell model
@ -230,11 +276,16 @@ namespace Opm {
}
{
const auto& sched_state = this->schedule()[timeStepIdx];
// update VFP properties
const auto& sched_state = this->schedule()[timeStepIdx];
vfp_properties_ = std::make_unique<VFPProperties>(sched_state.vfpinj(),
sched_state.vfpprod(),
this->wellState());
}
{
const auto& sched_state = this->schedule()[timeStepIdx];
this->initializeWellProdIndCalculators();
if (sched_state.events().hasEvent(ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX)) {
this->runWellPIScaling(timeStepIdx, local_deferredLogger);
@ -799,6 +850,8 @@ namespace Opm {
}
}
}
this->registerOpenWellsForWBPCalculation();
}
@ -1801,6 +1854,154 @@ namespace Opm {
template <typename TypeTag>
void
BlackoilWellModel<TypeTag>::
initializeWBPCalculationService()
{
this->wbpCalcMap_.clear();
this->wbpCalcMap_.resize(this->wells_ecl_.size());
this->registerOpenWellsForWBPCalculation();
auto wellID = std::size_t{0};
for (const auto& well : this->wells_ecl_) {
this->wbpCalcMap_[wellID].wbpCalcIdx_ = this->wbpCalculationService_
.createCalculator(well,
this->local_parallel_well_info_[wellID],
this->conn_idx_map_[wellID].local(),
this->makeWellSourceEvaluatorFactory(wellID));
++wellID;
}
this->wbpCalculationService_.defineCommunication();
}
template <typename TypeTag>
data::WellBlockAveragePressures
BlackoilWellModel<TypeTag>::
computeWellBlockAveragePressures() const
{
auto wbpResult = data::WellBlockAveragePressures{};
using Calculated = PAvgCalculator::Result::WBPMode;
using Output = data::WellBlockAvgPress::Quantity;
this->wbpCalculationService_.collectDynamicValues();
const auto numWells = this->wells_ecl_.size();
for (auto wellID = 0*numWells; wellID < numWells; ++wellID) {
const auto calcIdx = this->wbpCalcMap_[wellID].wbpCalcIdx_;
const auto& well = this->wells_ecl_[wellID];
if (! well.hasRefDepth()) {
// Can't perform depth correction without at least a
// fall-back datum depth.
continue;
}
this->wbpCalculationService_
.inferBlockAveragePressures(calcIdx, well.pavg(),
this->gravity_,
well.getWPaveRefDepth());
const auto& result = this->wbpCalculationService_
.averagePressures(calcIdx);
auto& reported = wbpResult.values[well.name()];
reported[Output::WBP] = result.value(Calculated::WBP);
reported[Output::WBP4] = result.value(Calculated::WBP4);
reported[Output::WBP5] = result.value(Calculated::WBP5);
reported[Output::WBP9] = result.value(Calculated::WBP9);
}
return wbpResult;
}
template <typename TypeTag>
ParallelWBPCalculation::EvaluatorFactory
BlackoilWellModel<TypeTag>::
makeWellSourceEvaluatorFactory(const std::vector<Well>::size_type wellIdx) const
{
using Span = PAvgDynamicSourceData::SourceDataSpan<double>;
using Item = typename Span::Item;
return [wellIdx, this]() -> ParallelWBPCalculation::Evaluator
{
if (! this->wbpCalcMap_[wellIdx].openWellIdx_.has_value()) {
// Well is stopped/shut. Return evaluator for stopped wells.
return []([[maybe_unused]] const int connIdx, Span sourceTerm)
{
// Well/connection is stopped/shut. Set all items to
// zero.
sourceTerm
.set(Item::Pressure , 0.0)
.set(Item::PoreVol , 0.0)
.set(Item::MixtureDensity, 0.0);
};
}
// Well is open. Return an evaluator for open wells/open connections.
return [this, wellPtr = this->well_container_[*this->wbpCalcMap_[wellIdx].openWellIdx_].get()]
(const int connIdx, Span sourceTerm)
{
// Note: The only item which actually matters for the WBP
// calculation at the well reservoir connection level is the
// mixture density. Set other items to zero.
const auto& connIdxMap =
this->conn_idx_map_[wellPtr->indexOfWell()];
const auto rho = wellPtr->
connectionDensity(connIdxMap.global(connIdx),
connIdxMap.open(connIdx));
sourceTerm
.set(Item::Pressure , 0.0)
.set(Item::PoreVol , 0.0)
.set(Item::MixtureDensity, rho);
};
};
}
template <typename TypeTag>
void
BlackoilWellModel<TypeTag>::
registerOpenWellsForWBPCalculation()
{
assert (this->wbpCalcMap_.size() == this->wells_ecl_.size());
for (auto& wbpCalc : this->wbpCalcMap_) {
wbpCalc.openWellIdx_.reset();
}
auto openWellIdx = typename std::vector<WellInterfacePtr>::size_type{0};
for (const auto* openWell : this->well_container_generic_) {
this->wbpCalcMap_[openWell->indexOfWell()].openWellIdx_ = openWellIdx++;
}
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::

View File

@ -137,6 +137,9 @@ namespace Opm
WellState& well_state,
DeferredLogger& deferred_logger) const override;
double connectionDensity(const int globalConnIdx,
const int openConnIdx) const override;
void addWellContributions(SparseMatrixAdapter& jacobian) const override;
void addWellPressureEquations(PressureMatrix& mat,

View File

@ -21,8 +21,12 @@
#include <opm/common/Exceptions.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/input/eclipse/Schedule/MSW/Segment.hpp>
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/input/eclipse/Units/Units.hpp>
#include <opm/material/densead/EvaluationFormat.hpp>
@ -703,6 +707,28 @@ namespace Opm
template<typename TypeTag>
double
MultisegmentWell<TypeTag>::
connectionDensity(const int globalConnIdx,
[[maybe_unused]] const int openConnIdx) const
{
// Simple approximation: Mixture density at reservoir connection is
// mixture density at connection's segment.
const auto segNum = this->wellEcl()
.getConnections()[globalConnIdx].segment();
const auto segIdx = this->wellEcl()
.getSegments().segmentNumberToIndex(segNum);
return this->segments_.density(segIdx).value();
}
template<typename TypeTag>
void
MultisegmentWell<TypeTag>::

View File

@ -185,6 +185,9 @@ namespace Opm
WellState& well_state,
DeferredLogger& deferred_logger) const override;
virtual double connectionDensity(const int globalConnIdx,
const int openConnIdx) const override;
virtual void addWellContributions(SparseMatrixAdapter& mat) const override;
virtual void addWellPressureEquations(PressureMatrix& mat,

View File

@ -73,7 +73,19 @@ public:
//! \brief Returns density for first perforation.
Scalar rho() const
{
return this->perf_densities_.empty() ? 0.0 : perf_densities_[0];
return this->rho(0);
}
//! \brief Returns density for specific perforation/connection.
//!
//! \param[in] i Connection index
//!
//! \return Mixture density at connection \p i.
Scalar rho(const typename std::vector<Scalar>::size_type i) const
{
return (i < this->perf_densities_.size())
? this->perf_densities_[i]
: 0.0;
}
//! \brief Returns pressure drop for a given perforation.

View File

@ -1570,6 +1570,23 @@ namespace Opm
template<typename TypeTag>
double
StandardWell<TypeTag>::
connectionDensity([[maybe_unused]] const int globalConnIdx,
const int openConnIdx) const
{
return (openConnIdx < 0)
? 0.0
: this->connections_.rho(openConnIdx);
}
template<typename TypeTag>
void
StandardWell<TypeTag>::

View File

@ -254,6 +254,9 @@ public:
WellState& well_state,
DeferredLogger& deferred_logger) const = 0;
virtual double connectionDensity(const int globalConnIdx,
const int openConnIdx) const = 0;
/// \brief Wether the Jacobian will also have well contributions in it.
virtual bool jacobianContainsWellContributions() const
{