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>
29#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
30#include <opm/simulators/wells/VFPProperties.hpp>
31#include <opm/simulators/utils/MPIPacker.hpp>
32#include <opm/simulators/linalg/bda/WellContributions.hpp>
35#include <ebos/eclmpiserializer.hh>
41#include <fmt/format.h>
44 template<
typename TypeTag>
45 BlackoilWellModel<TypeTag>::
46 BlackoilWellModel(Simulator& ebosSimulator,
const PhaseUsage& phase_usage)
47 : BlackoilWellModelGeneric(ebosSimulator.vanguard().schedule(),
48 ebosSimulator.vanguard().summaryState(),
49 ebosSimulator.vanguard().eclState(),
51 ebosSimulator.gridView().comm())
52 , ebosSimulator_(ebosSimulator)
54 terminal_output_ = ((ebosSimulator.gridView().comm().rank() == 0) &&
55 EWOMS_GET_PARAM(TypeTag,
bool, EnableTerminalOutput));
57 local_num_cells_ = ebosSimulator_.gridView().size(0);
60 global_num_cells_ = ebosSimulator_.vanguard().globalNumCells();
63 auto& parallel_wells = ebosSimulator.vanguard().parallelWells();
65 this->parallel_well_info_.reserve(parallel_wells.size());
66 for(
const auto& name_bool : parallel_wells) {
67 this->parallel_well_info_.emplace_back(name_bool, grid().comm());
71 this->alternative_well_rate_init_ =
72 EWOMS_GET_PARAM(TypeTag,
bool, AlternativeWellRateInit);
75 template<
typename TypeTag>
76 BlackoilWellModel<TypeTag>::
77 BlackoilWellModel(Simulator& ebosSimulator) :
78 BlackoilWellModel(ebosSimulator,
phaseUsageFromDeck(ebosSimulator.vanguard().eclState()))
82 template<
typename TypeTag>
84 BlackoilWellModel<TypeTag>::
87 extractLegacyCellPvtRegionIndex_();
88 extractLegacyDepth_();
90 gravity_ = ebosSimulator_.problem().gravity()[2];
95 ebosSimulator_.model().addAuxiliaryModule(
this);
97 is_cell_perforated_.resize(local_num_cells_,
false);
101 template<
typename TypeTag>
103 BlackoilWellModel<TypeTag>::
104 initWellContainer(
const int reportStepIdx)
106 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
107 + ScheduleEvents::NEW_WELL;
108 const auto& events = schedule()[reportStepIdx].wellgroup_events();
109 for (
auto& wellPtr : this->well_container_) {
110 const bool well_opened_this_step = report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
111 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
112 this->local_num_cells_, this->B_avg_, well_opened_this_step);
116 template<
typename TypeTag>
118 BlackoilWellModel<TypeTag>::
119 addNeighbors(std::vector<NeighborSet>& neighbors)
const
121 if (!param_.matrix_add_well_contributions_) {
126 const auto& schedule_wells = schedule().getWellsatEnd();
129 for (
const auto& well : schedule_wells)
131 std::vector<int> wellCells = this->getCellsForConnections(well);
132 for (
int cellIdx : wellCells) {
133 neighbors[cellIdx].insert(wellCells.begin(),
139 template<
typename TypeTag>
141 BlackoilWellModel<TypeTag>::
142 linearize(SparseMatrixAdapter& jacobian, GlobalEqVector& res)
144 if (!param_.matrix_add_well_contributions_)
146 OPM_BEGIN_PARALLEL_TRY_CATCH();
150 for (
const auto& well: well_container_) {
155 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::linearize failed: ",
156 ebosSimulator_.gridView().comm());
160 for (
const auto& well: well_container_) {
161 well->addWellContributions(jacobian);
170 template<
typename TypeTag>
172 BlackoilWellModel<TypeTag>::
173 beginReportStep(
const int timeStepIdx)
175 DeferredLogger local_deferredLogger;
177 report_step_starts_ =
true;
179 const Grid& grid = ebosSimulator_.vanguard().grid();
180 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
182 wells_ecl_ = getLocalWells(timeStepIdx);
183 this->local_parallel_well_info_ = createLocalParallelWellInfo(wells_ecl_);
188 OPM_BEGIN_PARALLEL_TRY_CATCH();
193 this->initializeWellPerfData();
194 this->initializeWellState(timeStepIdx, summaryState);
197 if (param_.use_multisegment_well_&& anyMSWellOpenLocal()) {
198 this->wellState().initWellStateMSWell(wells_ecl_, &this->prevWellState());
201 const Group& fieldGroup = schedule().getGroup(
"FIELD", timeStepIdx);
202 WellGroupHelpers::setCmodeGroup(fieldGroup, schedule(), summaryState, timeStepIdx, this->wellState(), this->groupState());
205 rateConverter_ = std::make_unique<RateConverterType>(phase_usage_,
206 std::vector<int>(local_num_cells_, 0));
207 rateConverter_->template defineState<ElementContext>(ebosSimulator_);
210 if (schedule_[timeStepIdx].has_gpmaint()) {
211 WellGroupHelpers::setRegionAveragePressureCalculator(fieldGroup, schedule(),
212 timeStepIdx, this->eclState_.fieldProps(), phase_usage_, regionalAveragePressureCalculator_);
216 const auto& sched_state = this->schedule()[timeStepIdx];
218 vfp_properties_ = std::make_unique<VFPProperties>(sched_state.vfpinj(),
219 sched_state.vfpprod(),
220 this->prevWellState());
221 this->initializeWellProdIndCalculators();
222 if (sched_state.events().hasEvent(ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX)) {
223 this->runWellPIScaling(timeStepIdx, local_deferredLogger);
227 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"beginReportStep() failed: ",
228 terminal_output_, grid.comm());
230 this->commitWGState();
235 template<
typename TypeTag>
237 BlackoilWellModel<TypeTag>::
240 OPM_TIMEBLOCK(beginTimeStep);
241 updatePerforationIntensiveQuantities();
242 updateAverageFormationFactor();
243 DeferredLogger local_deferredLogger;
244 switched_prod_groups_.clear();
245 switched_inj_groups_.clear();
247 this->resetWGState();
248 const int reportStepIdx = ebosSimulator_.episodeIndex();
249 updateAndCommunicateGroupData(reportStepIdx,
250 ebosSimulator_.model().newtonMethod().numIterations());
251 this->wellState().gliftTimeStepInit();
252 const double simulationTime = ebosSimulator_.time();
253 OPM_BEGIN_PARALLEL_TRY_CATCH();
256 wellTesting(reportStepIdx, simulationTime, local_deferredLogger);
259 createWellContainer(reportStepIdx);
262 const Grid& grid = ebosSimulator_.vanguard().grid();
263 wells_active_ = !this->well_container_.empty();
264 wells_active_ = grid.comm().max(wells_active_);
269 this->initWellContainer(reportStepIdx);
272 std::fill(is_cell_perforated_.begin(), is_cell_perforated_.end(),
false);
273 for (
auto& well : well_container_) {
274 well->updatePerforatedCell(is_cell_perforated_);
278 calculateEfficiencyFactors(reportStepIdx);
280 if constexpr (has_polymer_)
282 if (PolymerModule::hasPlyshlog() || getPropValue<TypeTag, Properties::EnablePolymerMW>() ) {
283 setRepRadiusPerfLength();
288 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"beginTimeStep() failed: ",
289 terminal_output_, ebosSimulator_.vanguard().grid().comm());
291 for (
auto& well : well_container_) {
292 well->setVFPProperties(vfp_properties_.get());
293 well->setGuideRate(&guideRate_);
297 for (
auto& well : well_container_) {
298 well->closeCompletions(wellTestState());
301 if (alternative_well_rate_init_) {
306 for (
auto& well : well_container_) {
307 if (well->isProducer()) {
308 well->updateWellStateRates(ebosSimulator_, this->wellState(), local_deferredLogger);
315 updateWellPotentials(reportStepIdx,
317 ebosSimulator_.vanguard().summaryConfig(),
318 local_deferredLogger);
319 }
catch ( std::runtime_error& e ) {
320 const std::string msg =
"A zero well potential is returned for output purposes. ";
321 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
325 const auto& comm = ebosSimulator_.vanguard().grid().comm();
326 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
327 std::vector<double> pot(numPhases(), 0.0);
328 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
329 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
330 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
332 auto exc_type = ExceptionType::NONE;
334 if (schedule_[reportStepIdx].has_gpmaint()) {
335 for (
auto& calculator : regionalAveragePressureCalculator_) {
336 calculator.second->template defineState<ElementContext>(ebosSimulator_);
338 const double dt = ebosSimulator_.timeStepSize();
339 WellGroupHelpers::updateGpMaintTargetForGroups(fieldGroup,
340 schedule_, regionalAveragePressureCalculator_, reportStepIdx, dt, this->wellState(), this->groupState());
344 for (
auto& well : well_container_) {
345 const uint64_t effective_events_mask = ScheduleEvents::WELL_STATUS_CHANGE
346 + ScheduleEvents::INJECTION_TYPE_CHANGED
347 + ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER
348 + ScheduleEvents::NEW_WELL;
350 const auto& events = schedule()[reportStepIdx].wellgroup_events();
351 const bool event = report_step_starts_ && events.hasEvent(well->name(), effective_events_mask);
352 const bool dyn_status_change = this->wellState().well(well->name()).status
353 != this->prevWellState().well(well->name()).status;
355 if (event || dyn_status_change) {
357 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), local_deferredLogger);
358 well->calculateExplicitQuantities(ebosSimulator_, this->wellState(), local_deferredLogger);
359 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), local_deferredLogger);
360 }
catch (
const std::exception& e) {
361 const std::string msg =
"Compute initial well solution for new well " + well->name() +
" failed. Continue with zero initial rates";
362 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
368 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
370 if (exc_type != ExceptionType::NONE) {
371 const std::string msg =
"Compute initial well solution for new wells failed. Continue with zero initial rates";
372 local_deferredLogger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
375 logAndCheckForExceptionsAndThrow(local_deferredLogger,
376 exc_type,
"beginTimeStep() failed: " + exc_msg, terminal_output_, comm);
380 template<
typename TypeTag>
382 BlackoilWellModel<TypeTag>::wellTesting(
const int timeStepIdx,
383 const double simulationTime,
384 DeferredLogger& deferred_logger)
386 for (
const std::string& well_name : this->getWellsForTesting(timeStepIdx, simulationTime)) {
387 const Well& wellEcl = schedule().getWell(well_name, timeStepIdx);
388 if (wellEcl.getStatus() == Well::Status::SHUT)
391 WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx, deferred_logger);
393 well->init(&phase_usage_, depth_, gravity_, local_num_cells_, B_avg_,
true);
395 double well_efficiency_factor = wellEcl.getEfficiencyFactor();
396 WellGroupHelpers::accumulateGroupEfficiencyFactor(schedule().getGroup(wellEcl.groupName(), timeStepIdx),
397 schedule(), timeStepIdx, well_efficiency_factor);
399 well->setWellEfficiencyFactor(well_efficiency_factor);
400 well->setVFPProperties(vfp_properties_.get());
401 well->setGuideRate(&guideRate_);
403 well->wellTesting(ebosSimulator_, simulationTime, this->wellState(), this->groupState(), wellTestState(), deferred_logger);
412 template<
typename TypeTag>
414 BlackoilWellModel<TypeTag>::
418 for (
auto&& pinfo : this->local_parallel_well_info_)
429 template<
typename TypeTag>
430 const SimulatorReportSingle&
431 BlackoilWellModel<TypeTag>::
432 lastReport()
const {
return last_report_; }
439 template<
typename TypeTag>
441 BlackoilWellModel<TypeTag>::
442 timeStepSucceeded(
const double& simulationTime,
const double dt)
444 this->closed_this_step_.clear();
447 report_step_starts_ =
false;
448 const int reportStepIdx = ebosSimulator_.episodeIndex();
450 DeferredLogger local_deferredLogger;
451 for (
const auto& well : well_container_) {
452 if (getPropValue<TypeTag, Properties::EnablePolymerMW>() && well->isInjector()) {
453 well->updateWaterThroughput(dt, this->wellState());
457 for (
const auto& well : well_container_) {
458 well->reportWellSwitching(this->wellState().well(well->indexOfWell()), local_deferredLogger);
461 if (terminal_output_) {
463 for (
const auto& [name, to] : switched_prod_groups_) {
464 const Group::ProductionCMode& oldControl = this->prevWGState().group_state.production_control(name);
465 std::string from = Group::ProductionCMode2String(oldControl);
467 std::string msg =
" Production Group " + name
468 +
" control mode changed from ";
471 local_deferredLogger.info(msg);
474 for (
const auto& [key, to] : switched_inj_groups_) {
475 const std::string& name = key.first;
476 const Opm::Phase& phase = key.second;
478 const Group::InjectionCMode& oldControl = this->prevWGState().group_state.injection_control(name, phase);
479 std::string from = Group::InjectionCMode2String(oldControl);
481 std::string msg =
" Injection Group " + name
482 +
" control mode changed from ";
485 local_deferredLogger.info(msg);
491 rateConverter_->template defineState<ElementContext>(ebosSimulator_);
495 updateWellPotentials(reportStepIdx,
497 ebosSimulator_.vanguard().summaryConfig(),
498 local_deferredLogger);
499 }
catch ( std::runtime_error& e ) {
500 const std::string msg =
"A zero well potential is returned for output purposes. ";
501 local_deferredLogger.warning(
"WELL_POTENTIAL_CALCULATION_FAILED", msg);
504 updateWellTestState(simulationTime, wellTestState());
507 const Group& fieldGroup = schedule_.getGroup(
"FIELD", reportStepIdx);
508 checkGconsaleLimits(fieldGroup, this->wellState(),
509 ebosSimulator_.episodeIndex(), local_deferredLogger);
511 this->calculateProductivityIndexValues(local_deferredLogger);
513 this->commitWGState();
515 const Opm::Parallel::Communication& comm = grid().comm();
517 if (terminal_output_) {
518 global_deferredLogger.logMessages();
522 this->computeWellTemperature();
526 template<
typename TypeTag>
528 BlackoilWellModel<TypeTag>::
529 computeTotalRatesForDof(RateVector& rate,
530 unsigned elemIdx)
const
534 if (!is_cell_perforated_[elemIdx])
537 for (
const auto& well : well_container_)
538 well->addCellRates(rate, elemIdx);
542 template<
typename TypeTag>
543 template <
class Context>
545 BlackoilWellModel<TypeTag>::
546 computeTotalRatesForDof(RateVector& rate,
547 const Context& context,
549 unsigned timeIdx)
const
552 int elemIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
554 if (!is_cell_perforated_[elemIdx])
557 for (
const auto& well : well_container_)
558 well->addCellRates(rate, elemIdx);
563 template<
typename TypeTag>
565 BlackoilWellModel<TypeTag>::
566 initializeWellState(
const int timeStepIdx,
567 const SummaryState& summaryState)
569 std::vector<double> cellPressures(this->local_num_cells_, 0.0);
570 ElementContext elemCtx(ebosSimulator_);
572 const auto& gridView = ebosSimulator_.vanguard().gridView();
574 OPM_BEGIN_PARALLEL_TRY_CATCH();
575 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
576 elemCtx.updatePrimaryStencil(elem);
577 elemCtx.updatePrimaryIntensiveQuantities(0);
579 const auto& fs = elemCtx.intensiveQuantities(0, 0).fluidState();
581 double& perf_pressure = cellPressures[elemCtx.globalSpaceIndex(0, 0)];
582 if (Indices::oilEnabled) {
583 perf_pressure = fs.pressure(FluidSystem::oilPhaseIdx).value();
584 }
else if (Indices::waterEnabled) {
585 perf_pressure = fs.pressure(FluidSystem::waterPhaseIdx).value();
587 perf_pressure = fs.pressure(FluidSystem::gasPhaseIdx).value();
590 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::initializeWellState() failed: ", ebosSimulator_.vanguard().grid().comm());
592 this->wellState().init(cellPressures, schedule(), wells_ecl_, local_parallel_well_info_, timeStepIdx,
593 &this->prevWellState(), well_perf_data_,
601 template<
typename TypeTag>
603 BlackoilWellModel<TypeTag>::
604 createWellContainer(
const int time_step)
606 DeferredLogger local_deferredLogger;
608 const int nw = numLocalWells();
610 well_container_.clear();
613 well_container_.reserve(nw);
615 for (
int w = 0; w < nw; ++w) {
616 const Well& well_ecl = wells_ecl_[w];
618 if (!well_ecl.hasConnections()) {
623 const std::string& well_name = well_ecl.name();
624 const auto well_status = this->schedule()
625 .getWell(well_name, time_step).getStatus();
627 if ((well_ecl.getStatus() == Well::Status::SHUT) ||
628 (well_status == Well::Status::SHUT))
631 if (well_ecl.getStatus() != Well::Status::SHUT) {
632 this->closed_this_step_.insert(well_name);
633 this->wellState().shutWell(w);
640 if (this->wellTestState().well_is_closed(well_name)) {
643 auto& events = this->wellState().well(w).events;
644 if (events.hasEvent(WellState::event_mask)) {
645 if (wellTestState().lastTestTime(well_name) == ebosSimulator_.time()) {
650 events.clearEvent(WellState::event_mask);
652 wellTestState().open_well(well_name);
653 wellTestState().open_completions(well_name);
660 bool wellIsStopped =
false;
661 if (wellTestState().well_is_closed(well_name))
663 if (well_ecl.getAutomaticShutIn()) {
665 this->wellState().shutWell(w);
668 if (!well_ecl.getAllowCrossFlow()) {
671 this->wellState().shutWell(w);
675 this->wellState().stopWell(w);
676 wellIsStopped =
true;
682 if (!well_ecl.getAllowCrossFlow() && well_ecl.isProducer() && well_ecl.predictionMode()) {
683 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
684 const auto prod_controls = well_ecl.productionControls(summaryState);
686 auto is_zero = [](
const double x)
688 return std::isfinite(x) && !std::isnormal(x);
691 bool zero_rate_control =
false;
692 switch (prod_controls.cmode) {
693 case Well::ProducerCMode::ORAT:
694 zero_rate_control = is_zero(prod_controls.oil_rate);
697 case Well::ProducerCMode::WRAT:
698 zero_rate_control = is_zero(prod_controls.water_rate);
701 case Well::ProducerCMode::GRAT:
702 zero_rate_control = is_zero(prod_controls.gas_rate);
705 case Well::ProducerCMode::LRAT:
706 zero_rate_control = is_zero(prod_controls.liquid_rate);
709 case Well::ProducerCMode::RESV:
710 zero_rate_control = is_zero(prod_controls.resv_rate);
714 zero_rate_control =
false;
718 if (zero_rate_control) {
720 local_deferredLogger.info(
" Well shut due to zero rate control and disallowing crossflow: " + well_ecl.name());
721 this->wellState().shutWell(w);
726 if (well_status == Well::Status::STOP) {
727 this->wellState().stopWell(w);
728 wellIsStopped =
true;
731 well_container_.emplace_back(this->createWellPointer(w, time_step));
734 well_container_.back()->stopWell();
740 const Opm::Parallel::Communication& comm = grid().comm();
742 if (terminal_output_) {
743 global_deferredLogger.logMessages();
746 well_container_generic_.clear();
747 for (
auto& w : well_container_)
748 well_container_generic_.push_back(w.get());
755 template <
typename TypeTag>
756 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
757 BlackoilWellModel<TypeTag>::
758 createWellPointer(
const int wellID,
const int time_step)
const
760 const auto is_multiseg = this->wells_ecl_[wellID].isMultiSegment();
762 if (! (this->param_.use_multisegment_well_ && is_multiseg)) {
763 return this->
template createTypedWellPointer<StandardWell<TypeTag>>(wellID, time_step);
766 return this->
template createTypedWellPointer<MultisegmentWell<TypeTag>>(wellID, time_step);
774 template <
typename TypeTag>
775 template <
typename WellType>
776 std::unique_ptr<WellType>
777 BlackoilWellModel<TypeTag>::
778 createTypedWellPointer(
const int wellID,
const int time_step)
const
781 const auto& perf_data = this->well_perf_data_[wellID];
784 const auto pvtreg = perf_data.empty()
785 ? 0 : pvt_region_idx_[perf_data.front().cell_index];
787 const auto& parallel_well_info = this->local_parallel_well_info_[wellID].get();
788 const auto global_pvtreg = parallel_well_info.broadcastFirstPerforationValue(pvtreg);
790 return std::make_unique<WellType>(this->wells_ecl_[wellID],
794 *this->rateConverter_,
796 this->numComponents(),
806 template<
typename TypeTag>
807 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
808 BlackoilWellModel<TypeTag>::
809 createWellForWellTest(
const std::string& well_name,
810 const int report_step,
811 DeferredLogger& deferred_logger)
const
814 const int nw_wells_ecl = wells_ecl_.size();
815 int index_well_ecl = 0;
816 for (; index_well_ecl < nw_wells_ecl; ++index_well_ecl) {
817 if (well_name == wells_ecl_[index_well_ecl].name()) {
822 if (index_well_ecl == nw_wells_ecl) {
823 OPM_DEFLOG_THROW(std::logic_error,
824 fmt::format(
"Could not find well {} in wells_ecl ", well_name),
828 return this->createWellPointer(index_well_ecl, report_step);
835 template<
typename TypeTag>
837 BlackoilWellModel<TypeTag>::
838 assemble(
const int iterationIdx,
842 DeferredLogger local_deferredLogger;
843 if (this->glift_debug) {
844 const std::string msg = fmt::format(
845 "assemble() : iteration {}" , iterationIdx);
846 gliftDebug(msg, local_deferredLogger);
848 last_report_ = SimulatorReportSingle();
849 Dune::Timer perfTimer;
852 if ( ! wellsActive() ) {
856 updatePerforationIntensiveQuantities();
858 if (iterationIdx == 0) {
863 OPM_BEGIN_PARALLEL_TRY_CATCH();
865 calculateExplicitQuantities(local_deferredLogger);
866 prepareTimeStep(local_deferredLogger);
868 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
869 "assemble() failed (It=0): ",
870 terminal_output_, grid().comm());
873 const bool well_group_control_changed = assembleImpl(iterationIdx, dt, 0, local_deferredLogger);
877 last_report_.well_group_control_changed = well_group_control_changed;
878 last_report_.assemble_time_well += perfTimer.stop();
885 template<
typename TypeTag>
887 BlackoilWellModel<TypeTag>::
888 assembleImpl(
const int iterationIdx,
890 const std::size_t recursion_level,
891 DeferredLogger& local_deferredLogger)
894 auto [well_group_control_changed, network_changed, network_imbalance] = updateWellControls(local_deferredLogger);
896 bool alq_updated =
false;
897 OPM_BEGIN_PARALLEL_TRY_CATCH();
900 initPrimaryVariablesEvaluation();
902 alq_updated = maybeDoGasLiftOptimize(local_deferredLogger);
903 assembleWellEq(dt, local_deferredLogger);
905 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
"assemble() failed: ",
906 terminal_output_, grid().comm());
909 const int reportStepIdx = ebosSimulator_.episodeIndex();
910 if (alq_updated || BlackoilWellModelGuideRates(*this).
911 guideRateUpdateIsNeeded(reportStepIdx)) {
912 const double simulationTime = ebosSimulator_.time();
913 const auto& comm = ebosSimulator_.vanguard().grid().comm();
914 const auto& summaryState = ebosSimulator_.vanguard().summaryState();
915 std::vector<double> pot(numPhases(), 0.0);
916 const Group& fieldGroup = schedule().getGroup(
"FIELD", reportStepIdx);
917 WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
918 this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
922 if (network_changed) {
923 if (shouldBalanceNetwork(reportStepIdx, iterationIdx) &&
924 shouldIterateNetwork(reportStepIdx, recursion_level, network_imbalance)) {
925 well_group_control_changed = assembleImpl(iterationIdx, dt, recursion_level + 1, local_deferredLogger);
928 return well_group_control_changed;
935 template<
typename TypeTag>
937 BlackoilWellModel<TypeTag>::
938 maybeDoGasLiftOptimize(DeferredLogger& deferred_logger)
940 bool do_glift_optimization =
false;
941 int num_wells_changed = 0;
942 const double simulation_time = ebosSimulator_.time();
943 const double min_wait = ebosSimulator_.vanguard().schedule().glo(ebosSimulator_.episodeIndex()).min_wait();
948 if ( simulation_time == last_glift_opt_time_ || simulation_time >= (last_glift_opt_time_ + min_wait)) {
949 do_glift_optimization =
true;
950 last_glift_opt_time_ = simulation_time;
953 if (do_glift_optimization) {
954 GLiftOptWells glift_wells;
955 GLiftProdWells prod_wells;
956 GLiftWellStateMap state_map;
964 GLiftEclWells ecl_well_map;
965 initGliftEclWellMap(ecl_well_map);
966 GasLiftGroupInfo group_info {
968 ebosSimulator_.vanguard().schedule(),
969 ebosSimulator_.vanguard().summaryState(),
970 ebosSimulator_.episodeIndex(),
971 ebosSimulator_.model().newtonMethod().numIterations(),
976 ebosSimulator_.vanguard().grid().comm(),
979 group_info.initialize();
980 gasLiftOptimizationStage1(
981 deferred_logger, prod_wells, glift_wells, group_info, state_map);
982 gasLiftOptimizationStage2(
983 deferred_logger, prod_wells, glift_wells, group_info, state_map,
984 ebosSimulator_.episodeIndex());
985 if (this->glift_debug) gliftDebugShowALQ(deferred_logger);
986 num_wells_changed = glift_wells.size();
988 num_wells_changed = this->comm_.sum(num_wells_changed);
989 return num_wells_changed > 0;
992 template<
typename TypeTag>
994 BlackoilWellModel<TypeTag>::
995 gasLiftOptimizationStage1(DeferredLogger& deferred_logger,
996 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
997 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map)
999 auto comm = ebosSimulator_.vanguard().grid().comm();
1000 int num_procs = comm.size();
1026 for (
int i = 0; i< num_procs; i++) {
1027 int num_rates_to_sync = 0;
1028 GLiftSyncGroups groups_to_sync;
1029 if (comm.rank() == i) {
1031 for (
const auto& well : well_container_) {
1033 if (group_info.hasWell(well->name())) {
1034 gasLiftOptimizationStage1SingleWell(
1035 well.get(), deferred_logger, prod_wells, glift_wells,
1036 group_info, state_map, groups_to_sync
1040 num_rates_to_sync = groups_to_sync.size();
1042 num_rates_to_sync = comm.sum(num_rates_to_sync);
1043 if (num_rates_to_sync > 0) {
1044 std::vector<int> group_indexes;
1045 group_indexes.reserve(num_rates_to_sync);
1046 std::vector<double> group_alq_rates;
1047 group_alq_rates.reserve(num_rates_to_sync);
1048 std::vector<double> group_oil_rates;
1049 group_oil_rates.reserve(num_rates_to_sync);
1050 std::vector<double> group_gas_rates;
1051 group_gas_rates.reserve(num_rates_to_sync);
1052 std::vector<double> group_water_rates;
1053 group_water_rates.reserve(num_rates_to_sync);
1054 if (comm.rank() == i) {
1055 for (
auto idx : groups_to_sync) {
1056 auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
1057 group_indexes.push_back(idx);
1058 group_oil_rates.push_back(oil_rate);
1059 group_gas_rates.push_back(gas_rate);
1060 group_water_rates.push_back(water_rate);
1061 group_alq_rates.push_back(alq);
1064 group_indexes.resize(num_rates_to_sync);
1065 group_oil_rates.resize(num_rates_to_sync);
1066 group_gas_rates.resize(num_rates_to_sync);
1067 group_water_rates.resize(num_rates_to_sync);
1068 group_alq_rates.resize(num_rates_to_sync);
1071 EclMpiSerializer ser(comm);
1072 ser.broadcast(i, group_indexes, group_oil_rates,
1073 group_gas_rates, group_water_rates, group_alq_rates);
1075 if (comm.rank() != i) {
1076 for (
int j=0; j<num_rates_to_sync; j++) {
1077 group_info.updateRate(group_indexes[j],
1078 group_oil_rates[j], group_gas_rates[j], group_water_rates[j], group_alq_rates[j]);
1081 if (this->glift_debug) {
1083 if (comm.rank() == i) {
1084 counter = this->wellState().gliftGetDebugCounter();
1086 counter = comm.sum(counter);
1087 if (comm.rank() != i) {
1088 this->wellState().gliftSetDebugCounter(counter);
1098 template<
typename TypeTag>
1100 BlackoilWellModel<TypeTag>::
1101 gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag> *well,
1102 DeferredLogger& deferred_logger,
1103 GLiftProdWells &prod_wells, GLiftOptWells &glift_wells,
1104 GasLiftGroupInfo &group_info, GLiftWellStateMap &state_map,
1105 GLiftSyncGroups& sync_groups)
1107 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1108 std::unique_ptr<GasLiftSingleWell> glift
1109 = std::make_unique<GasLiftSingleWell>(
1110 *well, ebosSimulator_, summary_state,
1111 deferred_logger, this->wellState(), this->groupState(),
1112 group_info, sync_groups, this->comm_, this->glift_debug);
1113 auto state = glift->runOptimize(
1114 ebosSimulator_.model().newtonMethod().numIterations());
1116 state_map.insert({well->name(), std::move(state)});
1117 glift_wells.insert({well->name(), std::move(glift)});
1120 prod_wells.insert({well->name(), well});
1124 template<
typename TypeTag>
1126 BlackoilWellModel<TypeTag>::
1127 initGliftEclWellMap(GLiftEclWells &ecl_well_map)
1129 for (
const auto& well: well_container_ ) {
1130 ecl_well_map.try_emplace(
1131 well->name(), &(well->wellEcl()), well->indexOfWell());
1136 template<
typename TypeTag>
1138 BlackoilWellModel<TypeTag>::
1139 assembleWellEq(
const double dt, DeferredLogger& deferred_logger)
1141 for (
auto& well : well_container_) {
1142 well->assembleWellEq(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger);
1146 template<
typename TypeTag>
1148 BlackoilWellModel<TypeTag>::
1149 apply( BVector& r)
const
1151 for (
auto& well : well_container_) {
1158 template<
typename TypeTag>
1160 BlackoilWellModel<TypeTag>::
1161 apply(
const BVector& x, BVector& Ax)
const
1163 for (
auto& well : well_container_) {
1168 template<
typename TypeTag>
1170 BlackoilWellModel<TypeTag>::
1171 getWellContributions(WellContributions& wellContribs)
const
1174 wellContribs.setBlockSize(StandardWell<TypeTag>::Indices::numEq, StandardWell<TypeTag>::numStaticWellEq);
1176 for(
unsigned int i = 0; i < well_container_.size(); i++){
1177 auto& well = well_container_[i];
1178 std::shared_ptr<StandardWell<TypeTag> > derived = std::dynamic_pointer_cast<StandardWell<TypeTag> >(well);
1180 wellContribs.addNumBlocks(derived->linSys().getNumBlocks());
1185 wellContribs.alloc();
1187 for(
unsigned int i = 0; i < well_container_.size(); i++){
1188 auto& well = well_container_[i];
1190 auto derived_std = std::dynamic_pointer_cast<StandardWell<TypeTag>>(well);
1192 derived_std->linSys().extract(derived_std->numStaticWellEq, wellContribs);
1194 auto derived_ms = std::dynamic_pointer_cast<MultisegmentWell<TypeTag> >(well);
1196 derived_ms->linSys().extract(wellContribs);
1198 OpmLog::warning(
"Warning unknown type of well");
1205 template<
typename TypeTag>
1207 BlackoilWellModel<TypeTag>::
1208 applyScaleAdd(
const Scalar alpha,
const BVector& x, BVector& Ax)
const
1210 if (this->well_container_.empty()) {
1214 if( scaleAddRes_.size() != Ax.size() ) {
1215 scaleAddRes_.resize( Ax.size() );
1220 apply( x, scaleAddRes_ );
1222 Ax.axpy( alpha, scaleAddRes_ );
1225 template<
typename TypeTag>
1227 BlackoilWellModel<TypeTag>::
1228 addWellContributions(SparseMatrixAdapter& jacobian)
const
1230 for (
const auto& well: well_container_ ) {
1231 well->addWellContributions(jacobian);
1235 template<
typename TypeTag>
1237 BlackoilWellModel<TypeTag>::
1238 addWellPressureEquations(PressureMatrix& jacobian,
const BVector& weights,
const bool use_well_weights)
const
1240 int nw = this->numLocalWellsEnd();
1241 int rdofs = local_num_cells_;
1242 for (
int i = 0; i < nw; i++ ){
1243 int wdof = rdofs + i;
1244 jacobian[wdof][wdof] = 1.0;
1247 for (
const auto& well : well_container_ ) {
1248 well->addWellPressureEquations(jacobian, weights, pressureVarIndex, use_well_weights, this->wellState());
1252 template <
typename TypeTag>
1253 void BlackoilWellModel<TypeTag>::
1254 addReservoirSourceTerms(GlobalEqVector& residual,
1255 std::vector<typename SparseMatrixAdapter::MatrixBlock*>& diagMatAddress)
const
1260 for (
const auto& well : well_container_) {
1261 if (!well->isOperableAndSolvable() && !well->wellIsStopped()) {
1264 const auto& cells = well->cells();
1265 const auto& rates = well->connectionRates();
1266 for (
unsigned perfIdx = 0; perfIdx < rates.size(); ++perfIdx) {
1267 unsigned cellIdx = cells[perfIdx];
1268 auto rate = rates[perfIdx];
1270 VectorBlockType res(0.0);
1271 using MatrixBlockType =
typename SparseMatrixAdapter::MatrixBlock;
1272 MatrixBlockType bMat(0.0);
1273 ebosSimulator_.model().linearizer().setResAndJacobi(res, bMat, rate);
1274 residual[cellIdx] += res;
1275 *diagMatAddress[cellIdx] += bMat;
1281 template<
typename TypeTag>
1283 BlackoilWellModel<TypeTag>::
1284 numLocalWellsEnd()
const
1286 auto w = schedule().getWellsatEnd();
1287 w.erase(std::remove_if(w.begin(), w.end(), not_on_process_), w.end());
1291 template<
typename TypeTag>
1292 std::vector<std::vector<int>>
1293 BlackoilWellModel<TypeTag>::
1294 getMaxWellConnections()
const
1296 std::vector<std::vector<int>> wells;
1298 auto schedule_wells = schedule().getWellsatEnd();
1299 schedule_wells.erase(std::remove_if(schedule_wells.begin(), schedule_wells.end(), not_on_process_), schedule_wells.end());
1300 wells.reserve(schedule_wells.size());
1303 for (
const auto& well : schedule_wells )
1305 std::vector<int> compressed_well_perforations = this->getCellsForConnections(well);
1308 std::sort(compressed_well_perforations.begin(),
1309 compressed_well_perforations.end());
1311 wells.push_back(compressed_well_perforations);
1316 template<
typename TypeTag>
1318 BlackoilWellModel<TypeTag>::
1319 addWellPressureEquationsStruct(PressureMatrix& jacobian)
const
1321 int nw = this->numLocalWellsEnd();
1322 int rdofs = local_num_cells_;
1323 for(
int i=0; i < nw; i++){
1324 int wdof = rdofs + i;
1325 jacobian.entry(wdof,wdof) = 1.0;
1327 std::vector<std::vector<int>> wellconnections = getMaxWellConnections();
1328 for(
int i=0; i < nw; i++){
1329 const auto& perfcells = wellconnections[i];
1330 for(
int perfcell : perfcells){
1331 int wdof = rdofs + i;
1332 jacobian.entry(wdof,perfcell) = 0.0;
1333 jacobian.entry(perfcell, wdof) = 0.0;
1338 template<
typename TypeTag>
1340 BlackoilWellModel<TypeTag>::
1341 numLocalNonshutWells()
const
1343 return well_container_.size();
1346 template<
typename TypeTag>
1348 BlackoilWellModel<TypeTag>::
1349 recoverWellSolutionAndUpdateWellState(
const BVector& x)
1352 DeferredLogger local_deferredLogger;
1353 OPM_BEGIN_PARALLEL_TRY_CATCH();
1355 for (
auto& well : well_container_) {
1356 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1357 well->recoverWellSolutionAndUpdateWellState(summary_state, x, this->wellState(), local_deferredLogger);
1361 OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
1362 "recoverWellSolutionAndUpdateWellState() failed: ",
1363 terminal_output_, ebosSimulator_.vanguard().grid().comm());
1370 template<
typename TypeTag>
1372 BlackoilWellModel<TypeTag>::
1373 initPrimaryVariablesEvaluation()
const
1375 for (
auto& well : well_container_) {
1376 well->initPrimaryVariablesEvaluation();
1385 template<
typename TypeTag>
1387 BlackoilWellModel<TypeTag>::
1388 getWellConvergence(
const std::vector<Scalar>& B_avg,
bool checkWellGroupControls)
const
1391 DeferredLogger local_deferredLogger;
1393 ConvergenceReport local_report;
1394 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1395 for (
const auto& well : well_container_) {
1396 if (well->isOperableAndSolvable() || well->wellIsStopped()) {
1397 local_report += well->getWellConvergence(this->wellState(), B_avg, local_deferredLogger, iterationIdx > param_.strict_outer_iter_wells_ );
1399 ConvergenceReport report;
1400 using CR = ConvergenceReport;
1401 report.setWellFailed({CR::WellFailure::Type::Unsolvable, CR::Severity::Normal, -1, well->name()});
1402 local_report += report;
1406 const Opm::Parallel::Communication comm = grid().comm();
1411 if (checkWellGroupControls) {
1412 report.setWellGroupTargetsViolated(this->lastReport().well_group_control_changed);
1415 if (terminal_output_) {
1416 global_deferredLogger.logMessages();
1419 if (terminal_output_) {
1420 for (
const auto& f : report.wellFailures()) {
1421 if (f.severity() == ConvergenceReport::Severity::NotANumber) {
1422 OpmLog::debug(
"NaN residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1423 }
else if (f.severity() == ConvergenceReport::Severity::TooLarge) {
1424 OpmLog::debug(
"Too large residual found with phase " + std::to_string(f.phase()) +
" for well " + f.wellName());
1435 template<
typename TypeTag>
1441 for (
auto& well : well_container_) {
1450 template<
typename TypeTag>
1451 std::tuple<bool, bool, double>
1458 if( !wellsActive() )
return {
false,
false, 0.0 };
1460 const int episodeIdx = ebosSimulator_.episodeIndex();
1461 const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
1462 const auto& comm = ebosSimulator_.vanguard().grid().comm();
1463 updateAndCommunicateGroupData(episodeIdx, iterationIdx);
1465 const auto [local_network_changed, local_network_imbalance]
1466 = shouldBalanceNetwork(episodeIdx, iterationIdx) ?
1467 updateNetworkPressures(episodeIdx) : std::make_pair(false, 0.0);
1468 const bool network_changed = comm.sum(local_network_changed);
1469 const double network_imbalance = comm.max(local_network_imbalance);
1471 bool changed_well_group =
false;
1473 const int nupcol = schedule()[episodeIdx].nupcol();
1476 if (iterationIdx <= nupcol) {
1477 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1478 changed_well_group = updateGroupControls(fieldGroup, deferred_logger, episodeIdx, iterationIdx);
1481 bool changed_well_to_group =
false;
1482 for (
const auto& well : well_container_) {
1483 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Group;
1484 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1486 changed_well_to_group = changed_well || changed_well_to_group;
1490 changed_well_to_group = comm.sum(changed_well_to_group);
1491 if (changed_well_to_group) {
1492 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1493 changed_well_group =
true;
1497 bool changed_well_individual =
false;
1498 for (
const auto& well : well_container_) {
1499 const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
1500 const bool changed_well = well->updateWellControl(ebosSimulator_, mode, this->wellState(), this->groupState(), deferred_logger);
1502 changed_well_individual = changed_well || changed_well_individual;
1505 changed_well_individual = comm.sum(changed_well_individual);
1506 if (changed_well_individual) {
1507 updateAndCommunicate(episodeIdx, iterationIdx, deferred_logger);
1508 changed_well_group =
true;
1512 const Group& fieldGroup = schedule().getGroup(
"FIELD", episodeIdx);
1513 updateWsolvent(fieldGroup, episodeIdx, this->nupcolWellState());
1515 return { changed_well_group, network_changed, network_imbalance };
1519 template<
typename TypeTag>
1521 BlackoilWellModel<TypeTag>::
1522 updateAndCommunicate(
const int reportStepIdx,
1523 const int iterationIdx,
1524 DeferredLogger& deferred_logger)
1526 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
1528 for (
const auto& well : well_container_) {
1529 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
1531 updateAndCommunicateGroupData(reportStepIdx, iterationIdx);
1534 template<
typename TypeTag>
1536 BlackoilWellModel<TypeTag>::
1537 updateGroupControls(
const Group& group,
1538 DeferredLogger& deferred_logger,
1539 const int reportStepIdx,
1540 const int iterationIdx)
1542 bool changed =
false;
1543 bool changed_hc = checkGroupHigherConstraints( group, deferred_logger, reportStepIdx);
1546 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
1548 bool changed_individual =
1549 BlackoilWellModelConstraints(*this).
1550 updateGroupIndividualControl(group,
1552 this->switched_inj_groups_,
1553 this->switched_prod_groups_,
1557 if (changed_individual) {
1559 updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
1562 for (
const std::string& groupName : group.groups()) {
1563 bool changed_this = updateGroupControls( schedule().getGroup(groupName, reportStepIdx), deferred_logger, reportStepIdx,iterationIdx);
1564 changed = changed || changed_this;
1569 template<
typename TypeTag>
1575 for (
const auto& well : well_container_) {
1576 const auto& wname = well->name();
1577 const auto wasClosed = wellTestState.well_is_closed(wname);
1578 well->checkWellOperability(ebosSimulator_, this->wellState(), local_deferredLogger);
1579 well->updateWellTestState(this->wellState().well(wname), simulationTime,
true, wellTestState, local_deferredLogger);
1581 if (!wasClosed && wellTestState.well_is_closed(wname)) {
1582 this->closed_this_step_.insert(wname);
1586 const Opm::Parallel::Communication comm = grid().comm();
1588 if (terminal_output_) {
1594 template<
typename TypeTag>
1598 std::string& exc_msg,
1599 ExceptionType::ExcEnum& exc_type,
1602 const int np = numPhases();
1603 std::vector<double> potentials;
1604 const auto& well= well_container_[widx];
1606 well->computeWellPotentials(ebosSimulator_, well_state_copy, potentials, deferred_logger);
1609 OPM_PARALLEL_CATCH_CLAUSE(exc_type, exc_msg);
1613 auto& ws = this->wellState().well(well->indexOfWell());
1614 for (
int p = 0; p < np; ++p) {
1616 ws.well_potentials[p] = std::max(0.0, potentials[p]);
1622 template <
typename TypeTag>
1624 BlackoilWellModel<TypeTag>::
1625 calculateProductivityIndexValues(DeferredLogger& deferred_logger)
1627 for (
const auto& wellPtr : this->well_container_) {
1628 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
1636 template <
typename TypeTag>
1638 BlackoilWellModel<TypeTag>::
1639 calculateProductivityIndexValuesShutWells(
const int reportStepIdx,
1640 DeferredLogger& deferred_logger)
1647 for (
const auto& shutWell : this->local_shut_wells_) {
1648 if (!this->wells_ecl_[shutWell].hasConnections()) {
1653 auto wellPtr = this->
template createTypedWellPointer
1654 <StandardWell<TypeTag>>(shutWell, reportStepIdx);
1656 wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_,
1657 this->local_num_cells_, this->B_avg_,
true);
1659 this->calculateProductivityIndexValues(wellPtr.get(), deferred_logger);
1667 template <
typename TypeTag>
1669 BlackoilWellModel<TypeTag>::
1670 calculateProductivityIndexValues(
const WellInterface<TypeTag>* wellPtr,
1671 DeferredLogger& deferred_logger)
1673 wellPtr->updateProductivityIndex(this->ebosSimulator_,
1674 this->prod_index_calc_[wellPtr->indexOfWell()],
1683 template<
typename TypeTag>
1685 BlackoilWellModel<TypeTag>::
1686 prepareTimeStep(DeferredLogger& deferred_logger)
1688 for (
const auto& well : well_container_) {
1689 auto& events = this->wellState().well(well->indexOfWell()).events;
1690 if (events.hasEvent(WellState::event_mask)) {
1691 well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
1692 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1693 well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger);
1694 well->initPrimaryVariablesEvaluation();
1697 events.clearEvent(WellState::event_mask);
1700 if (param_.solve_welleq_initially_ && well->isOperableAndSolvable()) {
1702 well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
1703 }
catch (
const std::exception& e) {
1704 const std::string msg =
"Compute initial well solution for " + well->name() +
" initially failed. Continue with the privious rates";
1705 deferred_logger.warning(
"WELL_INITIAL_SOLVE_FAILED", msg);
1709 updatePrimaryVariables(deferred_logger);
1712 template<
typename TypeTag>
1714 BlackoilWellModel<TypeTag>::
1715 updateAverageFormationFactor()
1717 std::vector< Scalar > B_avg(numComponents(), Scalar() );
1718 const auto& grid = ebosSimulator_.vanguard().grid();
1719 const auto& gridView = grid.leafGridView();
1720 ElementContext elemCtx(ebosSimulator_);
1722 OPM_BEGIN_PARALLEL_TRY_CATCH();
1723 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1724 elemCtx.updatePrimaryStencil(elem);
1725 elemCtx.updatePrimaryIntensiveQuantities(0);
1727 const auto& intQuants = elemCtx.intensiveQuantities(0, 0);
1728 const auto& fs = intQuants.fluidState();
1730 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
1732 if (!FluidSystem::phaseIsActive(phaseIdx)) {
1736 const unsigned compIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx));
1737 auto& B = B_avg[ compIdx ];
1739 B += 1 / fs.invB(phaseIdx).value();
1741 if constexpr (has_solvent_) {
1742 auto& B = B_avg[solventSaturationIdx];
1743 B += 1 / intQuants.solventInverseFormationVolumeFactor().value();
1746 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::updateAverageFormationFactor() failed: ", grid.comm())
1749 grid.comm().sum(B_avg.data(), B_avg.size());
1750 for (auto& bval : B_avg)
1752 bval /= global_num_cells_;
1761 template<
typename TypeTag>
1763 BlackoilWellModel<TypeTag>::
1764 updatePrimaryVariables(DeferredLogger& deferred_logger)
1766 for (
const auto& well : well_container_) {
1767 const auto& summary_state = ebosSimulator_.vanguard().summaryState();
1768 well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger);
1772 template<
typename TypeTag>
1774 BlackoilWellModel<TypeTag>::extractLegacyCellPvtRegionIndex_()
1776 const auto& grid = ebosSimulator_.vanguard().grid();
1777 const auto& eclProblem = ebosSimulator_.problem();
1778 const unsigned numCells = grid.size(0);
1780 pvt_region_idx_.resize(numCells);
1781 for (
unsigned cellIdx = 0; cellIdx < numCells; ++cellIdx) {
1782 pvt_region_idx_[cellIdx] =
1783 eclProblem.pvtRegionIndex(cellIdx);
1788 template<
typename TypeTag>
1790 BlackoilWellModel<TypeTag>::numComponents()
const
1798 if (numPhases() < 3) {
1801 int numComp = FluidSystem::numComponents;
1802 if constexpr (has_solvent_) {
1809 template<
typename TypeTag>
1811 BlackoilWellModel<TypeTag>::extractLegacyDepth_()
1813 const auto& eclProblem = ebosSimulator_.problem();
1814 depth_.resize(local_num_cells_);
1815 for (
unsigned cellIdx = 0; cellIdx < local_num_cells_; ++cellIdx) {
1816 depth_[cellIdx] = eclProblem.dofCenterDepth(cellIdx);
1820 template<
typename TypeTag>
1822 BlackoilWellModel<TypeTag>::
1823 updatePerforationIntensiveQuantities()
1825 ElementContext elemCtx(ebosSimulator_);
1826 const auto& gridView = ebosSimulator_.gridView();
1828 OPM_BEGIN_PARALLEL_TRY_CATCH();
1829 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1830 elemCtx.updatePrimaryStencil(elem);
1831 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1833 if (!is_cell_perforated_[elemIdx]) {
1836 elemCtx.updatePrimaryIntensiveQuantities(0);
1838 OPM_END_PARALLEL_TRY_CATCH(
"BlackoilWellModel::updatePerforationIntensiveQuantities() failed: ", ebosSimulator_.vanguard().grid().comm());
1842 template<
typename TypeTag>
1843 typename BlackoilWellModel<TypeTag>::WellInterfacePtr
1844 BlackoilWellModel<TypeTag>::
1845 getWell(
const std::string& well_name)
const
1848 auto well = std::find_if(well_container_.begin(),
1849 well_container_.end(),
1850 [&well_name](
const WellInterfacePtr& elem)->bool {
1851 return elem->name() == well_name;
1854 assert(well != well_container_.end());
1859 template<
typename TypeTag>
1861 BlackoilWellModel<TypeTag>::
1862 hasWell(
const std::string& well_name)
const
1864 return std::any_of(well_container_.begin(), well_container_.end(),
1865 [&well_name](
const WellInterfacePtr& elem) ->
bool
1867 return elem->name() == well_name;
1874 template <
typename TypeTag>
1876 BlackoilWellModel<TypeTag>::
1877 reportStepIndex()
const
1879 return std::max(this->ebosSimulator_.episodeIndex(), 0);
1886 template<
typename TypeTag>
1888 BlackoilWellModel<TypeTag>::
1889 calcRates(
const int fipnum,
1891 const std::vector<double>& production_rates,
1892 std::vector<double>& resv_coeff)
1894 rateConverter_->calcCoeff(fipnum, pvtreg, production_rates, resv_coeff);
1897 template<
typename TypeTag>
1899 BlackoilWellModel<TypeTag>::
1900 calcInjRates(
const int fipnum,
1902 std::vector<double>& resv_coeff)
1904 rateConverter_->calcInjCoeff(fipnum, pvtreg, resv_coeff);
1908 template <
typename TypeTag>
1910 BlackoilWellModel<TypeTag>::
1911 computeWellTemperature()
1916 int np = numPhases();
1917 double cellInternalEnergy;
1920 double perfPhaseRate;
1921 const int nw = numLocalWells();
1922 for (
auto wellID = 0*nw; wellID < nw; ++wellID) {
1923 const Well& well = wells_ecl_[wellID];
1924 if (well.isInjector())
1928 for (
int i = 0; i < wellID; ++i) {
1929 connpos += well_perf_data_[i].size();
1932 std::array<double,2> weighted{0.0,0.0};
1933 auto& [weighted_temperature, total_weight] = weighted;
1935 auto& well_info = local_parallel_well_info_[wellID].get();
1936 const int num_perf_this_well = well_info.communication().sum(well_perf_data_[wellID].size());
1937 auto& ws = this->wellState().well(wellID);
1938 auto& perf_data = ws.perf_data;
1939 auto& perf_phase_rate = perf_data.phase_rates;
1941 for (
int perf = 0; perf < num_perf_this_well; ++perf) {
1942 const int cell_idx = well_perf_data_[wellID][perf].cell_index;
1943 const auto& intQuants = ebosSimulator_.model().intensiveQuantities(cell_idx, 0);
1944 const auto& fs = intQuants.fluidState();
1947 double cellTemperatures = fs.temperature(0).value();
1949 double weight_factor = 0.0;
1950 for (
unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx)
1952 if (!FluidSystem::phaseIsActive(phaseIdx)) {
1955 cellInternalEnergy = fs.enthalpy(phaseIdx).value() - fs.pressure(phaseIdx).value() / fs.density(phaseIdx).value();
1956 cellBinv = fs.invB(phaseIdx).value();
1957 cellDensity = fs.density(phaseIdx).value();
1958 perfPhaseRate = perf_phase_rate[ perf*np + phaseIdx ];
1959 weight_factor += cellDensity * perfPhaseRate/cellBinv * cellInternalEnergy/cellTemperatures;
1961 total_weight += weight_factor;
1962 weighted_temperature += weight_factor * cellTemperatures;
1964 well_info.communication().sum(weighted.data(), 2);
1965 this->wellState().well(wellID).temperature = weighted_temperature/total_weight;
1971 template <
typename TypeTag>
1973 BlackoilWellModel<TypeTag>::
1974 assignWellTracerRates(data::Wells& wsrpt)
const
1976 const auto & wellTracerRates = ebosSimulator_.problem().tracerModel().getWellTracerRates();
1978 if (wellTracerRates.empty())
1981 for (
const auto& wTR : wellTracerRates) {
1982 std::string wellName = wTR.first.first;
1983 auto xwPos = wsrpt.find(wellName);
1984 if (xwPos == wsrpt.end()) {
1987 std::string tracerName = wTR.first.second;
1988 double rate = wTR.second;
1989 xwPos->second.rates.set(data::Rates::opt::tracer, rate, tracerName);
Class for handling the blackoil well model.
Definition: BlackoilWellModel.hpp:92
void calculateExplicitQuantities(DeferredLogger &deferred_logger) const
Calculating the explict quantities used in the well calculation.
Definition: BlackoilWellModel_impl.hpp:1438
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