mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge a706ffb611
into 1e89fe7013
This commit is contained in:
commit
2ba4aa70e1
@ -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>
|
||||
|
@ -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_;
|
||||
|
@ -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,
|
||||
|
@ -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>&, \
|
||||
|
@ -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.);
|
||||
|
@ -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_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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()
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user