23#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
24#include <opm/core/props/phaseUsageFromDeck.hpp>
25#include <opm/grid/utility/cartesianToCompressed.hpp>
26#include <opm/input/eclipse/Units/UnitSystem.hpp>
28#include <opm/simulators/wells/VFPProperties.hpp>
29#include <opm/simulators/utils/MPIPacker.hpp>
30#include <opm/simulators/linalg/bda/WellContributions.hpp>
33#include <ebos/eclmpiserializer.hh>
39#include <fmt/format.h>
42 template<
typename TypeTag>
43 BlackoilWellModel<TypeTag>::
44 BlackoilWellModel(Simulator& ebosSimulator,
const PhaseUsage& phase_usage)
45 : BlackoilWellModelGeneric(ebosSimulator.vanguard().schedule(),
46 ebosSimulator.vanguard().summaryState(),
47 ebosSimulator.vanguard().eclState(),
49 ebosSimulator.gridView().comm())
50 , ebosSimulator_(ebosSimulator)
52 terminal_output_ = ((ebosSimulator.gridView().comm().rank() == 0) &&
53 EWOMS_GET_PARAM(TypeTag,
bool, EnableTerminalOutput));
55 local_num_cells_ = ebosSimulator_.gridView().size(0);
58 global_num_cells_ = ebosSimulator_.vanguard().globalNumCells();
61 auto& parallel_wells = ebosSimulator.vanguard().parallelWells();
63 this->parallel_well_info_.reserve(parallel_wells.size());
64 for(
const auto& name_bool : parallel_wells) {
65 this->parallel_well_info_.emplace_back(name_bool, grid().comm());
69 this->alternative_well_rate_init_ =
70 EWOMS_GET_PARAM(TypeTag,
bool, AlternativeWellRateInit);
73 template<
typename TypeTag>
74 BlackoilWellModel<TypeTag>::
75 BlackoilWellModel(Simulator& ebosSimulator) :
76 BlackoilWellModel(ebosSimulator,
phaseUsageFromDeck(ebosSimulator.vanguard().eclState()))
80 template<
typename TypeTag>
82 BlackoilWellModel<TypeTag>::
85 extractLegacyCellPvtRegionIndex_();
86 extractLegacyDepth_();
88 gravity_ = ebosSimulator_.problem().gravity()[2];
93 ebosSimulator_.model().addAuxiliaryModule(
this);
95 is_cell_perforated_.resize(local_num_cells_,
false);
99 template<
typename TypeTag>
101 BlackoilWellModel<TypeTag>::
102 initWellContainer(
const int reportStepIdx)
104 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
105 + ScheduleEvents::NEW_WELL;
106 const auto& events = schedule()[reportStepIdx].wellgroup_events();
107 for (
auto& wellPtr : this->well_container_) {
108 const bool well_opened_this_step = report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
109 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
110 this->local_num_cells_, this->B_avg_, well_opened_this_step);
114 template<
typename TypeTag>
116 BlackoilWellModel<TypeTag>::
117 addNeighbors(std::vector<NeighborSet>& neighbors)
const
119 if (!param_.matrix_add_well_contributions_) {
124 const auto& schedule_wells = schedule().getWellsatEnd();
127 for (
const auto& well : schedule_wells)
129 std::vector<int> wellCells;
131 const auto& connectionSet = well.getConnections();
132 wellCells.reserve(connectionSet.size());
134 for (
size_t c=0; c < connectionSet.size(); c++ )
136 const auto& connection = connectionSet.get(c);
137 int compressed_idx = compressedIndexForInterior(connection.global_index());
138 if ( compressed_idx >= 0 ) {
139 wellCells.push_back(compressed_idx);
143 for (
int cellIdx : wellCells) {
144 neighbors[cellIdx].insert(wellCells.begin(),
150 template<
typename TypeTag>
152 BlackoilWellModel<TypeTag>::
153 linearize(SparseMatrixAdapter& jacobian, GlobalEqVector& res)
155 if (!param_.matrix_add_well_contributions_)
157 OPM_BEGIN_PARALLEL_TRY_CATCH();
161 for (
const auto& well: well_container_) {
166 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::linearize failed: ",
167 ebosSimulator_.gridView().comm());
171 for (
const auto& well: well_container_) {
172 well->addWellContributions(jacobian);
181 template<
typename TypeTag>
183 BlackoilWellModel<TypeTag>::
184 beginReportStep(
const int timeStepIdx)
186 DeferredLogger local_deferredLogger;
188 report_step_starts_ =
true;
190 const Grid& grid = ebosSimulator_.vanguard().grid();
191 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
193 wells_ecl_ = getLocalWells(timeStepIdx);
194 this->local_parallel_well_info_ = createLocalParallelWellInfo(wells_ecl_);
199 OPM_BEGIN_PARALLEL_TRY_CATCH();
204 this->initializeWellPerfData();
205 this->initializeWellState(timeStepIdx, summaryState);
208 if (param_.use_multisegment_well_&& anyMSWellOpenLocal()) {
209 this->wellState().initWellStateMSWell(wells_ecl_, &this->prevWellState());
212 const Group& fieldGroup = schedule().getGroup(
"FIELD", timeStepIdx);
213 WellGroupHelpers::setCmodeGroup(fieldGroup, schedule(), summaryState, timeStepIdx, this->wellState(), this->groupState());
216 rateConverter_.reset(
new RateConverterType (phase_usage_,
217 std::vector<int>(local_num_cells_, 0)));
218 rateConverter_->template defineState<ElementContext>(ebosSimulator_);
221 if (schedule_[timeStepIdx].has_gpmaint()) {
222 const auto& fp = this->eclState_.fieldProps();
223 const auto& fipnum = fp.get_int(
"FIPNUM");
224 regionalAveragePressureCalculator_.reset(
new AverageRegionalPressureType (phase_usage_,fipnum));
228 const auto& sched_state = this->schedule()[timeStepIdx];
230 vfp_properties_.reset(
new VFPProperties( sched_state.vfpinj(), sched_state.vfpprod(), this->prevWellState()));
231 this->initializeWellProdIndCalculators();
232 if (sched_state.events().hasEvent(ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX)) {
233 this->runWellPIScaling(timeStepIdx, local_deferredLogger);
237 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"beginReportStep() failed: ",
238 terminal_output_, grid.comm());
240 this->commitWGState();
245 template<
typename TypeTag>
247 BlackoilWellModel<TypeTag>::
250 updatePerforationIntensiveQuantities();
251 updateAverageFormationFactor();
252 DeferredLogger local_deferredLogger;
253 switched_prod_groups_.clear();
254 switched_inj_groups_.clear();
256 this->resetWGState();
257 const int reportStepIdx = ebosSimulator_.episodeIndex();
258 updateAndCommunicateGroupData(reportStepIdx,
259 ebosSimulator_.model().newtonMethod().numIterations());
260 this->wellState().gliftTimeStepInit();
261 const double simulationTime = ebosSimulator_.time();
262 OPM_BEGIN_PARALLEL_TRY_CATCH();
265 wellTesting(reportStepIdx, simulationTime, local_deferredLogger);
268 createWellContainer(reportStepIdx);
271 const Grid& grid = ebosSimulator_.vanguard().grid();
272 wells_active_ = !this->well_container_.empty();
273 wells_active_ = grid.comm().max(wells_active_);
278 this->initWellContainer(reportStepIdx);
281 std::fill(is_cell_perforated_.begin(), is_cell_perforated_.end(),
false);
282 for (
auto& well : well_container_) {
283 well->updatePerforatedCell(is_cell_perforated_);
287 calculateEfficiencyFactors(reportStepIdx);
289 if constexpr (has_polymer_)
291 if (PolymerModule::hasPlyshlog() || getPropValue<TypeTag, Properties::EnablePolymerMW>() ) {
292 setRepRadiusPerfLength();
297 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"beginTimeStep() failed: ",
298 terminal_output_, ebosSimulator_.vanguard().grid().comm());
300 for (
auto& well : well_container_) {
301 well->setVFPProperties(vfp_properties_.get());
302 well->setGuideRate(&guideRate_);
306 for (
auto& well : well_container_) {
307 well->closeCompletions(wellTestState());
310 if (alternative_well_rate_init_) {
315 for (
auto& well : well_container_) {
316 if (well->isProducer()) {
317 well->updateWellStateRates(ebosSimulator_, this->wellState(), local_deferredLogger);
324 updateWellPotentials(reportStepIdx,
326 ebosSimulator_.vanguard().summaryConfig(),
327 local_deferredLogger);
328 }
catch ( std::runtime_error& e ) {
329 const std::string msg =
"A zero well potential is returned for output purposes. ";
330 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
334 const auto& comm = ebosSimulator_.vanguard().grid().comm();
335 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
336 std::vector<double> pot(numPhases(), 0.0);
337 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
338 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
339 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
341 auto exc_type = ExceptionType::NONE;
343 if (schedule_[reportStepIdx].has_gpmaint()) {
344 regionalAveragePressureCalculator_->template defineState<ElementContext>(ebosSimulator_);
345 const double dt = ebosSimulator_.timeStepSize();
346 WellGroupHelpers::updateGpMaintTargetForGroups(fieldGroup,
347 schedule_, *regionalAveragePressureCalculator_, reportStepIdx, dt, this->wellState(), this->groupState());
351 for (
auto& well : well_container_) {
352 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
353 + ScheduleEvents::INJECTION_TYPE_CHANGED
354 + ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER
355 + ScheduleEvents::NEW_WELL;
357 const auto& events = schedule()[reportStepIdx].wellgroup_events();
358 const bool event = report_step_starts_ && events.hasEvent(well->name(), effective_events_mask);
359 const bool dyn_status_change = this->wellState().well(well->name()).status
360 != this->prevWellState().well(well->name()).status;
362 if (event || dyn_status_change) {
364 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), local_deferredLogger);
365 well->calculateExplicitQuantities(ebosSimulator_, this->wellState(), local_deferredLogger);
366 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), local_deferredLogger);
367 }
catch (
const std::exception& e) {
368 const std::string msg =
"Compute initial well solution for new well " + well->name() +
" failed. Continue with zero initial rates";
369 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
375 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
377 if (exc_type != ExceptionType::NONE) {
378 const std::string msg =
"Compute initial well solution for new wells failed. Continue with zero initial rates";
379 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
382 logAndCheckForExceptionsAndThrow(local_deferredLogger,
383 exc_type,
"beginTimeStep() failed: " + exc_msg, terminal_output_, comm);
387 template<
typename TypeTag>
389 BlackoilWellModel<TypeTag>::wellTesting(
const int timeStepIdx,
390 const double simulationTime,
391 DeferredLogger& deferred_logger)
393 const auto& wtest_config = schedule()[timeStepIdx].wtest_config();
394 if (!wtest_config.empty()) {
395 const std::vector<std::string> wellsForTesting = wellTestState()
396 .test_wells(wtest_config, simulationTime);
397 for (
const std::string& well_name : wellsForTesting) {
399 const Well& wellEcl = schedule().getWell(well_name, timeStepIdx);
400 if (wellEcl.getStatus() == Well::Status::SHUT)
403 WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx, deferred_logger);
405 well->init(&phase_usage_, depth_, gravity_, local_num_cells_, B_avg_,
true);
407 double well_efficiency_factor = wellEcl.getEfficiencyFactor();
408 WellGroupHelpers::accumulateGroupEfficiencyFactor(schedule().getGroup(wellEcl.groupName(), timeStepIdx),
409 schedule(), timeStepIdx, well_efficiency_factor);
411 well->setWellEfficiencyFactor(well_efficiency_factor);
412 well->setVFPProperties(vfp_properties_.get());
413 well->setGuideRate(&guideRate_);
415 well->wellTesting(ebosSimulator_, simulationTime, this->wellState(), this->groupState(), wellTestState(), deferred_logger);
425 template<
typename TypeTag>
427 BlackoilWellModel<TypeTag>::
431 for (
auto&& pinfo : this->local_parallel_well_info_)
442 template<
typename TypeTag>
443 const SimulatorReportSingle&
444 BlackoilWellModel<TypeTag>::
445 lastReport()
const {
return last_report_; }
452 template<
typename TypeTag>
454 BlackoilWellModel<TypeTag>::
455 timeStepSucceeded(
const double& simulationTime,
const double dt)
457 this->closed_this_step_.clear();
460 report_step_starts_ =
false;
461 const int reportStepIdx = ebosSimulator_.episodeIndex();
463 DeferredLogger local_deferredLogger;
464 for (
const auto& well : well_container_) {
465 if (getPropValue<TypeTag, Properties::EnablePolymerMW>() && well->isInjector()) {
466 well->updateWaterThroughput(dt, this->wellState());
470 for (
const auto& well : well_container_) {
471 well->reportWellSwitching(this->wellState().well(well->indexOfWell()), local_deferredLogger);
474 if (terminal_output_) {
476 for (
const auto& [name, to] : switched_prod_groups_) {
477 const Group::ProductionCMode& oldControl = this->prevWGState().group_state.production_control(name);
478 std::string from = Group::ProductionCMode2String(oldControl);
480 std::string msg =
" Production Group " + name
481 +
" control mode changed from ";
484 local_deferredLogger.info(msg);
487 for (
const auto& [key, to] : switched_inj_groups_) {
488 const std::string& name = key.first;
489 const Opm::Phase& phase = key.second;
491 const Group::InjectionCMode& oldControl = this->prevWGState().group_state.injection_control(name, phase);
492 std::string from = Group::InjectionCMode2String(oldControl);
494 std::string msg =
" Injection Group " + name
495 +
" control mode changed from ";
498 local_deferredLogger.info(msg);
504 rateConverter_->template defineState<ElementContext>(ebosSimulator_);
508 updateWellPotentials(reportStepIdx,
510 ebosSimulator_.vanguard().summaryConfig(),
511 local_deferredLogger);
512 }
catch ( std::runtime_error& e ) {
513 const std::string msg =
"A zero well potential is returned for output purposes. ";
514 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
517 updateWellTestState(simulationTime, wellTestState());
520 const Group& fieldGroup = schedule_.getGroup(
"FIELD", reportStepIdx);
521 checkGconsaleLimits(fieldGroup, this->wellState(),
522 ebosSimulator_.episodeIndex(), local_deferredLogger);
524 this->calculateProductivityIndexValues(local_deferredLogger);
526 this->commitWGState();
528 const Opm::Parallel::Communication& comm = grid().comm();
530 if (terminal_output_) {
531 global_deferredLogger.logMessages();
535 this->computeWellTemperature();
539 template<
typename TypeTag>
541 BlackoilWellModel<TypeTag>::
542 computeTotalRatesForDof(RateVector& rate,
543 unsigned elemIdx)
const
547 if (!is_cell_perforated_[elemIdx])
550 for (
const auto& well : well_container_)
551 well->addCellRates(rate, elemIdx);
555 template<
typename TypeTag>
556 template <
class Context>
558 BlackoilWellModel<TypeTag>::
559 computeTotalRatesForDof(RateVector& rate,
560 const Context& context,
562 unsigned timeIdx)
const
565 int elemIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
567 if (!is_cell_perforated_[elemIdx])
570 for (
const auto& well : well_container_)
571 well->addCellRates(rate, elemIdx);
576 template<
typename TypeTag>
578 BlackoilWellModel<TypeTag>::
579 initializeWellState(
const int timeStepIdx,
580 const SummaryState& summaryState)
582 std::vector<double> cellPressures(this->local_num_cells_, 0.0);
583 ElementContext elemCtx(ebosSimulator_);
585 const auto& gridView = ebosSimulator_.vanguard().gridView();
587 OPM_BEGIN_PARALLEL_TRY_CATCH();
588 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
589 elemCtx.updatePrimaryStencil(elem);
590 elemCtx.updatePrimaryIntensiveQuantities(0);
592 const auto& fs = elemCtx.intensiveQuantities(0, 0).fluidState();
594 double& perf_pressure = cellPressures[elemCtx.globalSpaceIndex(0, 0)];
595 if (Indices::oilEnabled) {
596 perf_pressure = fs.pressure(FluidSystem::oilPhaseIdx).value();
597 }
else if (Indices::waterEnabled) {
598 perf_pressure = fs.pressure(FluidSystem::waterPhaseIdx).value();
600 perf_pressure = fs.pressure(FluidSystem::gasPhaseIdx).value();
603 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::initializeWellState() failed: ", ebosSimulator_.vanguard().grid().comm());
605 this->wellState().init(cellPressures, schedule(), wells_ecl_, local_parallel_well_info_, timeStepIdx,
606 &this->prevWellState(), well_perf_data_,
614 template<
typename TypeTag>
616 BlackoilWellModel<TypeTag>::
617 createWellContainer(
const int time_step)
619 DeferredLogger local_deferredLogger;
621 const int nw = numLocalWells();
623 well_container_.clear();
626 well_container_.reserve(nw);
628 for (
int w = 0; w < nw; ++w) {
629 const Well& well_ecl = wells_ecl_[w];
631 if (well_ecl.getConnections().empty()) {
636 const std::string& well_name = well_ecl.name();
637 const auto well_status = this->schedule()
638 .getWell(well_name, time_step).getStatus();
640 if ((well_ecl.getStatus() == Well::Status::SHUT) ||
641 (well_status == Well::Status::SHUT))
644 if (well_ecl.getStatus() != Well::Status::SHUT) {
645 this->closed_this_step_.insert(well_name);
646 this->wellState().shutWell(w);
653 if (this->wellTestState().well_is_closed(well_name)) {
656 auto& events = this->wellState().well(w).events;
657 if (events.hasEvent(WellState::event_mask)) {
658 if (wellTestState().lastTestTime(well_name) == ebosSimulator_.time()) {
663 events.clearEvent(WellState::event_mask);
665 wellTestState().open_well(well_name);
666 wellTestState().open_completions(well_name);
673 bool wellIsStopped =
false;
674 if (wellTestState().well_is_closed(well_name))
676 if (well_ecl.getAutomaticShutIn()) {
678 this->wellState().shutWell(w);
681 if (!well_ecl.getAllowCrossFlow()) {
684 this->wellState().shutWell(w);
688 this->wellState().stopWell(w);
689 wellIsStopped =
true;
695 if (!well_ecl.getAllowCrossFlow() && well_ecl.isProducer() && well_ecl.predictionMode()) {
696 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
697 const auto prod_controls = well_ecl.productionControls(summaryState);
699 auto is_zero = [](
const double x)
701 return std::isfinite(x) && !std::isnormal(x);
704 bool zero_rate_control =
false;
705 switch (prod_controls.cmode) {
706 case Well::ProducerCMode::ORAT:
707 zero_rate_control = is_zero(prod_controls.oil_rate);
710 case Well::ProducerCMode::WRAT:
711 zero_rate_control = is_zero(prod_controls.water_rate);
714 case Well::ProducerCMode::GRAT:
715 zero_rate_control = is_zero(prod_controls.gas_rate);
718 case Well::ProducerCMode::LRAT:
719 zero_rate_control = is_zero(prod_controls.liquid_rate);
722 case Well::ProducerCMode::RESV:
723 zero_rate_control = is_zero(prod_controls.resv_rate);
727 zero_rate_control =
false;
731 if (zero_rate_control) {
733 local_deferredLogger.info(
" Well shut due to zero rate control and disallowing crossflow: " + well_ecl.name());
734 this->wellState().shutWell(w);
739 if (well_status == Well::Status::STOP) {
740 this->wellState().stopWell(w);
741 wellIsStopped =
true;
744 well_container_.emplace_back(this->createWellPointer(w, time_step));
747 well_container_.back()->stopWell();
753 const Opm::Parallel::Communication& comm = grid().comm();
755 if (terminal_output_) {
756 global_deferredLogger.logMessages();
759 well_container_generic_.clear();
760 for (
auto& w : well_container_)
761 well_container_generic_.push_back(w.get());
768 template <
typename TypeTag>
769 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
770 BlackoilWellModel<TypeTag>::
771 createWellPointer(
const int wellID,
const int time_step)
const
773 const auto is_multiseg = this->wells_ecl_[wellID].isMultiSegment();
775 if (! (this->param_.use_multisegment_well_ && is_multiseg)) {
776 return this->
template createTypedWellPointer<StandardWell<TypeTag>>(wellID, time_step);
779 return this->
template createTypedWellPointer<MultisegmentWell<TypeTag>>(wellID, time_step);
787 template <
typename TypeTag>
788 template <
typename WellType>
789 std::unique_ptr<WellType>
790 BlackoilWellModel<TypeTag>::
791 createTypedWellPointer(
const int wellID,
const int time_step)
const
794 const auto& perf_data = this->well_perf_data_[wellID];
797 const auto pvtreg = perf_data.empty()
798 ? 0 : pvt_region_idx_[perf_data.front().cell_index];
800 const auto& parallel_well_info = this->local_parallel_well_info_[wellID].get();
801 const auto global_pvtreg = parallel_well_info.broadcastFirstPerforationValue(pvtreg);
803 return std::make_unique<WellType>(this->wells_ecl_[wellID],
807 *this->rateConverter_,
809 this->numComponents(),
819 template<
typename TypeTag>
820 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
821 BlackoilWellModel<TypeTag>::
822 createWellForWellTest(
const std::string& well_name,
823 const int report_step,
824 DeferredLogger& deferred_logger)
const
827 const int nw_wells_ecl = wells_ecl_.size();
828 int index_well_ecl = 0;
829 for (; index_well_ecl < nw_wells_ecl; ++index_well_ecl) {
830 if (well_name == wells_ecl_[index_well_ecl].name()) {
835 if (index_well_ecl == nw_wells_ecl) {
836 OPM_DEFLOG_THROW(std::logic_error,
"Could not find well " << well_name <<
" in wells_ecl ", deferred_logger);
839 return this->createWellPointer(index_well_ecl, report_step);
846 template<
typename TypeTag>
848 BlackoilWellModel<TypeTag>::
849 assemble(
const int iterationIdx,
853 DeferredLogger local_deferredLogger;
854 if (this->glift_debug) {
855 const std::string msg = fmt::format(
856 "assemble() : iteration {}" , iterationIdx);
857 gliftDebug(msg, local_deferredLogger);
859 last_report_ = SimulatorReportSingle();
860 Dune::Timer perfTimer;
863 if ( ! wellsActive() ) {
867 updatePerforationIntensiveQuantities();
869 if (iterationIdx == 0) {
874 OPM_BEGIN_PARALLEL_TRY_CATCH();
876 calculateExplicitQuantities(local_deferredLogger);
877 prepareTimeStep(local_deferredLogger);
879 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"assemble() failed (It=0): ",
880 terminal_output_, grid().comm());
883 const bool well_group_control_changed = assembleImpl(iterationIdx, dt, 0, local_deferredLogger);
887 last_report_.well_group_control_changed = well_group_control_changed;
888 last_report_.assemble_time_well += perfTimer.stop();
895 template<
typename TypeTag>
897 BlackoilWellModel<TypeTag>::
898 assembleImpl(
const int iterationIdx,
900 const std::size_t recursion_level,
901 DeferredLogger& local_deferredLogger)
904 auto [well_group_control_changed, network_changed, network_imbalance] = updateWellControls(local_deferredLogger);
906 bool alq_updated =
false;
907 OPM_BEGIN_PARALLEL_TRY_CATCH();
910 initPrimaryVariablesEvaluation();
912 alq_updated = maybeDoGasLiftOptimize(local_deferredLogger);
913 assembleWellEq(dt, local_deferredLogger);
915 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"assemble() failed: ",
916 terminal_output_, grid().comm());
919 const int reportStepIdx = ebosSimulator_.episodeIndex();
920 if (alq_updated || guideRateUpdateIsNeeded(reportStepIdx)) {
921 const double simulationTime = ebosSimulator_.time();
922 const auto& comm = ebosSimulator_.vanguard().grid().comm();
923 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
924 std::vector<double> pot(numPhases(), 0.0);
925 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
926 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
927 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
931 if (network_changed) {
932 if (shouldBalanceNetwork(reportStepIdx, iterationIdx)) {
933 const auto& balance = schedule()[reportStepIdx].network_balance();
935 if (recursion_level < balance.pressure_max_iter() && network_imbalance > balance.pressure_tolerance()) {
936 well_group_control_changed = assembleImpl(iterationIdx, dt, recursion_level + 1, local_deferredLogger);
940 return well_group_control_changed;
947 template<
typename TypeTag>
949 BlackoilWellModel<TypeTag>::
950 maybeDoGasLiftOptimize(DeferredLogger& deferred_logger)
952 bool do_glift_optimization =
false;
953 int num_wells_changed = 0;
954 const double simulation_time = ebosSimulator_.time();
955 const double min_wait = ebosSimulator_.vanguard().schedule().glo(ebosSimulator_.episodeIndex()).min_wait();
960 if ( simulation_time == last_glift_opt_time_ || simulation_time >= (last_glift_opt_time_ + min_wait)) {
961 do_glift_optimization =
true;
962 last_glift_opt_time_ = simulation_time;
965 if (do_glift_optimization) {
966 GLiftOptWells glift_wells;
967 GLiftProdWells prod_wells;
968 GLiftWellStateMap state_map;
976 GLiftEclWells ecl_well_map;
977 initGliftEclWellMap(ecl_well_map);
978 GasLiftGroupInfo group_info {
980 ebosSimulator_.vanguard().schedule(),
981 ebosSimulator_.vanguard().summaryState(),
982 ebosSimulator_.episodeIndex(),
983 ebosSimulator_.model().newtonMethod().numIterations(),
987 ebosSimulator_.vanguard().grid().comm(),
990 group_info.initialize();
991 gasLiftOptimizationStage1(
992 deferred_logger, prod_wells, glift_wells, group_info, state_map);
993 gasLiftOptimizationStage2(
994 deferred_logger, prod_wells, glift_wells, state_map,
995 ebosSimulator_.episodeIndex());
996 if (this->glift_debug) gliftDebugShowALQ(deferred_logger);
997 num_wells_changed = glift_wells.size();
999 num_wells_changed = this->comm_.sum(num_wells_changed);
1000 return num_wells_changed > 0;
1003 template<
typename TypeTag>
1005 BlackoilWellModel<TypeTag>::
1006 gasLiftOptimizationStage1(DeferredLogger& deferred_logger,
1007 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
1008 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map)
1010 auto comm = ebosSimulator_.vanguard().grid().comm();
1011 int num_procs = comm.size();
1037 for (
int i = 0; i< num_procs; i++) {
1038 int num_rates_to_sync = 0;
1039 GLiftSyncGroups groups_to_sync;
1040 if (comm.rank() == i) {
1042 for (
const auto& well : well_container_) {
1044 if (group_info.hasWell(well->name())) {
1045 gasLiftOptimizationStage1SingleWell(
1046 well.get(), deferred_logger, prod_wells, glift_wells,
1047 group_info, state_map, groups_to_sync
1051 num_rates_to_sync = groups_to_sync.size();
1055 if (i == (num_procs - 1))
1057 num_rates_to_sync = comm.sum(num_rates_to_sync);
1058 if (num_rates_to_sync > 0) {
1059 std::vector<int> group_indexes;
1060 group_indexes.reserve(num_rates_to_sync);
1061 std::vector<double> group_alq_rates;
1062 group_alq_rates.reserve(num_rates_to_sync);
1063 std::vector<double> group_oil_rates;
1064 group_oil_rates.reserve(num_rates_to_sync);
1065 std::vector<double> group_gas_rates;
1066 group_gas_rates.reserve(num_rates_to_sync);
1067 std::vector<double> group_water_rates;
1068 group_water_rates.reserve(num_rates_to_sync);
1069 if (comm.rank() == i) {
1070 for (
auto idx : groups_to_sync) {
1071 auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
1072 group_indexes.push_back(idx);
1073 group_oil_rates.push_back(oil_rate);
1074 group_gas_rates.push_back(gas_rate);
1075 group_water_rates.push_back(water_rate);
1076 group_alq_rates.push_back(alq);
1079 group_indexes.resize(num_rates_to_sync);
1080 group_oil_rates.resize(num_rates_to_sync);
1081 group_gas_rates.resize(num_rates_to_sync);
1082 group_water_rates.resize(num_rates_to_sync);
1083 group_alq_rates.resize(num_rates_to_sync);
1094 EclMpiSerializer ser(comm);
1095 ser.broadcast(i, group_indexes, group_oil_rates,
1096 group_gas_rates, group_water_rates, group_alq_rates);
1098 if (comm.rank() != i) {
1099 for (
int j=0; j<num_rates_to_sync; j++) {
1100 group_info.updateRate(group_indexes[j],
1101 group_oil_rates[j], group_gas_rates[j], group_water_rates[j], group_alq_rates[j]);
1104 if (this->glift_debug) {
1106 if (comm.rank() == i) {
1107 counter = this->wellState().gliftGetDebugCounter();
1109 counter = comm.sum(counter);
1110 if (comm.rank() != i) {
1111 this->wellState().gliftSetDebugCounter(counter);
1121 template<
typename TypeTag>
1123 BlackoilWellModel<TypeTag>::
1124 gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag> *well,
1125 DeferredLogger& deferred_logger,
1126 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
1127 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map,
1128 GLiftSyncGroups& sync_groups)
1130 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1131 std::unique_ptr<GasLiftSingleWell> glift
1132 = std::make_unique<GasLiftSingleWell>(
1133 *well, ebosSimulator_, summary_state,
1134 deferred_logger, this->wellState(), this->groupState(),
1135 group_info, sync_groups, this->comm_, this->glift_debug);
1136 auto state = glift->runOptimize(
1137 ebosSimulator_.model().newtonMethod().numIterations());
1139 state_map.insert({well->name(), std::move(state)});
1140 glift_wells.insert({well->name(), std::move(glift)});
1143 prod_wells.insert({well->name(), well});
1147 template<
typename TypeTag>
1149 BlackoilWellModel<TypeTag>::
1150 initGliftEclWellMap(GLiftEclWells &ecl_well_map)
1152 for (
const auto& well: well_container_ ) {
1153 ecl_well_map.try_emplace(
1154 well->name(), &(well->wellEcl()), well->indexOfWell());
1159 template<
typename TypeTag>
1161 BlackoilWellModel<TypeTag>::
1162 assembleWellEq(
const double dt, DeferredLogger& deferred_logger)
1164 for (
auto& well : well_container_) {
1165 well->assembleWellEq(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger);
1169 template<
typename TypeTag>
1171 BlackoilWellModel<TypeTag>::
1172 apply( BVector& r)
const
1174 for (
auto& well : well_container_) {
1181 template<
typename TypeTag>
1183 BlackoilWellModel<TypeTag>::
1184 apply(
const BVector& x, BVector& Ax)
const
1186 for (
auto& well : well_container_) {
1191 template<
typename TypeTag>
1193 BlackoilWellModel<TypeTag>::
1194 getWellContributions(WellContributions& wellContribs)
const
1197 wellContribs.setBlockSize(StandardWell<TypeTag>::Indices::numEq, StandardWell<TypeTag>::numStaticWellEq);
1199 for(
unsigned int i = 0; i < well_container_.size(); i++){
1200 auto& well = well_container_[i];
1201 std::shared_ptr<StandardWell<TypeTag> > derived = std::dynamic_pointer_cast<StandardWell<TypeTag> >(well);
1203 unsigned int numBlocks;
1204 derived->getNumBlocks(numBlocks);
1205 wellContribs.addNumBlocks(numBlocks);
1210 wellContribs.alloc();
1212 for(
unsigned int i = 0; i < well_container_.size(); i++){
1213 auto& well = well_container_[i];
1215 auto derived_std = std::dynamic_pointer_cast<StandardWell<TypeTag> >(well);
1217 derived_std->addWellContribution(wellContribs);
1219 auto derived_ms = std::dynamic_pointer_cast<MultisegmentWell<TypeTag> >(well);
1221 derived_ms->addWellContribution(wellContribs);
1223 OpmLog::warning(
"Warning unknown type of well");
1230 template<
typename TypeTag>
1232 BlackoilWellModel<TypeTag>::
1233 applyScaleAdd(
const Scalar alpha,
const BVector& x, BVector& Ax)
const
1235 if (this->well_container_.empty()) {
1239 if( scaleAddRes_.size() != Ax.size() ) {
1240 scaleAddRes_.resize( Ax.size() );
1245 apply( x, scaleAddRes_ );
1247 Ax.axpy( alpha, scaleAddRes_ );
1250 template<
typename TypeTag>
1252 BlackoilWellModel<TypeTag>::
1253 addWellContributions(SparseMatrixAdapter& jacobian)
const
1255 for (
const auto& well: well_container_ ) {
1256 well->addWellContributions(jacobian);
1260 template<
typename TypeTag>
1262 BlackoilWellModel<TypeTag>::
1263 addWellPressureEquations(PressureMatrix& jacobian,
const BVector& weights,
const bool use_well_weights)
const
1265 int nw = this->numLocalWellsEnd();
1266 int rdofs = local_num_cells_;
1267 for (
int i = 0; i < nw; i++ ){
1268 int wdof = rdofs + i;
1269 jacobian[wdof][wdof] = 1.0;
1272 for (
const auto& well : well_container_ ) {
1273 well->addWellPressureEquations(jacobian, weights, pressureVarIndex, use_well_weights, this->wellState());
1277 template<
typename TypeTag>
1279 BlackoilWellModel<TypeTag>::
1280 numLocalWellsEnd()
const
1282 auto w = schedule().getWellsatEnd();
1283 w.erase(std::remove_if(w.begin(), w.end(), not_on_process_), w.end());
1287 template<
typename TypeTag>
1288 std::vector<std::vector<int>>
1289 BlackoilWellModel<TypeTag>::
1290 getMaxWellConnections()
const
1292 std::vector<std::vector<int>> wells;
1294 auto schedule_wells = schedule().getWellsatEnd();
1295 schedule_wells.erase(std::remove_if(schedule_wells.begin(), schedule_wells.end(), not_on_process_), schedule_wells.end());
1296 wells.reserve(schedule_wells.size());
1299 for (
const auto& well : schedule_wells )
1301 std::vector<int> compressed_well_perforations;
1303 const auto& completionSet = well.getConnections();
1304 compressed_well_perforations.reserve(completionSet.size());
1306 for (
const auto& connection: well.getConnections())
1308 const int compressed_idx = compressedIndexForInterior(connection.global_index());
1309 if ( compressed_idx >= 0 )
1311 compressed_well_perforations.push_back(compressed_idx);
1316 std::sort(compressed_well_perforations.begin(),
1317 compressed_well_perforations.end());
1319 wells.push_back(compressed_well_perforations);
1324 template<
typename TypeTag>
1326 BlackoilWellModel<TypeTag>::
1327 addWellPressureEquationsStruct(PressureMatrix& jacobian)
const
1329 int nw = this->numLocalWellsEnd();
1330 int rdofs = local_num_cells_;
1331 for(
int i=0; i < nw; i++){
1332 int wdof = rdofs + i;
1333 jacobian.entry(wdof,wdof) = 1.0;
1335 std::vector<std::vector<int>> wellconnections = getMaxWellConnections();
1336 for(
int i=0; i < nw; i++){
1337 const auto& perfcells = wellconnections[i];
1338 for(
int perfcell : perfcells){
1339 int wdof = rdofs + i;
1340 jacobian.entry(wdof,perfcell) = 0.0;
1341 jacobian.entry(perfcell, wdof) = 0.0;
1346 template<
typename TypeTag>
1348 BlackoilWellModel<TypeTag>::
1349 numLocalNonshutWells()
const
1351 return well_container_.size();
1354 template<
typename TypeTag>
1356 BlackoilWellModel<TypeTag>::
1357 recoverWellSolutionAndUpdateWellState(
const BVector& x)
1360 DeferredLogger local_deferredLogger;
1361 OPM_BEGIN_PARALLEL_TRY_CATCH();
1363 for (
auto& well : well_container_) {
1364 well->recoverWellSolutionAndUpdateWellState(x, this->wellState(), local_deferredLogger);
1368 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
1369 "recoverWellSolutionAndUpdateWellState() failed: ",
1370 terminal_output_, ebosSimulator_.vanguard().grid().comm());
1377 template<
typename TypeTag>
1379 BlackoilWellModel<TypeTag>::
1380 initPrimaryVariablesEvaluation()
const
1382 for (
auto& well : well_container_) {
1383 well->initPrimaryVariablesEvaluation();
1392 template<
typename TypeTag>
1394 BlackoilWellModel<TypeTag>::
1395 getWellConvergence(
const std::vector<Scalar>& B_avg,
bool checkWellGroupControls)
const
1398 DeferredLogger local_deferredLogger;
1400 ConvergenceReport local_report;
1401 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1402 for (
const auto& well : well_container_) {
1403 if (well->isOperableAndSolvable() || well->wellIsStopped()) {
1404 local_report += well->getWellConvergence(this->wellState(), B_avg, local_deferredLogger, iterationIdx > param_.strict_outer_iter_wells_ );
1406 ConvergenceReport report;
1407 using CR = ConvergenceReport;
1408 report.setWellFailed({CR::WellFailure::Type::Unsolvable, CR::Severity::Normal, -1, well->name()});
1409 local_report += report;
1413 const Opm::Parallel::Communication comm = grid().comm();
1418 if (checkWellGroupControls) {
1419 report.setWellGroupTargetsViolated(this->lastReport().well_group_control_changed);
1422 if (terminal_output_) {
1423 global_deferredLogger.logMessages();
1426 if (terminal_output_) {
1427 for (
const auto& f : report.wellFailures()) {
1428 if (f.severity() == ConvergenceReport::Severity::NotANumber) {
1429 OpmLog::debug(
"NaN residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1430 }
else if (f.severity() == ConvergenceReport::Severity::TooLarge) {
1431 OpmLog::debug(
"Too large residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1442 template<
typename TypeTag>
1448 for (
auto& well : well_container_) {
1457 template<
typename TypeTag>
1462 const auto& balance = schedule()[reportStepIdx].network_balance();
1463 if (balance.mode() == Network::Balance::CalcMode::TimeStepStart) {
1464 return iterationIdx == 0;
1465 }
else if (balance.mode() == Network::Balance::CalcMode::NUPCOL) {
1466 const int nupcol = schedule()[reportStepIdx].nupcol();
1467 return iterationIdx < nupcol;
1481 template<
typename TypeTag>
1482 std::tuple<bool, bool, double>
1483 BlackoilWellModel<TypeTag>::
1484 updateWellControls(DeferredLogger& deferred_logger)
1489 if( !wellsActive() )
return {
false,
false, 0.0 };
1491 const int episodeIdx = ebosSimulator_.episodeIndex();
1492 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1493 const auto& comm = ebosSimulator_.vanguard().grid().comm();
1494 updateAndCommunicateGroupData(episodeIdx, iterationIdx);
1496 const auto [local_network_changed, local_network_imbalance]
1497 = shouldBalanceNetwork(episodeIdx, iterationIdx) ?
1498 updateNetworkPressures(episodeIdx) : std::make_pair(false, 0.0);
1499 const bool network_changed = comm.sum(local_network_changed);
1500 const double network_imbalance = comm.max(local_network_imbalance);
1502 bool changed_well_group =
false;
1504 const int nupcol = schedule()[episodeIdx].nupcol();
1507 if (iterationIdx <= nupcol) {
1508 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1509 changed_well_group = updateGroupControls(fieldGroup, deferred_logger, episodeIdx, iterationIdx);
1512 bool changed_well_to_group =
false;
1513 for (
const auto& well : well_container_) {
1514 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Group;
1515 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1517 changed_well_to_group = changed_well || changed_well_to_group;
1521 changed_well_to_group = comm.sum(changed_well_to_group);
1522 if (changed_well_to_group) {
1523 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1524 changed_well_group =
true;
1528 bool changed_well_individual =
false;
1529 for (
const auto& well : well_container_) {
1530 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
1531 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1533 changed_well_individual = changed_well || changed_well_individual;
1536 changed_well_individual = comm.sum(changed_well_individual);
1537 if (changed_well_individual) {
1538 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1539 changed_well_group =
true;
1543 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1544 updateWsolvent(fieldGroup, episodeIdx, this->nupcolWellState());
1546 return { changed_well_group, network_changed, network_imbalance };
1550 template<
typename TypeTag>
1552 BlackoilWellModel<TypeTag>::
1553 updateAndCommunicate(
const int reportStepIdx,
1554 const int iterationIdx,
1555 DeferredLogger& deferred_logger)
1557 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
1559 for (
const auto& well : well_container_) {
1560 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
1562 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
1565 template<
typename TypeTag>
1567 BlackoilWellModel<TypeTag>::
1568 updateGroupControls(
const Group& group,
1569 DeferredLogger& deferred_logger,
1570 const int reportStepIdx,
1571 const int iterationIdx)
1573 bool changed =
false;
1574 bool changed_hc = checkGroupHigherConstraints( group, deferred_logger, reportStepIdx);
1577 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
1579 bool changed_individual = updateGroupIndividualControl( group, deferred_logger, reportStepIdx);
1580 if (changed_individual) {
1582 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
1585 for (
const std::string& groupName : group.groups()) {
1586 bool changed_this = updateGroupControls( schedule().getGroup(groupName, reportStepIdx), deferred_logger, reportStepIdx,iterationIdx);
1587 changed = changed || changed_this;
1592 template<
typename TypeTag>
1598 for (
const auto& well : well_container_) {
1599 const auto& wname = well->name();
1600 const auto wasClosed = wellTestState.well_is_closed(wname);
1601 well->checkWellOperability(ebosSimulator_, this->wellState(), local_deferredLogger);
1602 well->updateWellTestState(this->wellState().well(wname), simulationTime,
true, wellTestState, local_deferredLogger);
1604 if (!wasClosed && wellTestState.well_is_closed(wname)) {
1605 this->closed_this_step_.insert(wname);
1609 const Opm::Parallel::Communication comm = grid().comm();
1611 if (terminal_output_) {
1617 template<
typename TypeTag>
1621 std::string& exc_msg,
1622 ExceptionType::ExcEnum& exc_type,
1625 const int np = numPhases();
1626 std::vector<double> potentials;
1627 const auto& well= well_container_[widx];
1629 well->computeWellPotentials(ebosSimulator_, well_state_copy, potentials, deferred_logger);
1632 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
1636 auto& ws = this->wellState().well(well->indexOfWell());
1637 for (
int p = 0; p < np; ++p) {
1639 ws.well_potentials[p] = std::max(0.0, potentials[p]);
1645 template <
typename TypeTag>
1647 BlackoilWellModel<TypeTag>::
1648 calculateProductivityIndexValues(DeferredLogger& deferred_logger)
1650 for (
const auto& wellPtr : this->well_container_) {
1651 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
1659 template <
typename TypeTag>
1661 BlackoilWellModel<TypeTag>::
1662 calculateProductivityIndexValuesShutWells(
const int reportStepIdx,
1663 DeferredLogger& deferred_logger)
1670 for (
const auto& shutWell : this->local_shut_wells_) {
1671 if (this->wells_ecl_[shutWell].getConnections().empty()) {
1676 auto wellPtr = this->
template createTypedWellPointer
1677 <StandardWell<TypeTag>>(shutWell, reportStepIdx);
1679 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
1680 this->local_num_cells_, this->B_avg_,
true);
1682 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
1690 template <
typename TypeTag>
1692 BlackoilWellModel<TypeTag>::
1693 calculateProductivityIndexValues(
const WellInterface<TypeTag>* wellPtr,
1694 DeferredLogger& deferred_logger)
1696 wellPtr->updateProductivityIndex(this->ebosSimulator_,
1697 this->prod_index_calc_[wellPtr->indexOfWell()],
1706 template<
typename TypeTag>
1708 BlackoilWellModel<TypeTag>::
1709 prepareTimeStep(DeferredLogger& deferred_logger)
1711 for (
const auto& well : well_container_) {
1712 auto& events = this->wellState().well(well->indexOfWell()).events;
1713 if (events.hasEvent(WellState::event_mask)) {
1714 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
1715 well->updatePrimaryVariables(this->wellState(), deferred_logger);
1716 well->initPrimaryVariablesEvaluation();
1719 events.clearEvent(WellState::event_mask);
1722 if (param_.solve_welleq_initially_ && well->isOperableAndSolvable()) {
1724 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
1725 }
catch (
const std::exception& e) {
1726 const std::string msg =
"Compute initial well solution for " + well->name() +
" initially failed. Continue with the privious rates";
1727 deferred_logger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
1731 updatePrimaryVariables(deferred_logger);
1734 template<
typename TypeTag>
1736 BlackoilWellModel<TypeTag>::
1737 updateAverageFormationFactor()
1739 std::vector< Scalar > B_avg(numComponents(), Scalar() );
1740 const auto& grid = ebosSimulator_.vanguard().grid();
1741 const auto& gridView = grid.leafGridView();
1742 ElementContext elemCtx(ebosSimulator_);
1744 OPM_BEGIN_PARALLEL_TRY_CATCH();
1745 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1746 elemCtx.updatePrimaryStencil(elem);
1747 elemCtx.updatePrimaryIntensiveQuantities(0);
1749 const auto& intQuants = elemCtx.intensiveQuantities(0, 0);
1750 const auto& fs = intQuants.fluidState();
1752 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
1754 if (!FluidSystem::phaseIsActive(phaseIdx)) {
1758 const unsigned compIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx));
1759 auto& B = B_avg[ compIdx ];
1761 B += 1 / fs.invB(phaseIdx).value();
1763 if constexpr (has_solvent_) {
1764 auto& B = B_avg[solventSaturationIdx];
1765 B += 1 / intQuants.solventInverseFormationVolumeFactor().value();
1768 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::updateAverageFormationFactor() failed: ", grid.comm())
1771 grid.comm().sum(B_avg.data(), B_avg.size());
1772 for (auto& bval : B_avg)
1774 bval /= global_num_cells_;
1783 template<
typename TypeTag>
1785 BlackoilWellModel<TypeTag>::
1786 updatePrimaryVariables(DeferredLogger& deferred_logger)
1788 for (
const auto& well : well_container_) {
1789 well->updatePrimaryVariables(this->wellState(), deferred_logger);
1793 template<
typename TypeTag>
1795 BlackoilWellModel<TypeTag>::extractLegacyCellPvtRegionIndex_()
1797 const auto& grid = ebosSimulator_.vanguard().grid();
1798 const auto& eclProblem = ebosSimulator_.problem();
1799 const unsigned numCells = grid.size(0);
1801 pvt_region_idx_.resize(numCells);
1802 for (
unsigned cellIdx = 0; cellIdx < numCells; ++cellIdx) {
1803 pvt_region_idx_[cellIdx] =
1804 eclProblem.pvtRegionIndex(cellIdx);
1809 template<
typename TypeTag>
1811 BlackoilWellModel<TypeTag>::numComponents()
const
1819 if (numPhases() < 3) {
1822 int numComp = FluidSystem::numComponents;
1823 if constexpr (has_solvent_) {
1830 template<
typename TypeTag>
1832 BlackoilWellModel<TypeTag>::extractLegacyDepth_()
1834 const auto& eclProblem = ebosSimulator_.problem();
1835 depth_.resize(local_num_cells_);
1836 for (
unsigned cellIdx = 0; cellIdx < local_num_cells_; ++cellIdx) {
1837 depth_[cellIdx] = eclProblem.dofCenterDepth(cellIdx);
1841 template<
typename TypeTag>
1843 BlackoilWellModel<TypeTag>::
1844 updatePerforationIntensiveQuantities()
1846 ElementContext elemCtx(ebosSimulator_);
1847 const auto& gridView = ebosSimulator_.gridView();
1849 OPM_BEGIN_PARALLEL_TRY_CATCH();
1850 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1851 elemCtx.updatePrimaryStencil(elem);
1852 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1854 if (!is_cell_perforated_[elemIdx]) {
1857 elemCtx.updatePrimaryIntensiveQuantities(0);
1859 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::updatePerforationIntensiveQuantities() failed: ", ebosSimulator_.vanguard().grid().comm());
1863 template<
typename TypeTag>
1864 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
1865 BlackoilWellModel<TypeTag>::
1866 getWell(
const std::string& well_name)
const
1869 auto well = std::find_if(well_container_.begin(),
1870 well_container_.end(),
1871 [&well_name](
const WellInterfacePtr& elem)->bool {
1872 return elem->name() == well_name;
1875 assert(well != well_container_.end());
1880 template<
typename TypeTag>
1882 BlackoilWellModel<TypeTag>::
1883 hasWell(
const std::string& well_name)
const
1885 return std::any_of(well_container_.begin(), well_container_.end(),
1886 [&well_name](
const WellInterfacePtr& elem) ->
bool
1888 return elem->name() == well_name;
1895 template <
typename TypeTag>
1897 BlackoilWellModel<TypeTag>::
1898 reportStepIndex()
const
1900 return std::max(this->ebosSimulator_.episodeIndex(), 0);
1907 template<
typename TypeTag>
1909 BlackoilWellModel<TypeTag>::
1910 calcRates(
const int fipnum,
1912 std::vector<double>& resv_coeff)
1914 rateConverter_->calcCoeff(fipnum, pvtreg, resv_coeff);
1917 template<
typename TypeTag>
1919 BlackoilWellModel<TypeTag>::
1920 calcInjRates(
const int fipnum,
1922 std::vector<double>& resv_coeff)
1924 rateConverter_->calcInjCoeff(fipnum, pvtreg, resv_coeff);
1928 template <
typename TypeTag>
1930 BlackoilWellModel<TypeTag>::
1931 computeWellTemperature()
1936 int np = numPhases();
1937 double cellInternalEnergy;
1940 double perfPhaseRate;
1941 const int nw = numLocalWells();
1942 for (
auto wellID = 0*nw; wellID < nw; ++wellID) {
1943 const Well& well = wells_ecl_[wellID];
1944 if (well.isInjector())
1948 for (
int i = 0; i < wellID; ++i) {
1949 connpos += well_perf_data_[i].size();
1952 std::array<double,2> weighted{0.0,0.0};
1953 auto& [weighted_temperature, total_weight] = weighted;
1955 auto& well_info = local_parallel_well_info_[wellID].get();
1956 const int num_perf_this_well = well_info.communication().sum(well_perf_data_[wellID].size());
1957 auto& ws = this->wellState().well(wellID);
1958 auto& perf_data = ws.perf_data;
1959 auto& perf_phase_rate = perf_data.phase_rates;
1961 for (
int perf = 0; perf < num_perf_this_well; ++perf) {
1962 const int cell_idx = well_perf_data_[wellID][perf].cell_index;
1963 const auto& intQuants = *(ebosSimulator_.model().cachedIntensiveQuantities(cell_idx, 0));
1964 const auto& fs = intQuants.fluidState();
1967 double cellTemperatures = fs.temperature(0).value();
1969 double weight_factor = 0.0;
1970 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
1972 if (!FluidSystem::phaseIsActive(phaseIdx)) {
1975 cellInternalEnergy = fs.enthalpy(phaseIdx).value() - fs.pressure(phaseIdx).value() / fs.density(phaseIdx).value();
1976 cellBinv = fs.invB(phaseIdx).value();
1977 cellDensity = fs.density(phaseIdx).value();
1978 perfPhaseRate = perf_phase_rate[ perf*np + phaseIdx ];
1979 weight_factor += cellDensity * perfPhaseRate/cellBinv * cellInternalEnergy/cellTemperatures;
1981 total_weight += weight_factor;
1982 weighted_temperature += weight_factor * cellTemperatures;
1984 well_info.communication().sum(weighted.data(), 2);
1985 this->wellState().well(wellID).temperature = weighted_temperature/total_weight;
1991 template <
typename TypeTag>
1993 BlackoilWellModel<TypeTag>::
1994 assignWellTracerRates(data::Wells& wsrpt)
const
1996 const auto & wellTracerRates = ebosSimulator_.problem().tracerModel().getWellTracerRates();
1998 if (wellTracerRates.empty())
2001 for (
const auto& wTR : wellTracerRates) {
2002 std::string wellName = wTR.first.first;
2003 auto xwPos = wsrpt.find(wellName);
2004 if (xwPos == wsrpt.end()) {
2007 std::string tracerName = wTR.first.second;
2008 double rate = wTR.second;
2009 xwPos->second.rates.set(data::Rates::opt::tracer, rate, tracerName);
Class for handling the blackoil well model.
Definition: BlackoilWellModel.hpp:94
void calculateExplicitQuantities(DeferredLogger &deferred_logger) const
Calculating the explict quantities used in the well calculation.
Definition: BlackoilWellModel_impl.hpp:1445
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:56
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:205
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