23#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
24#include <opm/core/props/phaseUsageFromDeck.hpp>
25#include <opm/grid/utility/cartesianToCompressed.hpp>
27#include <opm/input/eclipse/Units/UnitSystem.hpp>
28#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
29#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
30#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
32#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
33#include <opm/simulators/wells/ParallelPAvgDynamicSourceData.hpp>
34#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
35#include <opm/simulators/wells/VFPProperties.hpp>
36#include <opm/simulators/utils/MPIPacker.hpp>
37#include <opm/simulators/linalg/bda/WellContributions.hpp>
40#include <ebos/eclmpiserializer.hh>
47#include <fmt/format.h>
50 template<
typename TypeTag>
51 BlackoilWellModel<TypeTag>::
52 BlackoilWellModel(Simulator& ebosSimulator,
const PhaseUsage& phase_usage)
53 : BlackoilWellModelGeneric(ebosSimulator.vanguard().schedule(),
54 ebosSimulator.vanguard().summaryState(),
55 ebosSimulator.vanguard().eclState(),
57 ebosSimulator.gridView().comm())
58 , ebosSimulator_(ebosSimulator)
60 terminal_output_ = ((ebosSimulator.gridView().comm().rank() == 0) &&
61 EWOMS_GET_PARAM(TypeTag,
bool, EnableTerminalOutput));
63 local_num_cells_ = ebosSimulator_.gridView().size(0);
66 global_num_cells_ = ebosSimulator_.vanguard().globalNumCells();
69 auto& parallel_wells = ebosSimulator.vanguard().parallelWells();
71 this->parallel_well_info_.reserve(parallel_wells.size());
72 for(
const auto& name_bool : parallel_wells) {
73 this->parallel_well_info_.emplace_back(name_bool, grid().comm());
77 this->alternative_well_rate_init_ =
78 EWOMS_GET_PARAM(TypeTag,
bool, AlternativeWellRateInit);
80 this->wbpCalculationService_
81 .localCellIndex([
this](
const std::size_t globalIndex)
82 {
return this->compressedIndexForInterior(globalIndex); })
83 .evalCellSource([
this](
const int localCell,
84 PAvgDynamicSourceData::SourceDataSpan<double> sourceTerms)
86 using Item = PAvgDynamicSourceData::SourceDataSpan<double>::Item;
88 const auto* intQuants = this->ebosSimulator_.model()
89 .cachedIntensiveQuantities(localCell, 0);
90 const auto& fs = intQuants->fluidState();
92 sourceTerms.set(Item::PoreVol, intQuants->porosity().value() *
93 this->ebosSimulator_.model().dofTotalVolume(localCell));
95 constexpr auto io = FluidSystem::oilPhaseIdx;
96 constexpr auto ig = FluidSystem::gasPhaseIdx;
97 constexpr auto iw = FluidSystem::waterPhaseIdx;
100 const auto haveOil = FluidSystem::phaseIsActive(io);
101 const auto haveGas = FluidSystem::phaseIsActive(ig);
102 const auto haveWat = FluidSystem::phaseIsActive(iw);
104 auto weightedPhaseDensity = [&fs](
const auto ip)
106 return fs.saturation(ip).value() * fs.density(ip).value();
109 if (haveOil) { sourceTerms.set(Item::Pressure, fs.pressure(io).value()); }
110 else if (haveGas) { sourceTerms.set(Item::Pressure, fs.pressure(ig).value()); }
111 else { sourceTerms.set(Item::Pressure, fs.pressure(iw).value()); }
115 if (haveOil) { rho += weightedPhaseDensity(io); }
116 if (haveGas) { rho += weightedPhaseDensity(ig); }
117 if (haveWat) { rho += weightedPhaseDensity(iw); }
119 sourceTerms.set(Item::MixtureDensity, rho);
123 template<
typename TypeTag>
124 BlackoilWellModel<TypeTag>::
125 BlackoilWellModel(Simulator& ebosSimulator) :
126 BlackoilWellModel(ebosSimulator,
phaseUsageFromDeck(ebosSimulator.vanguard().eclState()))
130 template<
typename TypeTag>
132 BlackoilWellModel<TypeTag>::
135 extractLegacyCellPvtRegionIndex_();
136 extractLegacyDepth_();
138 gravity_ = ebosSimulator_.problem().gravity()[2];
140 initial_step_ =
true;
143 ebosSimulator_.model().addAuxiliaryModule(
this);
145 is_cell_perforated_.resize(local_num_cells_,
false);
149 template<
typename TypeTag>
151 BlackoilWellModel<TypeTag>::
152 initWellContainer(
const int reportStepIdx)
154 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
155 + ScheduleEvents::NEW_WELL;
156 const auto& events = schedule()[reportStepIdx].wellgroup_events();
157 for (
auto& wellPtr : this->well_container_) {
158 const bool well_opened_this_step = report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
159 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
160 this->local_num_cells_, this->B_avg_, well_opened_this_step);
165 template<
typename TypeTag>
167 BlackoilWellModel<TypeTag>::
168 addNeighbors(std::vector<NeighborSet>& neighbors)
const
170 if (!param_.matrix_add_well_contributions_) {
175 const auto& schedule_wells = schedule().getWellsatEnd();
178 for (
const auto& well : schedule_wells)
180 std::vector<int> wellCells = this->getCellsForConnections(well);
181 for (
int cellIdx : wellCells) {
182 neighbors[cellIdx].insert(wellCells.begin(),
189 template<
typename TypeTag>
191 BlackoilWellModel<TypeTag>::
192 linearize(SparseMatrixAdapter& jacobian, GlobalEqVector& res)
194 OPM_BEGIN_PARALLEL_TRY_CATCH();
195 for (
const auto& well: well_container_) {
198 if (param_.matrix_add_well_contributions_) {
199 well->addWellContributions(jacobian);
205 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::linearize failed: ",
206 ebosSimulator_.gridView().comm());
210 template<
typename TypeTag>
212 BlackoilWellModel<TypeTag>::
213 linearizeDomain(
const Domain& domain, SparseMatrixAdapter& jacobian, GlobalEqVector& res)
218 for (
const auto& well: well_container_) {
219 if (well_domain_.at(well->name()) == domain.index) {
222 if (param_.matrix_add_well_contributions_) {
223 well->addWellContributions(jacobian);
233 template<
typename TypeTag>
235 BlackoilWellModel<TypeTag>::
236 beginReportStep(
const int timeStepIdx)
238 DeferredLogger local_deferredLogger{};
240 this->report_step_starts_ =
true;
244 const auto enableWellPIScaling =
true;
245 this->initializeLocalWellStructure(timeStepIdx, enableWellPIScaling);
248 this->initializeGroupStructure(timeStepIdx);
250 const auto& comm = this->ebosSimulator_.vanguard().grid().comm();
252 OPM_BEGIN_PARALLEL_TRY_CATCH()
256 this->rateConverter_ = std::make_unique<RateConverterType>
257 (this->phase_usage_, std::vector<int>(this->local_num_cells_, 0));
258 this->rateConverter_->template defineState<ElementContext>(this->ebosSimulator_);
262 const auto& sched_state = this->schedule()[timeStepIdx];
264 this->vfp_properties_ = std::make_unique<VFPProperties>
265 (sched_state.vfpinj(), sched_state.vfpprod(), this->wellState());
268 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
269 "beginReportStep() failed: ",
270 this->terminal_output_, comm)
274 this->commitWGState();
281 template <
typename TypeTag>
289 const auto& comm = this->ebosSimulator_.vanguard().grid().comm();
293 this->local_parallel_well_info_ =
294 this->createLocalParallelWellInfo(this->wells_ecl_);
299 OPM_BEGIN_PARALLEL_TRY_CATCH()
301 this->initializeWellPerfData();
303 this->initializeWBPCalculationService();
305 if (this->param_.use_multisegment_well_ &&
this->anyMSWellOpenLocal()) {
306 this->wellState().initWellStateMSWell(this->wells_ecl_, &this->prevWellState());
309 this->initializeWellProdIndCalculators();
312 .
hasEvent(ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX))
318 "Failed to initialize local well structure: ",
319 this->terminal_output_, comm)
326 template <
typename TypeTag>
333 const auto& comm = this->ebosSimulator_.vanguard().grid().comm();
335 OPM_BEGIN_PARALLEL_TRY_CATCH()
342 this->summaryState(),
349 WellGroupHelpers::setRegionAveragePressureCalculator
353 this->eclState_.fieldProps(),
355 this->regionalAveragePressureCalculator_);
359 "Failed to initialize group structure: ",
360 this->terminal_output_, comm)
368 template<
typename TypeTag>
374 updateAverageFormationFactor();
376 switched_prod_groups_.clear();
377 switched_inj_groups_.clear();
379 this->resetWGState();
382 ebosSimulator_.model().newtonMethod().numIterations());
383 this->wellState().gliftTimeStepInit();
385 OPM_BEGIN_PARALLEL_TRY_CATCH();
394 const Grid& grid = ebosSimulator_.vanguard().grid();
395 wells_active_ = !this->well_container_.empty();
396 wells_active_ = grid.comm().max(wells_active_);
404 std::fill(is_cell_perforated_.begin(), is_cell_perforated_.end(),
false);
405 for (
auto& well : well_container_) {
406 well->updatePerforatedCell(is_cell_perforated_);
410 calculateEfficiencyFactors(reportStepIdx);
412 if constexpr (has_polymer_)
414 if (PolymerModule::hasPlyshlog() || getPropValue<TypeTag, Properties::EnablePolymerMW>() ) {
415 setRepRadiusPerfLength();
420 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"beginTimeStep() failed: ",
421 terminal_output_, ebosSimulator_.vanguard().grid().comm());
423 for (
auto& well : well_container_) {
424 well->setVFPProperties(vfp_properties_.get());
425 well->setGuideRate(&guideRate_);
428 this->updateInjFCMult(local_deferredLogger);
431 for (
auto& well : well_container_) {
432 well->closeCompletions(wellTestState());
438 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
439 if (alternative_well_rate_init_) {
444 for (
auto& well : well_container_) {
445 const bool zero_target = well->stopppedOrZeroRateTarget(summaryState, this->wellState());
446 if (well->isProducer() && !zero_target) {
447 well->updateWellStateRates(ebosSimulator_, this->wellState(), local_deferredLogger);
452 for (
auto& well : well_container_) {
453 if (well->isVFPActive(local_deferredLogger)){
454 well->setPrevSurfaceRates(this->wellState(), this->prevWellState());
460 updateWellPotentials(reportStepIdx,
462 ebosSimulator_.vanguard().summaryConfig(),
463 local_deferredLogger);
464 }
catch ( std::runtime_error& e ) {
465 const std::string msg =
"A zero well potential is returned for output purposes. ";
466 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
470 const auto& comm = ebosSimulator_.vanguard().grid().comm();
471 std::vector<double> pot(numPhases(), 0.0);
472 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
473 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
474 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
476 auto exc_type = ExceptionType::NONE;
478 if (schedule_[reportStepIdx].has_gpmaint()) {
479 for (
auto& calculator : regionalAveragePressureCalculator_) {
480 calculator.second->template defineState<ElementContext>(ebosSimulator_);
482 const double dt = ebosSimulator_.timeStepSize();
483 WellGroupHelpers::updateGpMaintTargetForGroups(fieldGroup,
484 schedule_, regionalAveragePressureCalculator_, reportStepIdx, dt, this->wellState(), this->groupState());
488 for (
auto& well : well_container_) {
489 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
490 + ScheduleEvents::INJECTION_TYPE_CHANGED
491 + ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER
492 + ScheduleEvents::NEW_WELL;
494 const auto& events = schedule()[reportStepIdx].wellgroup_events();
495 const bool event = report_step_starts_ && events.hasEvent(well->name(), effective_events_mask);
496 const bool dyn_status_change = this->wellState().well(well->name()).status
497 != this->prevWellState().well(well->name()).status;
499 if (event || dyn_status_change) {
501 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), local_deferredLogger);
502 well->calculateExplicitQuantities(ebosSimulator_, this->wellState(), local_deferredLogger);
503 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), local_deferredLogger);
504 }
catch (
const std::exception& e) {
505 const std::string msg =
"Compute initial well solution for new well " + well->name() +
" failed. Continue with zero initial rates";
506 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
512 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
514 if (exc_type != ExceptionType::NONE) {
515 const std::string msg =
"Compute initial well solution for new wells failed. Continue with zero initial rates";
516 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
519 logAndCheckForExceptionsAndThrow(local_deferredLogger,
520 exc_type,
"beginTimeStep() failed: " + exc_msg, terminal_output_, comm);
524 template<
typename TypeTag>
526 BlackoilWellModel<TypeTag>::wellTesting(
const int timeStepIdx,
527 const double simulationTime,
528 DeferredLogger& deferred_logger)
530 for (
const std::string& well_name : this->getWellsForTesting(timeStepIdx, simulationTime)) {
531 const Well& wellEcl = schedule().getWell(well_name, timeStepIdx);
532 if (wellEcl.getStatus() == Well::Status::SHUT)
535 WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx, deferred_logger);
537 well->init(&phase_usage_, depth_, gravity_, local_num_cells_, B_avg_,
true);
539 double well_efficiency_factor = wellEcl.getEfficiencyFactor();
540 WellGroupHelpers::accumulateGroupEfficiencyFactor(schedule().getGroup(wellEcl.groupName(), timeStepIdx),
541 schedule(), timeStepIdx, well_efficiency_factor);
543 well->setWellEfficiencyFactor(well_efficiency_factor);
544 well->setVFPProperties(vfp_properties_.get());
545 well->setGuideRate(&guideRate_);
547 well->wellTesting(ebosSimulator_, simulationTime, this->wellState(), this->groupState(), wellTestState(), deferred_logger);
556 template<
typename TypeTag>
558 BlackoilWellModel<TypeTag>::
562 for (
auto&& pinfo : this->local_parallel_well_info_)
573 template<
typename TypeTag>
574 const SimulatorReportSingle&
575 BlackoilWellModel<TypeTag>::
576 lastReport()
const {
return last_report_; }
583 template<
typename TypeTag>
585 BlackoilWellModel<TypeTag>::
586 timeStepSucceeded(
const double simulationTime,
const double dt)
588 this->closed_this_step_.clear();
591 report_step_starts_ =
false;
592 const int reportStepIdx = ebosSimulator_.episodeIndex();
594 DeferredLogger local_deferredLogger;
595 for (
const auto& well : well_container_) {
596 if (getPropValue<TypeTag, Properties::EnablePolymerMW>() && well->isInjector()) {
597 well->updateWaterThroughput(dt, this->wellState());
601 if (Indices::waterEnabled) {
602 this->updateFiltrationParticleVolume(dt, FluidSystem::waterPhaseIdx);
606 this->updateInjMult(local_deferredLogger);
609 for (
const auto& well : well_container_) {
610 well->reportWellSwitching(this->wellState().well(well->indexOfWell()), local_deferredLogger);
613 if (terminal_output_) {
615 for (
const auto& [name, to] : switched_prod_groups_) {
616 const Group::ProductionCMode& oldControl = this->prevWGState().group_state.production_control(name);
617 std::string from = Group::ProductionCMode2String(oldControl);
619 std::string msg =
" Production Group " + name
620 +
" control mode changed from ";
623 local_deferredLogger.info(msg);
626 for (
const auto& [key, to] : switched_inj_groups_) {
627 const std::string& name = key.first;
630 const Group::InjectionCMode& oldControl = this->prevWGState().group_state.injection_control(name, phase);
631 std::string from = Group::InjectionCMode2String(oldControl);
633 std::string msg =
" Injection Group " + name
634 +
" control mode changed from ";
637 local_deferredLogger.info(msg);
643 rateConverter_->template defineState<ElementContext>(ebosSimulator_);
647 updateWellPotentials(reportStepIdx,
649 ebosSimulator_.vanguard().summaryConfig(),
650 local_deferredLogger);
651 }
catch ( std::runtime_error& e ) {
652 const std::string msg =
"A zero well potential is returned for output purposes. ";
653 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
656 updateWellTestState(simulationTime, wellTestState());
659 const Group& fieldGroup = schedule_.getGroup(
"FIELD", reportStepIdx);
661 fieldGroup, simulationTime, ebosSimulator_.episodeIndex(), local_deferredLogger);
662 checkGconsaleLimits(fieldGroup, this->wellState(),
663 ebosSimulator_.episodeIndex(), local_deferredLogger);
665 this->calculateProductivityIndexValues(local_deferredLogger);
667 this->commitWGState();
669 const Opm::Parallel::Communication& comm = grid().comm();
671 if (terminal_output_) {
672 global_deferredLogger.logMessages();
676 this->computeWellTemperature();
680 template<
typename TypeTag>
682 BlackoilWellModel<TypeTag>::
683 computeTotalRatesForDof(RateVector& rate,
684 unsigned elemIdx)
const
688 if (!is_cell_perforated_[elemIdx])
691 for (
const auto& well : well_container_)
692 well->addCellRates(rate, elemIdx);
696 template<
typename TypeTag>
697 template <
class Context>
699 BlackoilWellModel<TypeTag>::
700 computeTotalRatesForDof(RateVector& rate,
701 const Context& context,
703 unsigned timeIdx)
const
706 int elemIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
708 if (!is_cell_perforated_[elemIdx])
711 for (
const auto& well : well_container_)
712 well->addCellRates(rate, elemIdx);
717 template<
typename TypeTag>
719 BlackoilWellModel<TypeTag>::
720 initializeWellState(
const int timeStepIdx)
722 std::vector<double> cellPressures(this->local_num_cells_, 0.0);
723 ElementContext elemCtx(ebosSimulator_);
725 const auto& gridView = ebosSimulator_.vanguard().gridView();
727 OPM_BEGIN_PARALLEL_TRY_CATCH();
728 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
729 elemCtx.updatePrimaryStencil(elem);
730 elemCtx.updatePrimaryIntensiveQuantities(0);
732 const auto& fs = elemCtx.intensiveQuantities(0, 0).fluidState();
734 double& perf_pressure = cellPressures[elemCtx.globalSpaceIndex(0, 0)];
735 if (Indices::oilEnabled) {
736 perf_pressure = fs.pressure(FluidSystem::oilPhaseIdx).value();
737 }
else if (Indices::waterEnabled) {
738 perf_pressure = fs.pressure(FluidSystem::waterPhaseIdx).value();
740 perf_pressure = fs.pressure(FluidSystem::gasPhaseIdx).value();
743 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::initializeWellState() failed: ", ebosSimulator_.vanguard().grid().comm());
745 this->wellState().init(cellPressures, schedule(), wells_ecl_, local_parallel_well_info_, timeStepIdx,
746 &this->prevWellState(), well_perf_data_,
747 this->summaryState());
754 template<
typename TypeTag>
756 BlackoilWellModel<TypeTag>::
757 createWellContainer(
const int time_step)
759 DeferredLogger local_deferredLogger;
761 const int nw = numLocalWells();
763 well_container_.clear();
766 well_container_.reserve(nw);
768 for (
int w = 0; w < nw; ++w) {
769 const Well& well_ecl = wells_ecl_[w];
771 if (!well_ecl.hasConnections()) {
776 const std::string& well_name = well_ecl.name();
777 const auto well_status = this->schedule()
778 .getWell(well_name, time_step).getStatus();
780 if ((well_ecl.getStatus() == Well::Status::SHUT) ||
781 (well_status == Well::Status::SHUT))
784 if (well_ecl.getStatus() != Well::Status::SHUT) {
785 this->closed_this_step_.insert(well_name);
786 this->wellState().shutWell(w);
793 if (this->wellTestState().well_is_closed(well_name)) {
796 auto& events = this->wellState().well(w).events;
797 if (events.hasEvent(WellState::event_mask)) {
798 if (wellTestState().lastTestTime(well_name) == ebosSimulator_.time()) {
803 events.clearEvent(WellState::event_mask);
805 wellTestState().open_well(well_name);
806 wellTestState().open_completions(well_name);
813 bool wellIsStopped =
false;
814 if (wellTestState().well_is_closed(well_name))
816 if (well_ecl.getAutomaticShutIn()) {
818 this->wellState().shutWell(w);
821 if (!well_ecl.getAllowCrossFlow()) {
824 this->wellState().shutWell(w);
828 this->wellState().stopWell(w);
829 wellIsStopped =
true;
835 if (!well_ecl.getAllowCrossFlow() && well_ecl.isProducer() && well_ecl.predictionMode()) {
836 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
837 const auto prod_controls = well_ecl.productionControls(summaryState);
839 auto is_zero = [](
const double x)
841 return std::isfinite(x) && !std::isnormal(x);
844 bool zero_rate_control =
false;
845 switch (prod_controls.cmode) {
846 case Well::ProducerCMode::ORAT:
847 zero_rate_control = is_zero(prod_controls.oil_rate);
850 case Well::ProducerCMode::WRAT:
851 zero_rate_control = is_zero(prod_controls.water_rate);
854 case Well::ProducerCMode::GRAT:
855 zero_rate_control = is_zero(prod_controls.gas_rate);
858 case Well::ProducerCMode::LRAT:
859 zero_rate_control = is_zero(prod_controls.liquid_rate);
862 case Well::ProducerCMode::RESV:
863 zero_rate_control = is_zero(prod_controls.resv_rate);
867 zero_rate_control =
false;
871 if (zero_rate_control) {
873 local_deferredLogger.info(
" Well shut due to zero rate control and disallowing crossflow: " + well_ecl.name());
874 this->wellState().shutWell(w);
879 if (well_status == Well::Status::STOP) {
880 this->wellState().stopWell(w);
881 wellIsStopped =
true;
884 well_container_.emplace_back(this->createWellPointer(w, time_step));
887 well_container_.back()->stopWell();
893 const Opm::Parallel::Communication& comm = grid().comm();
895 if (terminal_output_) {
896 global_deferredLogger.logMessages();
899 well_container_generic_.clear();
900 for (
auto& w : well_container_)
901 well_container_generic_.push_back(w.get());
903 const auto& network = schedule()[time_step].network();
904 if (network.active() && !this->node_pressures_.empty()) {
905 for (
auto& well: well_container_generic_) {
909 if (well->isProducer()) {
910 const auto it = node_pressures_.find(well->wellEcl().groupName());
911 if (it != node_pressures_.end()) {
914 const double nodal_pressure = it->second;
915 well->setDynamicThpLimit(nodal_pressure);
921 this->registerOpenWellsForWBPCalculation();
928 template <
typename TypeTag>
929 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
930 BlackoilWellModel<TypeTag>::
931 createWellPointer(
const int wellID,
const int time_step)
const
933 const auto is_multiseg = this->wells_ecl_[wellID].isMultiSegment();
935 if (! (this->param_.use_multisegment_well_ && is_multiseg)) {
936 return this->
template createTypedWellPointer<StandardWell<TypeTag>>(wellID, time_step);
939 return this->
template createTypedWellPointer<MultisegmentWell<TypeTag>>(wellID, time_step);
947 template <
typename TypeTag>
948 template <
typename WellType>
949 std::unique_ptr<WellType>
950 BlackoilWellModel<TypeTag>::
951 createTypedWellPointer(
const int wellID,
const int time_step)
const
954 const auto& perf_data = this->well_perf_data_[wellID];
957 const auto pvtreg = perf_data.empty()
958 ? 0 : pvt_region_idx_[perf_data.front().cell_index];
960 const auto& parallel_well_info = this->local_parallel_well_info_[wellID].get();
961 const auto global_pvtreg = parallel_well_info.broadcastFirstPerforationValue(pvtreg);
963 return std::make_unique<WellType>(this->wells_ecl_[wellID],
967 *this->rateConverter_,
969 this->numComponents(),
979 template<
typename TypeTag>
980 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
981 BlackoilWellModel<TypeTag>::
982 createWellForWellTest(
const std::string& well_name,
983 const int report_step,
984 DeferredLogger& deferred_logger)
const
987 const int nw_wells_ecl = wells_ecl_.size();
988 int index_well_ecl = 0;
989 for (; index_well_ecl < nw_wells_ecl; ++index_well_ecl) {
990 if (well_name == wells_ecl_[index_well_ecl].name()) {
995 if (index_well_ecl == nw_wells_ecl) {
996 OPM_DEFLOG_THROW(std::logic_error,
997 fmt::format(
"Could not find well {} in wells_ecl ", well_name),
1001 return this->createWellPointer(index_well_ecl, report_step);
1006 template<
typename TypeTag>
1008 BlackoilWellModel<TypeTag>::
1009 balanceNetwork(DeferredLogger& deferred_logger) {
1010 const double dt = this->ebosSimulator_.timeStepSize();
1012 auto& well_state = this->wellState();
1013 constexpr std::size_t max_iter = 100;
1014 bool converged =
false;
1015 std::size_t iter = 0;
1016 bool changed_well_group =
false;
1018 changed_well_group = updateWellControlsAndNetwork(
true, dt, deferred_logger);
1019 assembleWellEqWithoutIteration(dt, deferred_logger);
1020 converged = this->getWellConvergence(this->B_avg_,
true).converged() && !changed_well_group;
1025 for (
auto& well : this->well_container_) {
1026 const auto& summary_state = this->ebosSimulator_.vanguard().summaryState();
1027 well->solveEqAndUpdateWellState(summary_state, well_state, deferred_logger);
1029 this->initPrimaryVariablesEvaluation();
1030 }
while (iter < max_iter);
1033 const std::string msg = fmt::format(
"balanceNetwork did not get converged with {} iterations, and unconverged "
1034 "network balance result will be used", max_iter);
1035 deferred_logger.warning(msg);
1037 const std::string msg = fmt::format(
"balanceNetwork get converged with {} iterations", iter);
1038 deferred_logger.debug(msg);
1045 template<
typename TypeTag>
1047 BlackoilWellModel<TypeTag>::
1048 assemble(
const int iterationIdx,
1052 DeferredLogger local_deferredLogger;
1053 if (this->glift_debug) {
1054 const std::string msg = fmt::format(
1055 "assemble() : iteration {}" , iterationIdx);
1056 gliftDebug(msg, local_deferredLogger);
1058 last_report_ = SimulatorReportSingle();
1059 Dune::Timer perfTimer;
1063 const int episodeIdx = ebosSimulator_.episodeIndex();
1064 const auto& network = schedule()[episodeIdx].network();
1065 if ( !wellsActive() && !network.active() ) {
1070 if (iterationIdx == 0 && wellsActive()) {
1075 OPM_BEGIN_PARALLEL_TRY_CATCH();
1077 calculateExplicitQuantities(local_deferredLogger);
1078 prepareTimeStep(local_deferredLogger);
1080 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
1081 "assemble() failed (It=0): ",
1082 terminal_output_, grid().comm());
1085 const bool well_group_control_changed = updateWellControlsAndNetwork(
false, dt, local_deferredLogger);
1089 if ( ! wellsActive() ) {
1093 assembleWellEqWithoutIteration(dt, local_deferredLogger);
1097 last_report_.well_group_control_changed = well_group_control_changed;
1098 last_report_.assemble_time_well += perfTimer.stop();
1104 template<
typename TypeTag>
1106 BlackoilWellModel<TypeTag>::
1107 updateWellControlsAndNetwork(
const bool mandatory_network_balance,
const double dt, DeferredLogger& local_deferredLogger)
1110 bool do_network_update =
true;
1111 bool well_group_control_changed =
false;
1113 const std::size_t iteration_to_relax = param_.network_max_strict_iterations_;
1115 const std::size_t max_iteration = param_.network_max_iterations_;
1116 std::size_t network_update_iteration = 0;
1117 while (do_network_update) {
1118 if (terminal_output_ && (network_update_iteration == iteration_to_relax) ) {
1119 local_deferredLogger.info(
" we begin using relaxed tolerance for network update now after " + std::to_string(iteration_to_relax) +
" iterations ");
1121 const bool relax_network_balance = network_update_iteration >= iteration_to_relax;
1122 std::tie(do_network_update, well_group_control_changed) =
1123 updateWellControlsAndNetworkIteration(mandatory_network_balance, relax_network_balance, dt,local_deferredLogger);
1124 ++network_update_iteration;
1126 if (network_update_iteration >= max_iteration ) {
1127 if (terminal_output_) {
1128 local_deferredLogger.info(
"maximum of " + std::to_string(max_iteration) +
" iterations has been used, we stop the network update now. "
1129 "The simulation will continue with unconverged network results");
1134 return well_group_control_changed;
1140 template<
typename TypeTag>
1141 std::pair<bool, bool>
1142 BlackoilWellModel<TypeTag>::
1143 updateWellControlsAndNetworkIteration(
const bool mandatory_network_balance,
1144 const bool relax_network_tolerance,
1146 DeferredLogger& local_deferredLogger)
1148 auto [well_group_control_changed, more_network_update] =
1149 updateWellControls(mandatory_network_balance, local_deferredLogger, relax_network_tolerance);
1151 bool alq_updated =
false;
1152 OPM_BEGIN_PARALLEL_TRY_CATCH();
1155 initPrimaryVariablesEvaluation();
1157 alq_updated = maybeDoGasLiftOptimize(local_deferredLogger);
1159 prepareWellsBeforeAssembling(dt, local_deferredLogger);
1161 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"updateWellControlsAndNetworkIteration() failed: ",
1162 terminal_output_, grid().comm());
1165 const int reportStepIdx = ebosSimulator_.episodeIndex();
1166 if (alq_updated || BlackoilWellModelGuideRates(*this).
1167 guideRateUpdateIsNeeded(reportStepIdx)) {
1168 const double simulationTime = ebosSimulator_.time();
1169 const auto& comm = ebosSimulator_.vanguard().grid().comm();
1170 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
1171 std::vector<double> pot(numPhases(), 0.0);
1172 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
1173 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
1174 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
1178 return {more_network_update, well_group_control_changed};
1183 template<
typename TypeTag>
1185 BlackoilWellModel<TypeTag>::
1186 assembleDomain([[maybe_unused]]
const int iterationIdx,
1188 const Domain& domain)
1190 last_report_ = SimulatorReportSingle();
1191 Dune::Timer perfTimer;
1195 const int episodeIdx = ebosSimulator_.episodeIndex();
1196 const auto& network = schedule()[episodeIdx].network();
1197 if ( !wellsActive() && !network.active() ) {
1207 DeferredLogger local_deferredLogger;
1208 updateWellControlsDomain(local_deferredLogger, domain);
1209 initPrimaryVariablesEvaluationDomain(domain);
1210 assembleWellEqDomain(dt, domain, local_deferredLogger);
1214 if (terminal_output_) {
1215 local_deferredLogger.logMessages();
1218 last_report_.converged =
true;
1219 last_report_.assemble_time_well += perfTimer.stop();
1223 template<
typename TypeTag>
1225 BlackoilWellModel<TypeTag>::
1226 maybeDoGasLiftOptimize(DeferredLogger& deferred_logger)
1228 bool do_glift_optimization =
false;
1229 int num_wells_changed = 0;
1230 const double simulation_time = ebosSimulator_.time();
1231 const double min_wait = ebosSimulator_.vanguard().schedule().glo(ebosSimulator_.episodeIndex()).min_wait();
1236 if ( simulation_time == last_glift_opt_time_ || simulation_time >= (last_glift_opt_time_ + min_wait)) {
1237 do_glift_optimization =
true;
1238 last_glift_opt_time_ = simulation_time;
1241 if (do_glift_optimization) {
1242 GLiftOptWells glift_wells;
1243 GLiftProdWells prod_wells;
1244 GLiftWellStateMap state_map;
1252 GLiftEclWells ecl_well_map;
1253 initGliftEclWellMap(ecl_well_map);
1254 GasLiftGroupInfo group_info {
1256 ebosSimulator_.vanguard().schedule(),
1257 ebosSimulator_.vanguard().summaryState(),
1258 ebosSimulator_.episodeIndex(),
1259 ebosSimulator_.model().newtonMethod().numIterations(),
1264 ebosSimulator_.vanguard().grid().comm(),
1267 group_info.initialize();
1268 gasLiftOptimizationStage1(
1269 deferred_logger, prod_wells, glift_wells, group_info, state_map);
1270 gasLiftOptimizationStage2(
1271 deferred_logger, prod_wells, glift_wells, group_info, state_map,
1272 ebosSimulator_.episodeIndex());
1273 if (this->glift_debug) gliftDebugShowALQ(deferred_logger);
1274 num_wells_changed = glift_wells.size();
1276 num_wells_changed = this->comm_.sum(num_wells_changed);
1277 return num_wells_changed > 0;
1280 template<
typename TypeTag>
1282 BlackoilWellModel<TypeTag>::
1283 gasLiftOptimizationStage1(DeferredLogger& deferred_logger,
1284 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
1285 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map)
1287 auto comm = ebosSimulator_.vanguard().grid().comm();
1288 int num_procs = comm.size();
1314 for (
int i = 0; i< num_procs; i++) {
1315 int num_rates_to_sync = 0;
1316 GLiftSyncGroups groups_to_sync;
1317 if (comm.rank() == i) {
1319 for (
const auto& well : well_container_) {
1321 if (group_info.hasWell(well->name())) {
1322 gasLiftOptimizationStage1SingleWell(
1323 well.get(), deferred_logger, prod_wells, glift_wells,
1324 group_info, state_map, groups_to_sync
1328 num_rates_to_sync = groups_to_sync.size();
1330 num_rates_to_sync = comm.sum(num_rates_to_sync);
1331 if (num_rates_to_sync > 0) {
1332 std::vector<int> group_indexes;
1333 group_indexes.reserve(num_rates_to_sync);
1334 std::vector<double> group_alq_rates;
1335 group_alq_rates.reserve(num_rates_to_sync);
1336 std::vector<double> group_oil_rates;
1337 group_oil_rates.reserve(num_rates_to_sync);
1338 std::vector<double> group_gas_rates;
1339 group_gas_rates.reserve(num_rates_to_sync);
1340 std::vector<double> group_water_rates;
1341 group_water_rates.reserve(num_rates_to_sync);
1342 if (comm.rank() == i) {
1343 for (
auto idx : groups_to_sync) {
1344 auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
1345 group_indexes.push_back(idx);
1346 group_oil_rates.push_back(oil_rate);
1347 group_gas_rates.push_back(gas_rate);
1348 group_water_rates.push_back(water_rate);
1349 group_alq_rates.push_back(alq);
1352 group_indexes.resize(num_rates_to_sync);
1353 group_oil_rates.resize(num_rates_to_sync);
1354 group_gas_rates.resize(num_rates_to_sync);
1355 group_water_rates.resize(num_rates_to_sync);
1356 group_alq_rates.resize(num_rates_to_sync);
1359 EclMpiSerializer ser(comm);
1360 ser.broadcast(i, group_indexes, group_oil_rates,
1361 group_gas_rates, group_water_rates, group_alq_rates);
1363 if (comm.rank() != i) {
1364 for (
int j=0; j<num_rates_to_sync; j++) {
1365 group_info.updateRate(group_indexes[j],
1366 group_oil_rates[j], group_gas_rates[j], group_water_rates[j], group_alq_rates[j]);
1369 if (this->glift_debug) {
1371 if (comm.rank() == i) {
1372 counter = this->wellState().gliftGetDebugCounter();
1374 counter = comm.sum(counter);
1375 if (comm.rank() != i) {
1376 this->wellState().gliftSetDebugCounter(counter);
1386 template<
typename TypeTag>
1388 BlackoilWellModel<TypeTag>::
1389 gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag> *well,
1390 DeferredLogger& deferred_logger,
1391 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
1392 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map,
1393 GLiftSyncGroups& sync_groups)
1395 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1396 std::unique_ptr<GasLiftSingleWell> glift
1397 = std::make_unique<GasLiftSingleWell>(
1398 *well, ebosSimulator_, summary_state,
1399 deferred_logger, this->wellState(), this->groupState(),
1400 group_info, sync_groups, this->comm_, this->glift_debug);
1401 auto state = glift->runOptimize(
1402 ebosSimulator_.model().newtonMethod().numIterations());
1404 state_map.insert({well->name(), std::move(state)});
1405 glift_wells.insert({well->name(), std::move(glift)});
1408 prod_wells.insert({well->name(), well});
1412 template<
typename TypeTag>
1414 BlackoilWellModel<TypeTag>::
1415 initGliftEclWellMap(GLiftEclWells &ecl_well_map)
1417 for (
const auto& well: well_container_ ) {
1418 ecl_well_map.try_emplace(
1419 well->name(), &(well->wellEcl()), well->indexOfWell());
1424 template<
typename TypeTag>
1426 BlackoilWellModel<TypeTag>::
1427 assembleWellEq(
const double dt, DeferredLogger& deferred_logger)
1429 for (
auto& well : well_container_) {
1430 well->assembleWellEq(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger);
1435 template<
typename TypeTag>
1437 BlackoilWellModel<TypeTag>::
1438 assembleWellEqDomain(
const double dt,
const Domain& domain, DeferredLogger& deferred_logger)
1440 for (
auto& well : well_container_) {
1441 if (well_domain_.at(well->name()) == domain.index) {
1442 well->assembleWellEq(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger);
1448 template<
typename TypeTag>
1450 BlackoilWellModel<TypeTag>::
1451 prepareWellsBeforeAssembling(
const double dt, DeferredLogger& deferred_logger)
1453 for (
auto& well : well_container_) {
1454 well->prepareWellBeforeAssembling(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger);
1459 template<
typename TypeTag>
1461 BlackoilWellModel<TypeTag>::
1462 assembleWellEqWithoutIteration(
const double dt, DeferredLogger& deferred_logger)
1464 for (
auto& well: well_container_) {
1465 well->assembleWellEqWithoutIteration(ebosSimulator_, dt, this->wellState(), this->groupState(),
1471 template<
typename TypeTag>
1473 BlackoilWellModel<TypeTag>::
1474 apply(BVector& r)
const
1476 for (
auto& well : well_container_) {
1483 template<
typename TypeTag>
1485 BlackoilWellModel<TypeTag>::
1486 apply(
const BVector& x, BVector& Ax)
const
1488 for (
auto& well : well_container_) {
1493 template<
typename TypeTag>
1495 BlackoilWellModel<TypeTag>::
1496 getWellContributions(WellContributions& wellContribs)
const
1499 wellContribs.setBlockSize(StandardWell<TypeTag>::Indices::numEq, StandardWell<TypeTag>::numStaticWellEq);
1501 for(
unsigned int i = 0; i < well_container_.size(); i++){
1502 auto& well = well_container_[i];
1503 std::shared_ptr<StandardWell<TypeTag> > derived = std::dynamic_pointer_cast<StandardWell<TypeTag> >(well);
1505 wellContribs.addNumBlocks(derived->linSys().getNumBlocks());
1510 wellContribs.alloc();
1512 for(
unsigned int i = 0; i < well_container_.size(); i++){
1513 auto& well = well_container_[i];
1515 auto derived_std = std::dynamic_pointer_cast<StandardWell<TypeTag>>(well);
1517 derived_std->linSys().extract(derived_std->numStaticWellEq, wellContribs);
1519 auto derived_ms = std::dynamic_pointer_cast<MultisegmentWell<TypeTag> >(well);
1521 derived_ms->linSys().extract(wellContribs);
1523 OpmLog::warning(
"Warning unknown type of well");
1530 template<
typename TypeTag>
1532 BlackoilWellModel<TypeTag>::
1533 applyScaleAdd(
const Scalar alpha,
const BVector& x, BVector& Ax)
const
1535 if (this->well_container_.empty()) {
1539 if( scaleAddRes_.size() != Ax.size() ) {
1540 scaleAddRes_.resize( Ax.size() );
1545 apply( x, scaleAddRes_ );
1547 Ax.axpy( alpha, scaleAddRes_ );
1550 template<
typename TypeTag>
1552 BlackoilWellModel<TypeTag>::
1553 addWellContributions(SparseMatrixAdapter& jacobian)
const
1555 for (
const auto& well: well_container_ ) {
1556 well->addWellContributions(jacobian);
1560 template<
typename TypeTag>
1562 BlackoilWellModel<TypeTag>::
1563 addWellPressureEquations(PressureMatrix& jacobian,
const BVector& weights,
const bool use_well_weights)
const
1565 int nw = this->numLocalWellsEnd();
1566 int rdofs = local_num_cells_;
1567 for (
int i = 0; i < nw; i++ ){
1568 int wdof = rdofs + i;
1569 jacobian[wdof][wdof] = 1.0;
1572 for (
const auto& well : well_container_ ) {
1573 well->addWellPressureEquations(jacobian, weights, pressureVarIndex, use_well_weights, this->wellState());
1577 template <
typename TypeTag>
1578 void BlackoilWellModel<TypeTag>::
1579 addReservoirSourceTerms(GlobalEqVector& residual,
1580 std::vector<typename SparseMatrixAdapter::MatrixBlock*>& diagMatAddress)
const
1585 for (
const auto& well : well_container_) {
1586 if (!well->isOperableAndSolvable() && !well->wellIsStopped()) {
1589 const auto& cells = well->cells();
1590 const auto& rates = well->connectionRates();
1591 for (
unsigned perfIdx = 0; perfIdx < rates.size(); ++perfIdx) {
1592 unsigned cellIdx = cells[perfIdx];
1593 auto rate = rates[perfIdx];
1595 VectorBlockType res(0.0);
1596 using MatrixBlockType =
typename SparseMatrixAdapter::MatrixBlock;
1597 MatrixBlockType bMat(0.0);
1598 ebosSimulator_.model().linearizer().setResAndJacobi(res, bMat, rate);
1599 residual[cellIdx] += res;
1600 *diagMatAddress[cellIdx] += bMat;
1606 template<
typename TypeTag>
1608 BlackoilWellModel<TypeTag>::
1609 addWellPressureEquationsStruct(PressureMatrix& jacobian)
const
1611 int nw = this->numLocalWellsEnd();
1612 int rdofs = local_num_cells_;
1613 for(
int i=0; i < nw; i++){
1614 int wdof = rdofs + i;
1615 jacobian.entry(wdof,wdof) = 1.0;
1617 std::vector<std::vector<int>> wellconnections = getMaxWellConnections();
1618 for(
int i=0; i < nw; i++){
1619 const auto& perfcells = wellconnections[i];
1620 for(
int perfcell : perfcells){
1621 int wdof = rdofs + i;
1622 jacobian.entry(wdof,perfcell) = 0.0;
1623 jacobian.entry(perfcell, wdof) = 0.0;
1629 template<
typename TypeTag>
1631 BlackoilWellModel<TypeTag>::
1632 recoverWellSolutionAndUpdateWellState(
const BVector& x)
1634 DeferredLogger local_deferredLogger;
1635 OPM_BEGIN_PARALLEL_TRY_CATCH();
1637 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1638 for (
auto& well : well_container_) {
1639 well->recoverWellSolutionAndUpdateWellState(summary_state, x, this->wellState(), local_deferredLogger);
1642 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
1643 "recoverWellSolutionAndUpdateWellState() failed: ",
1644 terminal_output_, ebosSimulator_.vanguard().grid().comm());
1648 template<
typename TypeTag>
1650 BlackoilWellModel<TypeTag>::
1651 recoverWellSolutionAndUpdateWellStateDomain(
const BVector& x,
const Domain& domain)
1656 DeferredLogger local_deferredLogger;
1657 const auto& summary_state = this->ebosSimulator_.vanguard().summaryState();
1658 for (
auto& well : well_container_) {
1659 if (well_domain_.at(well->name()) == domain.index) {
1660 well->recoverWellSolutionAndUpdateWellState(summary_state, x,
1662 local_deferredLogger);
1667 if (terminal_output_) {
1668 local_deferredLogger.logMessages();
1673 template<
typename TypeTag>
1675 BlackoilWellModel<TypeTag>::
1676 initPrimaryVariablesEvaluation()
const
1678 for (
auto& well : well_container_) {
1679 well->initPrimaryVariablesEvaluation();
1684 template<
typename TypeTag>
1686 BlackoilWellModel<TypeTag>::
1687 initPrimaryVariablesEvaluationDomain(
const Domain& domain)
const
1689 for (
auto& well : well_container_) {
1690 if (well_domain_.at(well->name()) == domain.index) {
1691 well->initPrimaryVariablesEvaluation();
1701 template<
typename TypeTag>
1703 BlackoilWellModel<TypeTag>::
1704 getDomainWellConvergence(
const Domain& domain,
1705 const std::vector<Scalar>& B_avg)
const
1707 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1708 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1709 const bool relax_tolerance = iterationIdx > param_.strict_outer_iter_wells_;
1712 ConvergenceReport local_report;
1713 for (
const auto& well : well_container_) {
1714 if ((well_domain_.at(well->name()) == domain.index)) {
1715 if (well->isOperableAndSolvable() || well->wellIsStopped()) {
1716 local_report += well->getWellConvergence(summary_state,
1719 local_deferredLogger,
1722 ConvergenceReport report;
1723 using CR = ConvergenceReport;
1724 report.setWellFailed({CR::WellFailure::Type::Unsolvable, CR::Severity::Normal, -1, well->name()});
1725 local_report += report;
1740 ConvergenceReport report = local_report;
1741 if (terminal_output_) {
1749 if (terminal_output_) {
1750 for (
const auto& f : report.wellFailures()) {
1751 if (f.severity() == ConvergenceReport::Severity::NotANumber) {
1752 OpmLog::debug(
"NaN residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1753 }
else if (f.severity() == ConvergenceReport::Severity::TooLarge) {
1754 OpmLog::debug(
"Too large residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1765 template<
typename TypeTag>
1767 BlackoilWellModel<TypeTag>::
1768 getWellConvergence(
const std::vector<Scalar>& B_avg,
bool checkWellGroupControls)
const
1771 DeferredLogger local_deferredLogger;
1773 ConvergenceReport local_report;
1774 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1775 for (
const auto& well : well_container_) {
1776 if (well->isOperableAndSolvable() || well->wellIsStopped()) {
1777 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1778 local_report += well->getWellConvergence(
1779 summary_state, this->wellState(), B_avg, local_deferredLogger,
1780 iterationIdx > param_.strict_outer_iter_wells_);
1782 ConvergenceReport report;
1783 using CR = ConvergenceReport;
1784 report.setWellFailed({CR::WellFailure::Type::Unsolvable, CR::Severity::Normal, -1, well->name()});
1785 local_report += report;
1789 const Opm::Parallel::Communication comm = grid().comm();
1794 if (checkWellGroupControls) {
1795 report.setWellGroupTargetsViolated(this->lastReport().well_group_control_changed);
1798 if (terminal_output_) {
1799 global_deferredLogger.logMessages();
1802 if (terminal_output_) {
1803 for (
const auto& f : report.wellFailures()) {
1804 if (f.severity() == ConvergenceReport::Severity::NotANumber) {
1805 OpmLog::debug(
"NaN residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1806 }
else if (f.severity() == ConvergenceReport::Severity::TooLarge) {
1807 OpmLog::debug(
"Too large residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1818 template<
typename TypeTag>
1824 for (
auto& well : well_container_) {
1833 template<
typename TypeTag>
1834 std::pair<bool, bool>
1838 const int episodeIdx = ebosSimulator_.episodeIndex();
1840 if (!wellsActive() && !
network.active()) {
1841 return {
false,
false};
1844 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1845 const auto& comm = ebosSimulator_.vanguard().grid().comm();
1846 updateAndCommunicateGroupData(episodeIdx, iterationIdx);
1849 bool more_network_update =
false;
1850 if (shouldBalanceNetwork(episodeIdx, iterationIdx) || mandatory_network_balance) {
1851 const auto local_network_imbalance = updateNetworkPressures(episodeIdx);
1852 const double network_imbalance = comm.max(local_network_imbalance);
1853 const auto& balance = schedule()[episodeIdx].network_balance();
1854 constexpr double relaxtion_factor = 10.0;
1855 const double tolerance = relax_network_tolerance ? relaxtion_factor * balance.pressure_tolerance() : balance.pressure_tolerance();
1856 more_network_update = network_imbalance > tolerance;
1859 bool changed_well_group =
false;
1861 const int nupcol = schedule()[episodeIdx].nupcol();
1864 if (iterationIdx <= nupcol) {
1865 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1866 changed_well_group = updateGroupControls(fieldGroup, deferred_logger, episodeIdx, iterationIdx);
1869 bool changed_well_to_group =
false;
1870 for (
const auto& well : well_container_) {
1871 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Group;
1872 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1874 changed_well_to_group = changed_well || changed_well_to_group;
1878 changed_well_to_group = comm.sum(changed_well_to_group);
1879 if (changed_well_to_group) {
1880 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1881 changed_well_group =
true;
1885 bool changed_well_individual =
false;
1886 for (
const auto& well : well_container_) {
1887 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
1888 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1890 changed_well_individual = changed_well || changed_well_individual;
1893 changed_well_individual = comm.sum(changed_well_individual);
1894 if (changed_well_individual) {
1895 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1896 changed_well_group =
true;
1900 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1901 updateWsolvent(fieldGroup, episodeIdx, this->nupcolWellState());
1903 return { changed_well_group, more_network_update };
1906 template<
typename TypeTag>
1908 BlackoilWellModel<TypeTag>::
1909 updateWellControlsDomain(DeferredLogger& deferred_logger,
const Domain& domain)
1911 if ( !wellsActive() ) return ;
1917 for (
const auto& well : well_container_) {
1918 if (well_domain_.at(well->name()) == domain.index) {
1919 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
1920 well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1929 template <
typename TypeTag>
1931 BlackoilWellModel<TypeTag>::
1932 initializeWBPCalculationService()
1934 this->wbpCalcMap_.clear();
1935 this->wbpCalcMap_.resize(this->wells_ecl_.size());
1937 this->registerOpenWellsForWBPCalculation();
1939 auto wellID = std::size_t{0};
1940 for (
const auto& well : this->wells_ecl_) {
1941 this->wbpCalcMap_[wellID].wbpCalcIdx_ = this->wbpCalculationService_
1942 .createCalculator(well,
1943 this->local_parallel_well_info_[wellID],
1944 this->conn_idx_map_[wellID].local(),
1945 this->makeWellSourceEvaluatorFactory(wellID));
1950 this->wbpCalculationService_.defineCommunication();
1957 template <
typename TypeTag>
1958 data::WellBlockAveragePressures
1959 BlackoilWellModel<TypeTag>::
1960 computeWellBlockAveragePressures()
const
1962 auto wbpResult = data::WellBlockAveragePressures{};
1964 using Calculated = PAvgCalculator::Result::WBPMode;
1965 using Output = data::WellBlockAvgPress::Quantity;
1967 this->wbpCalculationService_.collectDynamicValues();
1969 const auto numWells = this->wells_ecl_.size();
1970 for (
auto wellID = 0*numWells; wellID < numWells; ++wellID) {
1971 const auto calcIdx = this->wbpCalcMap_[wellID].wbpCalcIdx_;
1972 const auto& well = this->wells_ecl_[wellID];
1974 if (! well.hasRefDepth()) {
1980 this->wbpCalculationService_
1981 .inferBlockAveragePressures(calcIdx, well.pavg(),
1983 well.getWPaveRefDepth());
1985 const auto& result = this->wbpCalculationService_
1986 .averagePressures(calcIdx);
1988 auto& reported = wbpResult.values[well.name()];
1990 reported[Output::WBP] = result.value(Calculated::WBP);
1991 reported[Output::WBP4] = result.value(Calculated::WBP4);
1992 reported[Output::WBP5] = result.value(Calculated::WBP5);
1993 reported[Output::WBP9] = result.value(Calculated::WBP9);
2003 template <
typename TypeTag>
2004 ParallelWBPCalculation::EvaluatorFactory
2005 BlackoilWellModel<TypeTag>::
2006 makeWellSourceEvaluatorFactory(
const std::vector<Well>::size_type wellIdx)
const
2008 using Span = PAvgDynamicSourceData::SourceDataSpan<double>;
2009 using Item =
typename Span::Item;
2011 return [wellIdx,
this]() -> ParallelWBPCalculation::Evaluator
2013 if (! this->wbpCalcMap_[wellIdx].openWellIdx_.has_value()) {
2015 return []([[maybe_unused]]
const int connIdx, Span sourceTerm)
2021 .set(Item::Pressure , 0.0)
2022 .set(Item::PoreVol , 0.0)
2023 .set(Item::MixtureDensity, 0.0);
2028 return [
this, wellPtr = this->well_container_[*this->wbpCalcMap_[wellIdx].openWellIdx_].get()]
2029 (
const int connIdx, Span sourceTerm)
2035 const auto& connIdxMap =
2036 this->conn_idx_map_[wellPtr->indexOfWell()];
2038 const auto rho = wellPtr->
2039 connectionDensity(connIdxMap.global(connIdx),
2040 connIdxMap.open(connIdx));
2043 .set(Item::Pressure , 0.0)
2044 .set(Item::PoreVol , 0.0)
2045 .set(Item::MixtureDensity, rho);
2054 template <
typename TypeTag>
2056 BlackoilWellModel<TypeTag>::
2057 registerOpenWellsForWBPCalculation()
2059 assert (this->wbpCalcMap_.size() == this->wells_ecl_.size());
2061 for (
auto& wbpCalc : this->wbpCalcMap_) {
2062 wbpCalc.openWellIdx_.reset();
2065 auto openWellIdx =
typename std::vector<WellInterfacePtr>::size_type{0};
2066 for (
const auto* openWell : this->well_container_generic_) {
2067 this->wbpCalcMap_[openWell->indexOfWell()].openWellIdx_ = openWellIdx++;
2075 template<
typename TypeTag>
2077 BlackoilWellModel<TypeTag>::
2078 updateAndCommunicate(
const int reportStepIdx,
2079 const int iterationIdx,
2080 DeferredLogger& deferred_logger)
2082 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
2084 for (
const auto& well : well_container_) {
2085 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
2087 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
2090 template<
typename TypeTag>
2092 BlackoilWellModel<TypeTag>::
2093 updateGroupControls(
const Group& group,
2094 DeferredLogger& deferred_logger,
2095 const int reportStepIdx,
2096 const int iterationIdx)
2098 bool changed =
false;
2099 bool changed_hc = checkGroupHigherConstraints( group, deferred_logger, reportStepIdx);
2102 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
2104 bool changed_individual =
2105 BlackoilWellModelConstraints(*this).
2106 updateGroupIndividualControl(group,
2108 this->switched_inj_groups_,
2109 this->switched_prod_groups_,
2113 if (changed_individual) {
2115 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
2118 for (
const std::string& groupName : group.groups()) {
2119 bool changed_this = updateGroupControls( schedule().getGroup(groupName, reportStepIdx), deferred_logger, reportStepIdx,iterationIdx);
2120 changed = changed || changed_this;
2125 template<
typename TypeTag>
2131 for (
const auto& well : well_container_) {
2132 const auto&
wname = well->name();
2138 this->closed_this_step_.insert(
wname);
2142 const Opm::Parallel::Communication comm = grid().comm();
2144 if (terminal_output_) {
2150 template<
typename TypeTag>
2158 const int np = numPhases();
2160 const auto& well= well_container_[
widx];
2165 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
2169 auto& ws = this->wellState().well(well->indexOfWell());
2170 for (
int p = 0; p < np; ++p) {
2172 ws.well_potentials[p] = std::max(0.0, potentials[p]);
2178 template <
typename TypeTag>
2180 BlackoilWellModel<TypeTag>::
2181 calculateProductivityIndexValues(DeferredLogger& deferred_logger)
2183 for (
const auto& wellPtr : this->well_container_) {
2184 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
2192 template <
typename TypeTag>
2194 BlackoilWellModel<TypeTag>::
2195 calculateProductivityIndexValuesShutWells(
const int reportStepIdx,
2196 DeferredLogger& deferred_logger)
2203 for (
const auto& shutWell : this->local_shut_wells_) {
2204 if (!this->wells_ecl_[shutWell].hasConnections()) {
2209 auto wellPtr = this->
template createTypedWellPointer
2210 <StandardWell<TypeTag>>(shutWell, reportStepIdx);
2212 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
2213 this->local_num_cells_, this->B_avg_,
true);
2215 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
2223 template <
typename TypeTag>
2225 BlackoilWellModel<TypeTag>::
2226 calculateProductivityIndexValues(
const WellInterface<TypeTag>* wellPtr,
2227 DeferredLogger& deferred_logger)
2229 wellPtr->updateProductivityIndex(this->ebosSimulator_,
2230 this->prod_index_calc_[wellPtr->indexOfWell()],
2237 template<
typename TypeTag>
2239 BlackoilWellModel<TypeTag>::
2240 prepareTimeStep(DeferredLogger& deferred_logger)
2242 const bool network_rebalance_necessary = this->needRebalanceNetwork(ebosSimulator_.episodeIndex());
2244 for (
const auto& well : well_container_) {
2245 auto& events = this->wellState().well(well->indexOfWell()).events;
2246 if (events.hasEvent(WellState::event_mask)) {
2247 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
2248 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
2249 well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger);
2250 well->initPrimaryVariablesEvaluation();
2253 events.clearEvent(WellState::event_mask);
2256 if (param_.solve_welleq_initially_ && well->isOperableAndSolvable()) {
2258 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
2259 }
catch (
const std::exception& e) {
2260 const std::string msg =
"Compute initial well solution for " + well->name() +
" initially failed. Continue with the privious rates";
2261 deferred_logger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
2266 well->resetWellOperability();
2268 updatePrimaryVariables(deferred_logger);
2270 if (network_rebalance_necessary) {
2272 balanceNetwork(deferred_logger);
2276 template<
typename TypeTag>
2278 BlackoilWellModel<TypeTag>::
2279 updateAverageFormationFactor()
2281 std::vector< Scalar > B_avg(numComponents(), Scalar() );
2282 const auto& grid = ebosSimulator_.vanguard().grid();
2283 const auto& gridView = grid.leafGridView();
2284 ElementContext elemCtx(ebosSimulator_);
2286 OPM_BEGIN_PARALLEL_TRY_CATCH();
2287 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
2288 elemCtx.updatePrimaryStencil(elem);
2289 elemCtx.updatePrimaryIntensiveQuantities(0);
2291 const auto& intQuants = elemCtx.intensiveQuantities(0, 0);
2292 const auto& fs = intQuants.fluidState();
2294 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
2296 if (!FluidSystem::phaseIsActive(phaseIdx)) {
2300 const unsigned compIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx));
2301 auto& B = B_avg[ compIdx ];
2303 B += 1 / fs.invB(phaseIdx).value();
2305 if constexpr (has_solvent_) {
2306 auto& B = B_avg[solventSaturationIdx];
2307 B += 1 / intQuants.solventInverseFormationVolumeFactor().value();
2310 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::updateAverageFormationFactor() failed: ", grid.comm())
2313 grid.comm().sum(B_avg.data(), B_avg.size());
2314 for (auto& bval : B_avg)
2316 bval /= global_num_cells_;
2325 template<
typename TypeTag>
2327 BlackoilWellModel<TypeTag>::
2328 updatePrimaryVariables(DeferredLogger& deferred_logger)
2330 for (
const auto& well : well_container_) {
2331 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
2332 well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger);
2336 template<
typename TypeTag>
2338 BlackoilWellModel<TypeTag>::extractLegacyCellPvtRegionIndex_()
2340 const auto& grid = ebosSimulator_.vanguard().grid();
2341 const auto& eclProblem = ebosSimulator_.problem();
2342 const unsigned numCells = grid.size(0);
2344 pvt_region_idx_.resize(numCells);
2345 for (
unsigned cellIdx = 0; cellIdx < numCells; ++cellIdx) {
2346 pvt_region_idx_[cellIdx] =
2347 eclProblem.pvtRegionIndex(cellIdx);
2352 template<
typename TypeTag>
2354 BlackoilWellModel<TypeTag>::numComponents()
const
2362 int numComp = numPhases() < 3? numPhases(): FluidSystem::numComponents;
2363 if constexpr (has_solvent_) {
2369 template<
typename TypeTag>
2371 BlackoilWellModel<TypeTag>::extractLegacyDepth_()
2373 const auto& eclProblem = ebosSimulator_.problem();
2374 depth_.resize(local_num_cells_);
2375 for (
unsigned cellIdx = 0; cellIdx < local_num_cells_; ++cellIdx) {
2376 depth_[cellIdx] = eclProblem.dofCenterDepth(cellIdx);
2380 template<
typename TypeTag>
2381 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
2382 BlackoilWellModel<TypeTag>::
2383 getWell(
const std::string& well_name)
const
2386 auto well = std::find_if(well_container_.begin(),
2387 well_container_.end(),
2388 [&well_name](
const WellInterfacePtr& elem)->bool {
2389 return elem->name() == well_name;
2392 assert(well != well_container_.end());
2397 template<
typename TypeTag>
2399 BlackoilWellModel<TypeTag>::
2400 hasWell(
const std::string& well_name)
const
2402 return std::any_of(well_container_.begin(), well_container_.end(),
2403 [&well_name](
const WellInterfacePtr& elem) ->
bool
2405 return elem->name() == well_name;
2412 template <
typename TypeTag>
2414 BlackoilWellModel<TypeTag>::
2415 reportStepIndex()
const
2417 return std::max(this->ebosSimulator_.episodeIndex(), 0);
2424 template<
typename TypeTag>
2426 BlackoilWellModel<TypeTag>::
2427 calcRates(
const int fipnum,
2429 const std::vector<double>& production_rates,
2430 std::vector<double>& resv_coeff)
2432 rateConverter_->calcCoeff(fipnum, pvtreg, production_rates, resv_coeff);
2435 template<
typename TypeTag>
2437 BlackoilWellModel<TypeTag>::
2438 calcInjRates(
const int fipnum,
2440 std::vector<double>& resv_coeff)
2442 rateConverter_->calcInjCoeff(fipnum, pvtreg, resv_coeff);
2446 template <
typename TypeTag>
2448 BlackoilWellModel<TypeTag>::
2449 computeWellTemperature()
2454 int np = numPhases();
2455 double cellInternalEnergy;
2458 double perfPhaseRate;
2459 const int nw = numLocalWells();
2460 for (
auto wellID = 0*nw; wellID < nw; ++wellID) {
2461 const Well& well = wells_ecl_[wellID];
2462 if (well.isInjector())
2465 std::array<double,2> weighted{0.0,0.0};
2466 auto& [weighted_temperature, total_weight] = weighted;
2468 auto& well_info = local_parallel_well_info_[wellID].get();
2469 auto& ws = this->wellState().well(wellID);
2470 auto& perf_data = ws.perf_data;
2471 auto& perf_phase_rate = perf_data.phase_rates;
2473 using int_type =
decltype(well_perf_data_[wellID].size());
2474 for (int_type perf = 0, end_perf = well_perf_data_[wellID].size(); perf < end_perf; ++perf) {
2475 const int cell_idx = well_perf_data_[wellID][perf].cell_index;
2476 const auto& intQuants = ebosSimulator_.model().intensiveQuantities(cell_idx, 0);
2477 const auto& fs = intQuants.fluidState();
2480 double cellTemperatures = fs.temperature(0).value();
2482 double weight_factor = 0.0;
2483 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
2485 if (!FluidSystem::phaseIsActive(phaseIdx)) {
2488 cellInternalEnergy = fs.enthalpy(phaseIdx).value() - fs.pressure(phaseIdx).value() / fs.density(phaseIdx).value();
2489 cellBinv = fs.invB(phaseIdx).value();
2490 cellDensity = fs.density(phaseIdx).value();
2491 perfPhaseRate = perf_phase_rate[ perf*np + phaseIdx ];
2492 weight_factor += cellDensity * perfPhaseRate/cellBinv * cellInternalEnergy/cellTemperatures;
2494 total_weight += weight_factor;
2495 weighted_temperature += weight_factor * cellTemperatures;
2497 well_info.communication().sum(weighted.data(), 2);
2498 this->wellState().well(wellID).temperature = weighted_temperature/total_weight;
2503 template <
typename TypeTag>
2505 BlackoilWellModel<TypeTag>::
2506 logPrimaryVars()
const
2508 std::ostringstream os;
2509 for (
const auto& w : well_container_) {
2510 os << w->name() <<
":";
2511 auto pv = w->getPrimaryVars();
2512 for (
const double v : pv) {
2517 OpmLog::debug(os.str());
2522 template <
typename TypeTag>
2524 BlackoilWellModel<TypeTag>::
2525 getPrimaryVarsDomain(
const Domain& domain)
const
2527 std::vector<double> ret;
2528 for (
const auto& well : well_container_) {
2529 if (well_domain_.at(well->name()) == domain.index) {
2530 const auto& pv = well->getPrimaryVars();
2531 ret.insert(ret.end(), pv.begin(), pv.end());
2539 template <
typename TypeTag>
2541 BlackoilWellModel<TypeTag>::
2542 setPrimaryVarsDomain(
const Domain& domain,
const std::vector<double>& vars)
2544 std::size_t offset = 0;
2545 for (
auto& well : well_container_) {
2546 if (well_domain_.at(well->name()) == domain.index) {
2547 int num_pri_vars = well->setPrimaryVars(vars.begin() + offset);
2548 offset += num_pri_vars;
2551 assert(offset == vars.size());
2556 template <
typename TypeTag>
2558 BlackoilWellModel<TypeTag>::
2559 setupDomains(
const std::vector<Domain>& domains)
2561 OPM_BEGIN_PARALLEL_TRY_CATCH();
2566 for (
const auto& wellPtr : this->well_container_) {
2567 const int first_well_cell = wellPtr->cells()[0];
2568 for (
const auto& domain : domains) {
2569 const bool found = std::binary_search(domain.cells.begin(), domain.cells.end(), first_well_cell);
2573 well_domain_[wellPtr->name()] = domain.index;
2575 for (
int well_cell : wellPtr->cells()) {
2576 if (!std::binary_search(domain.cells.begin(), domain.cells.end(), well_cell)) {
2577 OPM_THROW(std::runtime_error,
"Well found on multiple domains.");
2583 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::setupDomains(): well found on multiple domains.",
2584 ebosSimulator_.gridView().comm());
2587 if (ebosSimulator_.gridView().comm().rank() == 0) {
2588 std::ostringstream os;
2589 os <<
"Well name Domain\n";
2590 for (
const auto& [wname, domain] : well_domain_) {
2591 os << wname << std::setw(21 - wname.size()) << domain <<
'\n';
2593 OpmLog::debug(os.str());
Definition AquiferInterface.hpp:35
Class for handling the blackoil well model.
Definition BlackoilWellModel.hpp:97
void calculateExplicitQuantities(DeferredLogger &deferred_logger) const
Calculating the explict quantities used in the well calculation.
Definition BlackoilWellModel_impl.hpp:1821
Definition DeferredLogger.hpp:57
void logMessages()
Log all messages to the OpmLog backends, and clear the message container.
Definition DeferredLogger.cpp:85
The state of a set of wells, tailored for use by the fully implicit blackoil simulator.
Definition WellState.hpp:60
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition BlackoilPhases.hpp:27
Opm::DeferredLogger gatherDeferredLogger(const Opm::DeferredLogger &local_deferredlogger, Opm::Parallel::Communication)
Create a global log combining local logs.
Definition gatherDeferredLogger.cpp:168
ConvergenceReport gatherConvergenceReport(const ConvergenceReport &local_report, Parallel::Communication mpi_communicator)
Create a global convergence report combining local (per-process) reports.
Definition gatherConvergenceReport.cpp:249
PhaseUsage phaseUsageFromDeck(const EclipseState &eclipseState)
Looks at presence of WATER, OIL and GAS keywords in state object to determine active phases.
Definition phaseUsageFromDeck.cpp:145