This commit is contained in:
Lisa Julia Nebel 2025-02-14 15:01:42 +00:00 committed by GitHub
commit 2ba4aa70e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 111 additions and 89 deletions

View File

@ -63,7 +63,7 @@ MultisegmentWellSegments(const int numSegments,
const int num_perfs_whole_mswell,
WellInterfaceGeneric<Scalar>& well)
: perforations_(numSegments)
, perforation_depth_diffs_(num_perfs_whole_mswell, 0.0)
, global_perforation_depth_diffs_(num_perfs_whole_mswell, 0.0)
, inlets_(well.wellEcl().getSegments().size())
, depth_diffs_(numSegments, 0.0)
, densities_(numSegments, 0.0)
@ -103,7 +103,7 @@ MultisegmentWellSegments(const int numSegments,
perforations_[segment_index].push_back(i_perf_wells);
well.perfDepth()[i_perf_wells] = connection.depth();
const Scalar segment_depth = segment_set[segment_index].depth();
perforation_depth_diffs_[i_perf_wells] = well_.perfDepth()[i_perf_wells] - segment_depth;
global_perforation_depth_diffs_[i_perf_wells] = well_.perfDepth()[i_perf_wells] - segment_depth;
i_perf_wells++;
}
}
@ -344,10 +344,10 @@ getHydroPressureLoss(const int seg,
template<class FluidSystem, class Indices>
typename MultisegmentWellSegments<FluidSystem,Indices>::Scalar
MultisegmentWellSegments<FluidSystem,Indices>::
getPressureDiffSegPerf(const int seg,
const int perf) const
getPressureDiffSegGlobalPerf(const int seg,
const int global_perf_index) const
{
return well_.gravity() * densities_[seg].value() * perforation_depth_diffs_[perf];
return well_.gravity() * densities_[seg].value() * global_perforation_depth_diffs_[global_perf_index];
}
template<class FluidSystem, class Indices>

View File

@ -65,8 +65,8 @@ public:
const int seg_side) const;
//! Pressure difference between segment and perforation.
Scalar getPressureDiffSegPerf(const int seg,
const int perf) const;
Scalar getPressureDiffSegGlobalPerf(const int seg,
const int global_perf_index) const;
EvalWell getSurfaceVolume(const EvalWell& temperature,
const EvalWell& saltConcentration,
@ -128,7 +128,7 @@ public:
Scalar perforation_depth_diff(const int perf) const
{
return perforation_depth_diffs_[perf];
return global_perforation_depth_diffs_[perf];
}
void copyPhaseDensities(const PhaseUsage& pu,
@ -152,7 +152,7 @@ private:
// This vector contains the depth differences for *all* perforations across all processes
// that this well lies on, its size is well.wellEcl().getConnections().size(),
// also it works with *global* perforation indices!
std::vector<Scalar> perforation_depth_diffs_;
std::vector<Scalar> global_perforation_depth_diffs_;
// the inlet segments for each segment. It is for convenience and efficiency reason
std::vector<std::vector<int>> inlets_;

View File

@ -135,8 +135,8 @@ namespace Opm
this->initMatrixAndVectors();
// calculate the depth difference between the perforations and the perforated grid block
for (int local_perf_index = 0; local_perf_index < this->number_of_perforations_; ++local_perf_index) {
// This variable loops over the number_of_perforations_ of *this* process, hence it is *local*.
for (int local_perf_index = 0; local_perf_index < this->local_number_of_perforations_; ++local_perf_index) {
// This variable loops over the local_number_of_perforations_ of *this* process, hence it is *local*.
const int cell_idx = this->well_cells_[local_perf_index];
// Here we need to access the perf_depth_ at the global perforation index though!
this->cell_perforation_depth_diffs_[local_perf_index] = depth_arg[cell_idx] - this->perf_depth_[this->pw_info_.localToGlobal(local_perf_index)];
@ -617,12 +617,15 @@ namespace Opm
MultisegmentWell<TypeTag>::
computePerfCellPressDiffs(const Simulator& simulator)
{
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
// We call this function on every process for the local_number_of_perforations_ on that process
// Each process updates the pressure for his perforations
for (int local_perf_index = 0; local_perf_index < this->local_number_of_perforations_; ++local_perf_index) {
// This variable loops over the local_number_of_perforations_ of *this* process, hence it is *local*.
std::vector<Scalar> kr(this->number_of_phases_, 0.0);
std::vector<Scalar> density(this->number_of_phases_, 0.0);
const int cell_idx = this->well_cells_[perf];
const int cell_idx = this->well_cells_[local_perf_index];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
const auto& fs = intQuants.fluidState();
@ -659,7 +662,7 @@ namespace Opm
}
average_density /= sum_kr;
this->cell_perforation_pressure_diffs_[perf] = this->gravity_ * average_density * this->cell_perforation_depth_diffs_[perf];
this->cell_perforation_pressure_diffs_[local_perf_index] = this->gravity_ * average_density * this->cell_perforation_depth_diffs_[local_perf_index];
}
}
@ -749,9 +752,9 @@ namespace Opm
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const
{
auto fluidState = [&simulator, this](const int perf)
auto fluidState = [&simulator, this](const int local_perf_index)
{
const auto cell_idx = this->well_cells_[perf];
const auto cell_idx = this->well_cells_[local_perf_index];
return simulator.model()
.intensiveQuantities(cell_idx, /*timeIdx=*/ 0).fluidState();
};
@ -789,7 +792,7 @@ namespace Opm
// The subsetPerfID loops over 0 .. this->perf_data_->size().
// *(this->perf_data_) contains info about the local processes only,
// hence subsetPerfID is a local perf id and we can call getMobility
// directly with that.
// as well as fluidState directly with that.
getMobility(simulator, static_cast<int>(subsetPerfID), mob, deferred_logger);
const auto& fs = fluidState(subsetPerfID);
@ -815,7 +818,7 @@ namespace Opm
comm.sum(wellPI, np);
}
assert (static_cast<int>(subsetPerfID) == this->number_of_perforations_ &&
assert (static_cast<int>(subsetPerfID) == this->local_number_of_perforations_ &&
"Internal logic error in processing connections for PI/II");
}
@ -1113,13 +1116,24 @@ namespace Opm
// TODO: later to investigate how to handle the pvt region
int pvt_region_index;
{
// using the first perforated cell
const int cell_idx = this->well_cells_[0];
// using the first perforated cell, so we look for global index 0
int cell_idx = this->well_cells_[0];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/0);
const auto& fs = intQuants.fluidState();
temperature.setValue(fs.temperature(FluidSystem::oilPhaseIdx).value());
saltConcentration = this->extendEval(fs.saltConcentration());
// The following broadcast calls are neccessary to ensure that processes that do *not* contain
// the first perforation get the correct temperature, saltConcentration and pvt_region_index
auto fsTemperature = fs.temperature(FluidSystem::oilPhaseIdx).value();
fsTemperature = this->pw_info_.broadcastFirstPerforationValue(fsTemperature);
temperature.setValue(fsTemperature);
auto fsSaltConcentration = fs.saltConcentration();
fsSaltConcentration = this->pw_info_.broadcastFirstPerforationValue(fsSaltConcentration);
saltConcentration = this->extendEval(fsSaltConcentration);
pvt_region_index = fs.pvtRegionIndex();
pvt_region_index = this->pw_info_.broadcastFirstPerforationValue(pvt_region_index);
}
this->segments_.computeFluidProperties(temperature,
@ -1276,7 +1290,7 @@ namespace Opm
const auto& int_quantities = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
const auto& fs = int_quantities.fluidState();
// pressure difference between the segment and the perforation
const Scalar perf_seg_press_diff = this->segments_.getPressureDiffSegPerf(seg, perf);
const Scalar perf_seg_press_diff = this->segments_.getPressureDiffSegGlobalPerf(seg, perf);
// pressure difference between the perforation and the grid cell
const Scalar cell_perf_press_diff = this->cell_perforation_pressure_diffs_[local_perf_index];
const Scalar pressure_cell = this->getPerfCellPressure(fs).value();
@ -1644,7 +1658,6 @@ namespace Opm
Scalar relaxation_factor = 1.;
const Scalar min_relaxation_factor = 0.6;
bool converged = false;
[[maybe_unused]] int stagnate_count = 0;
bool relax_convergence = false;
this->regularize_ = false;
const auto& summary_state = simulator.vanguard().summaryState();
@ -1740,21 +1753,6 @@ namespace Opm
if (is_oscillate || is_stagnate) {
// HACK!
std::string message;
if (relaxation_factor == min_relaxation_factor) {
++stagnate_count;
if (false) { // this disables the usage of the relaxed tolerance
fmt::format_to(std::back_inserter(message), " Well {} observes severe stagnation and/or oscillation."
" We relax the tolerance and check for convergence. \n", this->name());
const auto reportStag = getWellConvergence(simulator, well_state, Base::B_avg_,
deferred_logger, true);
if (reportStag.converged()) {
converged = true;
fmt::format_to(std::back_inserter(message), " Well {} manages to get converged with relaxed tolerances in {} inner iterations", this->name(), it);
deferred_logger.debug(message);
return converged;
}
}
}
// a factor value to reduce the relaxation_factor
constexpr Scalar reduction_mutliplier = 0.9;
@ -2008,7 +2006,7 @@ namespace Opm
const auto& fs = intQuants.fluidState();
// pressure difference between the segment and the perforation
const EvalWell perf_seg_press_diff = this->segments_.getPressureDiffSegPerf(seg, perf);
const EvalWell perf_seg_press_diff = this->segments_.getPressureDiffSegGlobalPerf(seg, perf);
// pressure difference between the perforation and the grid cell
const Scalar cell_perf_press_diff = this->cell_perforation_pressure_diffs_[local_perf_index];
@ -2061,14 +2059,24 @@ namespace Opm
EvalWell saltConcentration;
int pvt_region_index;
{
// using the pvt region of first perforated cell
// TODO: it should be a member of the WellInterface, initialized properly
const int cell_idx = this->well_cells_[0];
// using the pvt region of first perforated cell, so we look for global index 0
int cell_idx = this->well_cells_[0];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/0);
const auto& fs = intQuants.fluidState();
temperature.setValue(fs.temperature(FluidSystem::oilPhaseIdx).value());
saltConcentration = this->extendEval(fs.saltConcentration());
// The following broadcast calls are neccessary to ensure that processes that do *not* contain
// the first perforation get the correct temperature, saltConcentration and pvt_region_index
auto fsTemperature = fs.temperature(FluidSystem::oilPhaseIdx).value();
fsTemperature = this->pw_info_.broadcastFirstPerforationValue(fsTemperature);
temperature.setValue(fsTemperature);
auto fsSaltConcentration = fs.saltConcentration();
fsSaltConcentration = this->pw_info_.broadcastFirstPerforationValue(fsSaltConcentration);
saltConcentration = this->extendEval(fsSaltConcentration);
pvt_region_index = fs.pvtRegionIndex();
pvt_region_index = this->pw_info_.broadcastFirstPerforationValue(pvt_region_index);
}
return this->segments_.getSurfaceVolume(temperature,

View File

@ -22,6 +22,7 @@
#include <opm/common/ErrorMacros.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/material/densead/Evaluation.hpp>
#include <fmt/format.h>
#include <cassert>
@ -771,6 +772,11 @@ checkAllConnectionsFound()
template<class Scalar> using dIter = typename std::vector<Scalar>::iterator;
template<class Scalar> using cdIter = typename std::vector<Scalar>::const_iterator;
#define INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, DIM) \
template Opm::DenseAd::Evaluation<T, DIM, 0u> Opm::ParallelWellInfo<T>:: \
broadcastFirstPerforationValue<Opm::DenseAd::Evaluation<T, DIM, 0u>> \
(Opm::DenseAd::Evaluation<T, DIM, 0u> const&) const;
#define INSTANTIATE_TYPE(T) \
template class CheckDistributedWellConnections<T>; \
template class CommunicateAboveBelow<T>; \
@ -780,10 +786,16 @@ template<class Scalar> using cdIter = typename std::vector<Scalar>::const_iterat
ParallelWellInfo<T>::sumPerfValues<cdIter<T>>(cdIter<T>,cdIter<T>) const; \
template typename dIter<T>::value_type \
ParallelWellInfo<T>::sumPerfValues<dIter<T>>(dIter<T>,dIter<T>) const; \
template int ParallelWellInfo<T>:: \
template int ParallelWellInfo<T>:: \
broadcastFirstPerforationValue<int>(const int&) const; \
template T ParallelWellInfo<T>:: \
template T ParallelWellInfo<T>:: \
broadcastFirstPerforationValue<T>(const T&) const; \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 1) \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 2) \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 3) \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 4) \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 5) \
INSTANTIATE_BROADCAST_FIRST_PERF_DENSEAD_EVALUATION(T, 6) \
template void CommunicateAboveBelow<T>:: \
partialSumPerfValues<dIter<T>>(dIter<T>, dIter<T>) const; \
template bool operator<(const ParallelWellInfo<T>&, \

View File

@ -396,7 +396,7 @@ namespace Opm
auto& perf_data = ws.perf_data;
auto& perf_rates = perf_data.phase_rates;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
// Calculate perforation quantities.
std::vector<EvalWell> cq_s(this->num_components_, {this->primary_variables_.numWellEq() + Indices::numEq, 0.0});
EvalWell water_flux_s{this->primary_variables_.numWellEq() + Indices::numEq, 0.0};
@ -778,7 +778,7 @@ namespace Opm
std::fill(this->ipr_a_.begin(), this->ipr_a_.end(), 0.);
std::fill(this->ipr_b_.begin(), this->ipr_b_.end(), 0.);
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
std::vector<Scalar> mob(this->num_components_, 0.0);
getMobility(simulator, perf, mob, deferred_logger);
@ -1061,7 +1061,7 @@ namespace Opm
{
bool all_drawdown_wrong_direction = true;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/0);
const auto& fs = intQuants.fluidState();
@ -1308,7 +1308,7 @@ namespace Opm
comm.sum(wellPI, np);
}
assert ((static_cast<int>(subsetPerfID) == this->number_of_perforations_) &&
assert ((static_cast<int>(subsetPerfID) == this->local_number_of_perforations_) &&
"Internal logic error in processing connections for PI/II");
}
@ -1485,7 +1485,7 @@ namespace Opm
const bool allow_cf = this->getAllowCrossFlow();
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
// flux for each perforation
@ -2064,7 +2064,7 @@ namespace Opm
auto& perf_water_throughput = well_state.well(this->index_of_well_)
.perf_data.water_throughput;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const Scalar perf_water_vel =
this->primary_variables_.value(Bhp + 1 + perf);
@ -2129,7 +2129,7 @@ namespace Opm
const auto& perf_data = ws.perf_data;
const auto& perf_water_throughput = perf_data.water_throughput;
const Scalar throughput = perf_water_throughput[perf];
const int pskin_index = Bhp + 1 + this->number_of_perforations_ + perf;
const int pskin_index = Bhp + 1 + this->local_number_of_perforations_ + perf;
EvalWell poly_conc(this->primary_variables_.numWellEq() + Indices::numEq, 0.0);
poly_conc.setValue(this->wpolymer());
@ -2253,7 +2253,7 @@ namespace Opm
};
Scalar max_pressure = 0.0;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& int_quants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
const auto& fs = int_quants.fluidState();
@ -2514,7 +2514,7 @@ namespace Opm
std::vector<Scalar> well_q_s(this->num_components_, 0.);
const EvalWell& bhp = this->primary_variables_.eval(Bhp);
const bool allow_cf = this->getAllowCrossFlow() || openCrossFlowAvoidSingularity(simulator);
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
std::vector<Scalar> mob(this->num_components_, 0.);

View File

@ -94,14 +94,14 @@ WellInterfaceGeneric(const Well& well,
// We do not want to count SHUT perforations here, so
// it would be wrong to use wells.getConnections().size().
// This is the number_of_perforations_ on this process only!
number_of_perforations_ = perf_data.size();
// This is the local_number_of_perforations_ on this process only!
local_number_of_perforations_ = perf_data.size();
// perforations related
{
well_cells_.resize(number_of_perforations_);
well_index_.resize(number_of_perforations_);
saturation_table_number_.resize(number_of_perforations_);
well_cells_.resize(local_number_of_perforations_);
well_index_.resize(local_number_of_perforations_);
saturation_table_number_.resize(local_number_of_perforations_);
int perf = 0;
for (const auto& pd : perf_data) {
well_cells_[perf] = pd.cell_index;
@ -462,7 +462,7 @@ setWellEfficiencyFactor(const Scalar efficiency_factor)
template<class Scalar>
void WellInterfaceGeneric<Scalar>::setRepRadiusPerfLength()
{
const int nperf = number_of_perforations_;
const int nperf = local_number_of_perforations_;
perf_rep_radius_.clear();
perf_length_.clear();
@ -535,7 +535,7 @@ template<class Scalar>
void WellInterfaceGeneric<Scalar>::
updatePerforatedCell(std::vector<bool>& is_cell_perforated)
{
for (int perf_idx = 0; perf_idx < number_of_perforations_; ++perf_idx) {
for (int perf_idx = 0; perf_idx < local_number_of_perforations_; ++perf_idx) {
is_cell_perforated[well_cells_[perf_idx]] = true;
}
}
@ -707,7 +707,7 @@ void WellInterfaceGeneric<Scalar>::addPerforations(const std::vector<RuntimePerf
this->saturation_table_number_
.push_back(this->saturation_table_number_.front());
++this->number_of_perforations_;
++this->local_number_of_perforations_;
}
}
}

View File

@ -129,7 +129,7 @@ public:
int numPhases() const { return number_of_phases_; }
int numPerfs() const { return number_of_perforations_; }
int numPerfs() const { return local_number_of_perforations_; }
Scalar refDepth() const { return ref_depth_; }
@ -328,7 +328,7 @@ protected:
std::vector<Scalar> well_index_;
// number of the perforations for this well on this process
int number_of_perforations_;
int local_number_of_perforations_;
// depth for each perforation
std::vector<Scalar> perf_depth_;

View File

@ -76,7 +76,7 @@ namespace Opm
index_of_well,
perf_data)
{
connectionRates_.resize(this->number_of_perforations_);
connectionRates_.resize(this->local_number_of_perforations_);
if constexpr (has_solvent || has_zFraction) {
if (well.isInjector()) {
@ -934,7 +934,7 @@ namespace Opm
if(!this->isOperableAndSolvable() && !this->wellIsStopped())
return;
for (int perfIdx = 0; perfIdx < this->number_of_perforations_; ++perfIdx) {
for (int perfIdx = 0; perfIdx < this->local_number_of_perforations_; ++perfIdx) {
if (this->cells()[perfIdx] == cellIdx) {
for (int i = 0; i < RateVector::dimension; ++i) {
rates[i] += connectionRates_[perfIdx][i];
@ -947,7 +947,7 @@ namespace Opm
typename WellInterface<TypeTag>::Scalar
WellInterface<TypeTag>::volumetricSurfaceRateForConnection(int cellIdx, int phaseIdx) const
{
for (int perfIdx = 0; perfIdx < this->number_of_perforations_; ++perfIdx) {
for (int perfIdx = 0; perfIdx < this->local_number_of_perforations_; ++perfIdx) {
if (this->cells()[perfIdx] == cellIdx) {
const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx));
return connectionRates_[perfIdx][activeCompIdx].value();
@ -1595,10 +1595,12 @@ namespace Opm
// if we don't have any potentials we weight it using the mobilites
// We only need approximation so we don't bother with the vapporized oil and dissolved gas
Scalar total_tw = 0;
const int nperf = this->number_of_perforations_;
const int nperf = this->local_number_of_perforations_;
for (int perf = 0; perf < nperf; ++perf) {
total_tw += this->well_index_[perf];
}
total_tw = this->parallelWellInfo().communication().sum(total_tw);
for (int perf = 0; perf < nperf; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/0);
@ -1762,7 +1764,7 @@ namespace Opm
auto& d_factor = ws.perf_data.connection_d_factor;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model().intensiveQuantities(cell_idx, /*timeIdx=*/ 0);
@ -1828,7 +1830,7 @@ namespace Opm
auto& tmult = ws.perf_data.connection_compaction_tmult;
auto& ctf = ws.perf_data.connection_transmissibility_factor;
for (int perf = 0; perf < this->number_of_perforations_; ++perf) {
for (int perf = 0; perf < this->local_number_of_perforations_; ++perf) {
const int cell_idx = this->well_cells_[perf];
const auto& intQuants = simulator.model()

View File

@ -231,7 +231,7 @@ template<class Scalar>
void WellState<Scalar>::initSingleWell(const std::vector<Scalar>& cellPressures,
const std::vector<Scalar>& cellTemperatures,
const Well& well,
const std::vector<PerforationData<Scalar>>& well_perf_data,
const std::vector<PerforationData<Scalar>>& well_perf_data, //this variable contains only the perforation data on this process!
const ParallelWellInfo<Scalar>& well_info,
const SummaryState& summary_state)
{
@ -239,6 +239,7 @@ void WellState<Scalar>::initSingleWell(const std::vector<Scalar>& cellPressures,
if (!well_perf_data.empty()) {
pressure_first_connection = cellPressures[well_perf_data[0].cell_index];
}
// The following call is neccessary to ensure that processes that do not contain the first perforation get the correct value
pressure_first_connection = well_info.broadcastFirstPerforationValue(pressure_first_connection);
if (well.isInjector()) {
@ -246,6 +247,7 @@ void WellState<Scalar>::initSingleWell(const std::vector<Scalar>& cellPressures,
if (!well_perf_data.empty()) {
temperature_first_connection = cellTemperatures[well_perf_data[0].cell_index];
}
// The following call is neccessary to ensure that processes that do not contain the first perforation get the correct value
temperature_first_connection = well_info.broadcastFirstPerforationValue(temperature_first_connection);
this->initSingleInjector(well, well_info, pressure_first_connection, temperature_first_connection,
well_perf_data, summary_state);
@ -785,6 +787,10 @@ void WellState<Scalar>::initWellStateMSWell(const std::vector<Well>& wells_ecl,
if (first_perf > -1) { //-1 indicates that the global id is not on this process
segment_pressure[seg] = perf_press[first_perf];
}
// The segment_pressure needs to be communicated right away, otherwise the segment_pressure for the
// case segment_perforations[seg].empty() is incorrect, since it uses the pressure of the outlet segment,
// which is only on one process!
segment_pressure[seg] = ws.parallel_info.get().communication().sum(segment_pressure[seg]);
segment_indices.push_back(seg);
} else {
// seg_press_.push_back(bhp); // may not be a good decision
@ -793,21 +799,6 @@ void WellState<Scalar>::initWellStateMSWell(const std::vector<Well>& wells_ecl,
segment_pressure[seg] = segment_pressure[segment_set.segmentNumberToIndex(outlet_seg)];
}
}
if (ws.parallel_info.get().communication().size() > 1) {
// Communicate the segment_pressure values
std::vector<Scalar> values_to_combine(segment_indices.size(), 0.0);
for (size_t i = 0; i < segment_indices.size(); ++i) {
values_to_combine[i] = segment_pressure[segment_indices[i]];
}
ws.parallel_info.get().communication().sum(values_to_combine.data(), values_to_combine.size());
// Now make segment_pressure equal across all processes
for (size_t i = 0; i < segment_indices.size(); ++i) {
segment_pressure[segment_indices[i]] = values_to_combine[i];
}
}
}
}
}

View File

@ -103,7 +103,7 @@ public:
const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
const int report_step,
const WellState* prevState,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data, //this variable contains only the perforation data on this process!
const SummaryState& summary_state,
const bool enableDistributedWells);
@ -112,7 +112,7 @@ public:
const Schedule& schedule,
const bool handle_ms_well,
const std::size_t numCells,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data, //this variable contains only the perforation data on this process!
const SummaryState& summary_state);
void setCurrentWellRates(const std::string& wellName,

View File

@ -64,6 +64,15 @@ add_test_compare_parallel_simulation(CASENAME msw-3d-two-producers
MPI_PROCS 4
TEST_ARGS --allow-distributed-wells=true)
add_test_compare_parallel_simulation(CASENAME msw-model-1
FILENAME MSW_MODEL_1
DIR model1
SIMULATOR flow_distribute_z
ABS_TOL 1e4 # the absolute tolerance is pretty high here, yet in this case, we are only interested in the relative tolerance
REL_TOL 1e-4
MPI_PROCS 4
TEST_ARGS --allow-distributed-wells=true)
add_test_compare_parallel_simulation(CASENAME spe9group
FILENAME SPE9_CP_GROUP
SIMULATOR flow