FlowProblemBlackoil.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 Copyright 2023 INRIA
5 Copyright 2024 SINTEF Digital
6
7 This file is part of the Open Porous Media project (OPM).
8
9 OPM is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 2 of the License, or
12 (at your option) any later version.
13
14 OPM is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with OPM. If not, see <http://www.gnu.org/licenses/>.
21
22 Consult the COPYING file in the top-level source directory of this
23 module for the precise wording of the license and the list of
24 copyright holders.
25*/
31#ifndef OPM_FLOW_PROBLEM_BLACK_HPP
32#define OPM_FLOW_PROBLEM_BLACK_HPP
33
34#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
35#include <opm/material/fluidsystems/blackoilpvt/DryGasPvt.hpp>
36#include <opm/material/fluidsystems/blackoilpvt/WetGasPvt.hpp>
37#include <opm/material/fluidsystems/blackoilpvt/LiveOilPvt.hpp>
38#include <opm/material/fluidsystems/blackoilpvt/DeadOilPvt.hpp>
39#include <opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityOilPvt.hpp>
40#include <opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityWaterPvt.hpp>
41#include <opm/material/fluidsystems/blackoilpvt/ConstantRsDeadOilPvt.hpp>
42
46
47#include <opm/output/eclipse/EclipseIO.hpp>
48
49#include <opm/input/eclipse/Units/Units.hpp>
50
60
62
63#if HAVE_DAMARIS
65#endif
66
67#include <algorithm>
68#include <cstddef>
69#include <functional>
70#include <limits>
71#include <memory>
72#include <stdexcept>
73#include <string>
74#include <string_view>
75#include <vector>
76
77namespace Opm {
78
85template <class TypeTag>
86class FlowProblemBlackoil : public FlowProblem<TypeTag>
87{
88 // TODO: the naming of the Types might be able to be adjusted
89public:
91
92private:
93 using typename FlowProblemType::Scalar;
94 using typename FlowProblemType::Simulator;
95 using typename FlowProblemType::GridView;
96 using typename FlowProblemType::FluidSystem;
97 using typename FlowProblemType::Vanguard;
99 using typename FlowProblemType::EqVector;
105
106 // TODO: potentially some cleaning up depending on the usage later here
122
126
130
132 using typename FlowProblemType::RateVector;
134 using typename FlowProblemType::Indices;
136 using typename FlowProblemType::ElementContext;
137
138 using typename FlowProblemType::MaterialLaw;
139 using typename FlowProblemType::DimMatrix;
140
141 static constexpr bool enableDissolvedGas =
142 Indices::compositionSwitchIdx != std::numeric_limits<unsigned>::max();
143 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
144 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
145 enum { enableGeochemistry = getPropValue<TypeTag, Properties::EnableGeochemistry>() };
146 enum { enableMech = getPropValue<TypeTag, Properties::EnableMech>() };
147
148 using BioeffectsModule = BlackOilBioeffectsModule<TypeTag, enableBioeffects>;
149 using BrineModule = BlackOilBrineModule<TypeTag, enableBrine>;
150 using ConvectiveMixingModule = BlackOilConvectiveMixingModule<TypeTag, enableConvectiveMixing>;
153 using ExtboModule = BlackOilExtboModule<TypeTag, enableExtbo>;
154 using FoamModule = BlackOilFoamModule<TypeTag, enableFoam>;
155 using PolymerModule = BlackOilPolymerModule<TypeTag, enablePolymer>;
156 using SolventModule = BlackOilSolventModule<TypeTag, enableSolvent>;
157
158 using EclWriterType = EclWriter<TypeTag, OutputBlackOilModule<TypeTag> >;
159 using IndexTraits = typename FluidSystem::IndexTraitsType;
160 using InitialFluidState = typename EquilInitializer<TypeTag>::ScalarFluidState;
161 using HybridNewton = BlackOilHybridNewton<TypeTag>;
162 using ModuleParams = BlackoilModuleParams<ConvectiveMixingModuleParam<Scalar>>;
163
164#if HAVE_DAMARIS
165 using DamarisWriterType = DamarisWriter<TypeTag>;
166#endif
167
168public:
171
175 static void registerParameters()
176 {
178
180#if HAVE_DAMARIS
181 DamarisWriterType::registerParameters();
182#endif
184 }
185
189 explicit FlowProblemBlackoil(Simulator& simulator)
190 : FlowProblemType(simulator)
191 , thresholdPressures_(simulator)
192 , mixControls_(simulator.vanguard().schedule())
193 , actionHandler_(simulator.vanguard().eclState(),
194 simulator.vanguard().schedule(),
195 simulator.vanguard().actionState(),
196 simulator.vanguard().summaryState(),
197 this->wellModel_,
198 simulator.vanguard().grid().comm())
199 , hybridNewton_(simulator)
200 {
201 this->model().addOutputModule(std::make_unique<VtkTracerModule<TypeTag>>(simulator));
202
203 // Tell the black-oil extensions to initialize their internal data structures
204 const auto& vanguard = simulator.vanguard();
205
206 if constexpr (enableBrine) {
207 BlackOilBrineParams<Scalar> brineParams;
208 brineParams.template initFromState<enableBrine,
209 enableSaltPrecipitation>(vanguard.eclState());
210 BrineModule::setParams(std::move(brineParams));
211 }
212
213 if constexpr (enableDiffusion) {
214 DiffusionModule::initFromState(vanguard.eclState());
215 }
216
217 if constexpr (enableDispersion) {
218 DispersionModule::initFromState(vanguard.eclState());
219 }
220
221 if constexpr (enableExtbo) {
222 BlackOilExtboParams<Scalar> extboParams;
223 extboParams.template initFromState<enableExtbo>(vanguard.eclState());
224 ExtboModule::setParams(std::move(extboParams));
225 }
226
227 if constexpr (enableFoam) {
229 foamParams.template initFromState<enableFoam>(vanguard.eclState());
230 FoamModule::setParams(std::move(foamParams));
231 }
232
233 if constexpr (enableBioeffects) {
234 BlackOilBioeffectsParams<Scalar> bioeffectsParams;
235 bioeffectsParams.template initFromState<enableBioeffects, enableMICP>(vanguard.eclState());
236 BioeffectsModule::setParams(std::move(bioeffectsParams));
237 }
238
239 if constexpr (enablePolymer) {
240 BlackOilPolymerParams<Scalar> polymerParams;
241 polymerParams.template initFromState<enablePolymer, enablePolymerMolarWeight>(vanguard.eclState());
242 PolymerModule::setParams(std::move(polymerParams));
243 }
244
245 if constexpr (enableSolvent) {
246 BlackOilSolventParams<Scalar> solventParams;
247 solventParams.template initFromState<enableSolvent>(vanguard.eclState(), vanguard.schedule());
248 SolventModule::setParams(std::move(solventParams));
249 }
250
251 // create the ECL writer
252 eclWriter_ = std::make_unique<EclWriterType>(simulator);
253 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
254
255 // Safeguard against geochemistry since it exsist in a separate module with a separate problem class
256 if constexpr (!enableGeochemistry) {
257 if (vanguard.eclState().runspec().geochem().enabled()) {
258 throw std::runtime_error("GEOCHEM keyword in the deck but geochemistry module "
259 "was disabled at compile time!");
260 }
261 }
262
263 // Safeguard against TPSA-geomechanics since it requires FlowProblemTPSA
264 if constexpr (!enableMech) {
265 const auto& rspec = vanguard.eclState().runspec();
266 if (rspec.mech() && rspec.mechSolver().tpsa()) {
267 throw std::runtime_error("TPSA solver enabled in the deck, but geomechanics "
268 "module was disabled at compile time!");
269 }
270 }
271
272#if HAVE_DAMARIS
273 // create Damaris writer
274 damarisWriter_ = std::make_unique<DamarisWriterType>(simulator);
275 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
276#endif
277 }
278
282 void beginEpisode() override
283 {
285
286 auto& simulator = this->simulator();
287
288 const int episodeIdx = simulator.episodeIndex();
289 const auto& schedule = simulator.vanguard().schedule();
290
291 // Evaluate UDQ assign statements to make sure the settings are
292 // available as UDA controls for the current report step.
293 this->actionHandler_
294 .evalUDQAssignments(episodeIdx, simulator.vanguard().udqState());
295
296 if (episodeIdx >= 0) {
297 const auto& oilVap = schedule[episodeIdx].oilvap();
298 if (oilVap.getType() == OilVaporizationProperties::OilVaporization::VAPPARS) {
299 FluidSystem::setVapPars(oilVap.vap1(), oilVap.vap2());
300 }
301 else {
302 FluidSystem::setVapPars(0.0, 0.0);
303 }
304
305 if constexpr (enableConvectiveMixing) {
306 ConvectiveMixingModule::beginEpisode(simulator.vanguard().eclState(), schedule, episodeIdx,
307 this->moduleParams_.convectiveMixingModuleParam);
308 }
309 }
310 }
311
315 void beginTimeStep() override
316 {
319 }
320
325 {
326 // TODO: there should be room to remove duplication for this
327 // function, but there is relatively complicated logic in the
328 // function calls here. Some refactoring is needed.
329 FlowProblemType::finishInit();
330
331 auto& simulator = this->simulator();
332
333 auto finishTransmissibilities = [updated = false, this]() mutable
334 {
335 if (updated) { return; }
336
337 this->transmissibilities_.finishInit([&vg = this->simulator().vanguard()](const unsigned int it) {
338 return vg.gridIdxToEquilGridIdx(it);
339 });
340
341 updated = true;
342 };
343
344 // calculating the TRANX, TRANY, TRANZ and NNC for output purpose
345 // for parallel running, it is based on global trans_
346 // for serial running, it is based on the transmissibilities_
347 // we try to avoid for the parallel running, has both global trans_ and transmissibilities_ allocated at the same time
348 if (enableEclOutput_) {
349 if (simulator.vanguard().grid().comm().size() > 1) {
350 if (simulator.vanguard().grid().comm().rank() == 0)
351 eclWriter_->setTransmissibilities(&simulator.vanguard().globalTransmissibility());
352 } else {
353 finishTransmissibilities();
354 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
355 }
356
357 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
358 return simulator.vanguard().gridEquilIdxToGridIdx(i);
359 };
360
361 this->eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
362 }
363 simulator.vanguard().releaseGlobalTransmissibilities();
364
365 const auto& eclState = simulator.vanguard().eclState();
366 const auto& schedule = simulator.vanguard().schedule();
367
368 // Set the start time of the simulation
369 simulator.setStartTime(schedule.getStartTime());
370 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
371
372 // We want the episode index to be the same as the report step index to make
373 // things simpler, so we have to set the episode index to -1 because it is
374 // incremented by endEpisode(). The size of the initial time step and
375 // length of the initial episode is set to zero for the same reason.
376 simulator.setEpisodeIndex(-1);
377 simulator.setEpisodeLength(0.0);
378
379 this->initGravity_(eclState);
380
381 if (this->enableTuning_) {
382 // if support for the TUNING keyword is enabled, we get the initial time
383 // steping parameters from it instead of from command line parameters
384 const auto& tuning = schedule[0].tuning();
385 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
386 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
387 }
388
389 // conserve inner energy instead of enthalpy if TEMP is used
390 // or THERMAL and parameter ConserveInnerEnergyThermal is true (default false)
391 bool isThermal = eclState.getSimulationConfig().isThermal();
392 bool isTemp = eclState.getSimulationConfig().isTemp();
393 bool conserveInnerEnergy = isTemp || (isThermal && Parameters::Get<Parameters::ConserveInnerEnergyThermal>());
394 FluidSystem::setEnergyEqualEnthalpy(conserveInnerEnergy);
395
396 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
397 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
398 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
399 }
400
401 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
402 [&simulator](const unsigned idx)
403 {
404 std::array<int,dim> coords;
405 simulator.vanguard().cartesianCoordinate(idx, coords);
406 std::ranges::transform(coords, coords.begin(),
407 [](const auto c) { return c + 1; });
408 return coords;
409 });
410
413
414 // write the static output files (EGRID, INIT)
415 if (enableEclOutput_) {
416 this->eclWriter_->writeInit();
417 }
418
419 finishTransmissibilities();
420
421 const auto& initconfig = eclState.getInitConfig();
422 this->tracerModel_.init(initconfig.restartRequested());
423 if (initconfig.restartRequested()) {
425 }
426 else {
427 this->readInitialCondition_();
428 }
429 this->temperatureModel_.init();
430 this->tracerModel_.prepareTracerBatches();
431
432 this->updatePffDofData_();
433
434 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
435 const auto& vanguard = this->simulator().vanguard();
436 const auto& gridView = vanguard.gridView();
437 const int numElements = gridView.size(/*codim=*/0);
438 this->polymer_.maxAdsorption.resize(numElements, 0.0);
439 }
440
442
443 // compute and set eq weights based on initial b values
445
447 this->drift_.resize(this->model().numGridDof());
448 this->drift_ = 0.0;
449 }
450
451 // after finishing the initialization and writing the initial solution, we move
452 // to the first "real" episode/report step
453 // for restart the episode index and start is already set
454 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
455 simulator.startNextEpisode(schedule.seconds(1));
456 simulator.setEpisodeIndex(0);
457 simulator.setTimeStepIndex(0);
458 }
459
460 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
462 {
463 // User requested that saturation functions be checked for
464 // consistency and essential/critical requirements are not met.
465 // Abort simulation run.
466 //
467 // Note: We need synchronisation here lest ranks other than the
468 // I/O rank throw exceptions too early thereby risking an
469 // incomplete failure report being shown to the user.
470 this->simulator().vanguard().grid().comm().barrier();
471
472 throw std::domain_error {
473 "Saturation function end-points do not "
474 "meet requisite consistency conditions"
475 };
476 }
477
478 // TODO: move to the end for later refactoring of the function finishInit()
479 //
480 // deal with DRSDT
481 this->mixControls_.init(this->model().numGridDof(),
482 this->episodeIndex(),
483 eclState.runspec().tabdims().getNumPVTTables());
484
485 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
486 simulator.setTimeStepSize(0.0);
487 simulator.model().applyInitialSolution();
489 }
490
491 if (!eclState.getIOConfig().initOnly()) {
492 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
493 OpmLog::info("\nThe deck has TUNING in the SCHEDULE section, but "
494 "it is ignored due\nto the flag --enable-tuning=false. "
495 "Set this flag to true to activate it.\n"
496 "Manually tuning the simulator with the TUNING keyword may "
497 "increase run time.\nIt is recommended using the simulator's "
498 "default tuning (--enable-tuning=false).");
499 }
500 }
501 }
502
506 void endTimeStep() override
507 {
508 FlowProblemType::endTimeStep();
509 this->endStepApplyAction();
510 }
511
513 {
514 // After the solution is updated, the values in output module needs
515 // also updated.
516 this->eclWriter().mutableOutputModule().invalidateLocalData();
517
518 // For CpGrid with LGRs, ecl/vtk output is not supported yet.
519 const auto& grid = this->simulator().vanguard().gridView().grid();
520
521 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
522 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
523 if (!isCpGrid || (grid.maxLevel() == 0)) {
524 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
525 }
526
527 {
528 OPM_TIMEBLOCK(applyActions);
529
530 const int episodeIdx = this->episodeIndex();
531 auto& simulator = this->simulator();
532
533 // Clear out any existing events as these have already been
534 // processed when we're running an action block
535 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
536
537 // Re-ordering in case of Alugrid
538 this->actionHandler_
539 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
540 [this](const bool global)
541 {
542 using TransUpdateQuantities = typename
543 Vanguard::TransmissibilityType::TransUpdateQuantities;
544
545 this->transmissibilities_
546 .update(global, TransUpdateQuantities::All,
547 [&vg = this->simulator().vanguard()]
548 (const unsigned int i)
549 {
550 return vg.gridIdxToEquilGridIdx(i);
551 });
552 });
553 }
554 }
555
559 void endEpisode() override
560 {
561 OPM_TIMEBLOCK(endEpisode);
562
563 // Rerun UDQ assignents following action processing on the final
564 // time step of this episode to make sure that any UDQ ASSIGN
565 // operations triggered in action blocks take effect. This is
566 // mainly to work around a shortcoming of the ScheduleState copy
567 // constructor which clears pending UDQ assignments under the
568 // assumption that all such assignments have been processed. If an
569 // action block happens to trigger on the final time step of an
570 // episode and that action block runs a UDQ assignment, then that
571 // assignment would be dropped and the rest of the simulator will
572 // never see its effect without this hack.
573 this->actionHandler_
574 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
575
576 FlowProblemType::endEpisode();
577 }
578
579 void writeReports(const SimulatorTimer& timer)
580 {
581 if (this->enableEclOutput_) {
582 this->eclWriter_->writeReports(timer);
583 }
584 }
585
586
591 void writeOutput(const bool verbose) override
592 {
593 FlowProblemType::writeOutput(verbose);
594
595 const auto isSubStep = !this->episodeWillBeOver();
596
597 auto localCellData = data::Solution {};
598
599#if HAVE_DAMARIS
600 // N.B. the Damaris output has to be done before the ECL output as the ECL one
601 // does all kinds of std::move() relocation of data
602 if (this->enableDamarisOutput_ && (this->damarisWriter_ != nullptr)) {
603 this->damarisWriter_->writeOutput(localCellData, isSubStep);
604 }
605#endif
606
607 if (this->enableEclOutput_ && (this->eclWriter_ != nullptr)) {
608 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep,
609 this->simulator().vanguard().schedule()
610 .exitStatus().has_value());
611 }
612 }
613
615 {
616 OPM_TIMEBLOCK(finalizeOutput);
617 // this will write all pending output to disk
618 // to avoid corruption of output files
619 eclWriter_.reset();
620 }
621
622
627 {
628 FlowProblemType::initialSolutionApplied();
629
630 // let the object for threshold pressures initialize itself. this is done only at
631 // this point, because determining the threshold pressures may require to access
632 // the initial solution.
633 this->thresholdPressures_.finishInit();
634
635 // For CpGrid with LGRs, ecl-output is not supported yet.
636 const auto& grid = this->simulator().vanguard().gridView().grid();
637
638 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
639 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
640 // Skip - for now - calculate the initial fip values for CpGrid with LGRs.
641 if (!isCpGrid || (grid.maxLevel() == 0)) {
642 if (this->simulator().episodeIndex() == 0) {
643 eclWriter_->writeInitialFIPReport();
644 }
645 }
646 }
647
649 unsigned globalDofIdx,
650 unsigned timeIdx) const override
651 {
652 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
653
654 // Add source term from deck
655 const auto& source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
656 std::array<int,3> ijk;
657 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
658
659 if (source.hasSource(ijk)) {
660 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
661 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
662 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
663 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
664
665 for (unsigned i = 0; i < phidx_map.size(); ++i) {
666 const auto phaseIdx = phidx_map[i];
667 const auto sourceComp = sc_map[i];
668 const auto compIdx = cidx_map[i];
669 if (!FluidSystem::phaseIsActive(phaseIdx)) {
670 continue;
671 }
672 Scalar mass_rate = source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
673 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
674 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
675 }
676 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
677 }
678
679 if constexpr (enableSolvent) {
680 Scalar mass_rate = source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
681 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
682 const auto& solventPvt = SolventModule::solventPvt();
683 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
684 }
685 rate[Indices::contiSolventEqIdx] += mass_rate;
686 }
687 if constexpr (enablePolymer) {
688 rate[Indices::polymerConcentrationIdx] += source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
689 }
690 if constexpr (enableMICP) {
691 rate[Indices::microbialConcentrationIdx] += source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
692 rate[Indices::oxygenConcentrationIdx] += source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
693 rate[Indices::ureaConcentrationIdx] += source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
694 }
695 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
696 for (unsigned i = 0; i < phidx_map.size(); ++i) {
697 const auto phaseIdx = phidx_map[i];
698 if (!FluidSystem::phaseIsActive(phaseIdx)) {
699 continue;
700 }
701 const auto sourceComp = sc_map[i];
702 const auto source_hrate = source.hrate(ijk, sourceComp);
703 if (source_hrate) {
704 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
705 } else {
706 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, /*timeIdx*/ 0);
707 auto fs = intQuants.fluidState();
708 // if temperature is not set, use cell temperature as default
709 const auto source_temp = source.temperature(ijk, sourceComp);
710 if (source_temp) {
711 Scalar temperature = source_temp.value();
712 fs.setTemperature(temperature);
713 }
714 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
715 Scalar mass_rate = source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
716 Scalar energy_rate = getValue(h)*mass_rate;
717 rate[Indices::contiEnergyEqIdx] += energy_rate;
718 }
719 }
720 }
721 }
722
723 // if requested, compensate systematic mass loss for cells which were "well
724 // behaved" in the last time step
725 if (this->enableDriftCompensation_) {
726 const auto& simulator = this->simulator();
727 const auto& model = this->model();
728
729 // we use a lower tolerance for the compensation too
730 // assure the added drift from the last step does not
731 // cause convergence issues on the current step
732 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
733 Scalar poro = this->porosity(globalDofIdx, timeIdx);
734 Scalar dt = simulator.timeStepSize();
735 EqVector dofDriftRate = this->drift_[globalDofIdx];
736 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
737
738 // restrict drift compensation to the CNV tolerance
739 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
740 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
741 if (cnv > maxCompensation) {
742 dofDriftRate[eqIdx] *= maxCompensation/cnv;
743 }
744 }
745
746 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
747 rate[eqIdx] -= dofDriftRate[eqIdx];
748 }
749 }
750
754 template <class LhsEval, class Callback>
755 LhsEval permFactTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
756 {
757 OPM_TIMEBLOCK_LOCAL(permFactTransMultiplier, Subsystem::PvtProps);
758 if constexpr (enableSaltPrecipitation) {
759 const auto& fs = intQuants.fluidState();
760 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
761 LhsEval porosityFactor = obtain(1. - fs.saltSaturation());
762 porosityFactor = min(porosityFactor, 1.0);
763 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
764 return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
765 }
766 else if constexpr (enableBioeffects) {
767 return obtain(intQuants.permFactor());
768 }
769 else {
770 return 1.0;
771 }
772 }
773
774 // temporary solution to facilitate output of initial state from flow
775 const InitialFluidState& initialFluidState(unsigned globalDofIdx) const
776 { return initialFluidStates_[globalDofIdx]; }
777
778 std::vector<InitialFluidState>& initialFluidStates()
779 { return initialFluidStates_; }
780
781 const std::vector<InitialFluidState>& initialFluidStates() const
782 { return initialFluidStates_; }
783
784 const EclipseIO& eclIO() const
785 { return eclWriter_->eclIO(); }
786
788 { return eclWriter_->setSubStepReport(report); }
789
791 { return eclWriter_->setSimulationReport(report); }
792
793 InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
794 {
795 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
796 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
797 if (bcprop.size() > 0) {
798 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
799
800 // index == 0: no boundary conditions for this
801 // global cell and direction
802 if (this->bcindex_(dir)[globalDofIdx] == 0)
803 return initialFluidStates_[globalDofIdx];
804
805 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
806 if (bc.bctype == BCType::DIRICHLET )
807 {
808 InitialFluidState fluidState;
809 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
810 fluidState.setPvtRegionIndex(pvtRegionIdx);
811
812 switch (bc.component) {
813 case BCComponent::OIL:
814 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
815 throw std::logic_error("oil is not active and you're trying to add oil BC");
816
817 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
818 break;
819 case BCComponent::GAS:
820 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
821 throw std::logic_error("gas is not active and you're trying to add gas BC");
822
823 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
824 break;
825 case BCComponent::WATER:
826 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
827 throw std::logic_error("water is not active and you're trying to add water BC");
828
829 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
830 break;
831 case BCComponent::SOLVENT:
832 case BCComponent::POLYMER:
833 case BCComponent::MICR:
834 case BCComponent::OXYG:
835 case BCComponent::UREA:
837 throw std::logic_error("you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
838 }
839 fluidState.setTotalSaturation(1.0);
840 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
841 const auto pressure_input = bc.pressure;
842 if (pressure_input) {
843 pressure = *pressure_input;
844 }
845
846 std::array<Scalar, numPhases> pc = {0};
847 const auto& matParams = this->materialLawParams(globalDofIdx);
848 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
849 Valgrind::CheckDefined(pressure);
850 Valgrind::CheckDefined(pc);
851 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
852 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
853 if (Indices::oilEnabled)
854 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
855 else if (Indices::gasEnabled)
856 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
857 else if (Indices::waterEnabled)
858 //single (water) phase
859 fluidState.setPressure(phaseIdx, pressure);
860 }
861 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
862 double temperature = initialFluidStates_[globalDofIdx].temperature(0); // we only have one temperature
863 const auto temperature_input = bc.temperature;
864 if(temperature_input)
865 temperature = *temperature_input;
866 fluidState.setTemperature(temperature);
867 }
868
869 if constexpr (enableDissolvedGas) {
870 if (FluidSystem::enableDissolvedGas()) {
871 fluidState.setRs(0.0);
872 fluidState.setRv(0.0);
873 }
874 }
875 if constexpr (enableDisgasInWater) {
876 if (FluidSystem::enableDissolvedGasInWater()) {
877 fluidState.setRsw(0.0);
878 }
879 }
880 if constexpr (enableVapwat) {
881 if (FluidSystem::enableVaporizedWater()) {
882 fluidState.setRvw(0.0);
883 }
884 }
885
886 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
887 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
888
889 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
890 fluidState.setInvB(phaseIdx, b);
891
892 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
893 fluidState.setDensity(phaseIdx, rho);
894 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
895 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
896 fluidState.setEnthalpy(phaseIdx, h);
897 }
898 }
899 fluidState.checkDefined();
900 return fluidState;
901 }
902 }
903 return initialFluidStates_[globalDofIdx];
904 }
905
906
908 { return *eclWriter_; }
909
911 { return *eclWriter_; }
912
917 Scalar maxGasDissolutionFactor(unsigned timeIdx, unsigned globalDofIdx) const
918 {
919 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
920 this->episodeIndex(),
921 this->pvtRegionIndex(globalDofIdx));
922 }
923
928 Scalar maxOilVaporizationFactor(unsigned timeIdx, unsigned globalDofIdx) const
929 {
930 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
931 this->episodeIndex(),
932 this->pvtRegionIndex(globalDofIdx));
933 }
934
947 {
948 const auto& rspec = this->simulator().vanguard().eclState().runspec();
949 const bool tpsaActive = rspec.mech() && rspec.mechSolver().tpsa();
950 if (tpsaActive) {
951 return false;
952 }
953
954 int episodeIdx = this->episodeIndex();
955 return !this->mixControls_.drsdtActive(episodeIdx) &&
956 !this->mixControls_.drvdtActive(episodeIdx) &&
957 this->rockCompPoroMultWc_.empty() &&
958 this->rockCompPoroMult_.empty();
959 }
960
967 template <class Context>
968 void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
969 {
970 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
971
972 values.setPvtRegionIndex(pvtRegionIndex(context, spaceIdx, timeIdx));
973 values.assignNaive(initialFluidStates_[globalDofIdx]);
974
975 if constexpr (enableSolvent) {
976 SolventModule::assignPrimaryVars(values,
977 this->solventSaturation_[globalDofIdx],
978 this->solventRsw_[globalDofIdx]);
979 }
980
981 if constexpr (enablePolymer) {
982 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
983 }
984
985 if constexpr (enablePolymerMolarWeight) {
986 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
987 }
988
989 if constexpr (enableBrine) {
990 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
991 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
992 }
993 else {
994 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
995 }
996 }
997
998 if constexpr (enableBioeffects) {
999 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
1000 values[Indices::biofilmVolumeFractionIdx] = this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
1001 if constexpr (enableMICP) {
1002 values[Indices::oxygenConcentrationIdx] = this->bioeffects_.oxygenConcentration[globalDofIdx];
1003 values[Indices::ureaConcentrationIdx] = this->bioeffects_.ureaConcentration[globalDofIdx];
1004 values[Indices::calciteVolumeFractionIdx] = this->bioeffects_.calciteVolumeFraction[globalDofIdx];
1005 }
1006 }
1007
1008 values.checkDefined();
1009 }
1010
1011
1012 Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
1013 {
1014 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
1015 this->pvtRegionIndex(elemIdx));
1016 }
1017
1018 bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
1019 {
1020 return this->mixControls_.drsdtConvective(episodeIdx, this->pvtRegionIndex(elemIdx));
1021 }
1022
1028 template <class Context>
1029 void boundary(BoundaryRateVector& values,
1030 const Context& context,
1031 unsigned spaceIdx,
1032 unsigned timeIdx) const
1033 {
1034 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
1035 if (!context.intersection(spaceIdx).boundary())
1036 return;
1037
1038 if constexpr (energyModuleType != EnergyModules::FullyImplicitThermal || !enableThermalFluxBoundaries)
1039 values.setNoFlow();
1040 else {
1041 // in the energy case we need to specify a non-trivial boundary condition
1042 // because the geothermal gradient needs to be maintained. for this, we
1043 // simply assume the initial temperature at the boundary and specify the
1044 // thermal flow accordingly. in this context, "thermal flow" means energy
1045 // flow due to a temerature gradient while assuming no-flow for mass
1046 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1047 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1048 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
1049 }
1050
1051 if (this->nonTrivialBoundaryConditions()) {
1052 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1053 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1054 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1055 unsigned pvtRegionIdx = pvtRegionIndex(context, spaceIdx, timeIdx);
1056 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1057 if (type == BCType::THERMAL)
1058 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1059 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1060 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1061 else if (type == BCType::RATE)
1062 values.setMassRate(massrate, pvtRegionIdx);
1063 }
1064 }
1065
1070 void readSolutionFromOutputModule(const int restart_step, bool fip_init)
1071 {
1072 auto& simulator = this->simulator();
1073 const auto& eclState = simulator.vanguard().eclState();
1074
1075 std::size_t numElems = this->model().numGridDof();
1076 this->initialFluidStates_.resize(numElems);
1077 if constexpr (enableSolvent) {
1078 this->solventSaturation_.resize(numElems, 0.0);
1079 this->solventRsw_.resize(numElems, 0.0);
1080 }
1081
1082 if constexpr (enablePolymer)
1083 this->polymer_.concentration.resize(numElems, 0.0);
1084
1085 if constexpr (enablePolymerMolarWeight) {
1086 const std::string msg {"Support of the RESTART for polymer molecular weight "
1087 "is not implemented yet. The polymer weight value will be "
1088 "zero when RESTART begins"};
1089 OpmLog::warning("NO_POLYMW_RESTART", msg);
1090 this->polymer_.moleWeight.resize(numElems, 0.0);
1091 }
1092
1093 if constexpr (enableBioeffects) {
1094 this->bioeffects_.resize(numElems);
1095 }
1096
1097 // Initialize mixing controls before trying to set any lastRx valuesx
1098 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1099
1100 if constexpr (enableBioeffects) {
1101 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1102 }
1103
1104 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1105 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1106 elemFluidState.setPvtRegionIndex(pvtRegionIndex(elemIdx));
1107 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1108 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1109
1110 // Note: Function processRestartSaturations_() mutates the
1111 // 'ssol' argument--the value from the restart file--if solvent
1112 // is enabled. Then, store the updated solvent saturation into
1113 // 'solventSaturation_'. Otherwise, just pass a dummy value to
1114 // the function and discard the unchanged result. Do not index
1115 // into 'solventSaturation_' unless solvent is enabled.
1116 {
1117 auto ssol = enableSolvent
1118 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1119 : Scalar(0);
1120
1121 this->processRestartSaturations_(elemFluidState, ssol);
1122
1123 if constexpr (enableSolvent) {
1124 this->solventSaturation_[elemIdx] = ssol;
1125 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1126 }
1127 }
1128
1129 // For CO2STORE and H2STORE we need to set the initial temperature for isothermal simulations
1130 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1131 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1132 if (needTemperature) {
1133 const auto& fp = simulator.vanguard().eclState().fieldProps();
1134 elemFluidState.setTemperature(fp.get_double("TEMPI")[elemIdx]);
1135 }
1136 }
1137
1138 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1139
1140 if constexpr (enablePolymer)
1141 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1142 // if we need to restart for polymer molecular weight simulation, we need to add related here
1143 }
1144
1145 const int episodeIdx = this->episodeIndex();
1146 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1147
1148 // assign the restart solution to the current solution. note that we still need
1149 // to compute real initial solution after this because the initial fluid states
1150 // need to be correct for stuff like boundary conditions.
1151 auto& sol = this->model().solution(/*timeIdx=*/0);
1152 const auto& gridView = this->gridView();
1153 ElementContext elemCtx(simulator);
1154 for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1155 elemCtx.updatePrimaryStencil(elem);
1156 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1157 this->initial(sol[elemIdx], elemCtx, /*spaceIdx=*/0, /*timeIdx=*/0);
1158 }
1159
1160 // make sure that the ghost and overlap entities exhibit the correct
1161 // solution. alternatively, this could be done in the loop above by also
1162 // considering non-interior elements. Since the initial() method might not work
1163 // 100% correctly for such elements, let's play safe and explicitly synchronize
1164 // using message passing.
1165 this->model().syncOverlap();
1166
1167 if (fip_init) {
1168 this->updateReferencePorosity_();
1169 this->mixControls_.init(this->model().numGridDof(),
1170 this->episodeIndex(),
1171 eclState.runspec().tabdims().getNumPVTTables());
1172 }
1173 }
1174
1178 Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
1179 { return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1180
1182 { return thresholdPressures_; }
1183
1185 { return thresholdPressures_; }
1186
1188 {
1189 return moduleParams_;
1190 }
1191
1192 template<class Serializer>
1193 void serializeOp(Serializer& serializer)
1194 {
1195 serializer(static_cast<FlowProblemType&>(*this));
1196 serializer(mixControls_);
1197 serializer(*eclWriter_);
1198 }
1199
1200protected:
1201 void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
1202 {
1203 this->updateExplicitQuantities_(first_step_after_restart);
1204
1205 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1206 updateMaxPolymerAdsorption_();
1207
1208 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1209 }
1210
1212 {
1213 // we need to update the max polymer adsoption data for all elements
1214 this->updateProperty_("FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1215 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1216 {
1217 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1218 });
1219 }
1220
1221 bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1222 {
1223 const Scalar pa = scalarValue(iq.polymerAdsorption());
1224 auto& mpa = this->polymer_.maxAdsorption;
1225 if (mpa[compressedDofIdx] < pa) {
1226 mpa[compressedDofIdx] = pa;
1227 return true;
1228 } else {
1229 return false;
1230 }
1231 }
1232
1234 {
1235 std::vector<Scalar> sumInvB(numPhases, 0.0);
1236 const auto& gridView = this->gridView();
1237 ElementContext elemCtx(this->simulator());
1238 for(const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1239 elemCtx.updatePrimaryStencil(elem);
1240 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1241 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1242 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1243 if (!FluidSystem::phaseIsActive(phaseIdx))
1244 continue;
1245
1246 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1247 }
1248 }
1249
1250 std::size_t numDof = this->model().numGridDof();
1251 const auto& comm = this->simulator().vanguard().grid().comm();
1252 comm.sum(sumInvB.data(),sumInvB.size());
1253 Scalar numTotalDof = comm.sum(numDof);
1254
1255 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1256 if (!FluidSystem::phaseIsActive(phaseIdx))
1257 continue;
1258
1259 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1260 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1261 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1262 this->model().setEqWeight(activeSolventCompIdx, avgB);
1263 }
1264 }
1265
1266 // update the parameters needed for DRSDT and DRVDT
1268 {
1269 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1270 // update the "last Rs" values for all elements, including the ones in the ghost
1271 // and overlap regions
1272 int episodeIdx = this->episodeIndex();
1273 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1274 this->mixControls_.drsdtActive(episodeIdx),
1275 this->mixControls_.drvdtActive(episodeIdx)};
1276 if (!active[0] && !active[1] && !active[2]) {
1277 return false;
1278 }
1279
1280 this->updateProperty_("FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1281 [this,episodeIdx,active](unsigned compressedDofIdx,
1282 const IntensiveQuantities& iq)
1283 {
1284 const DimMatrix& perm = this->intrinsicPermeability(compressedDofIdx);
1285 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1286 const int pvtRegionIdx = this->pvtRegionIndex(compressedDofIdx);
1287 this->mixControls_.update(compressedDofIdx,
1288 iq,
1289 episodeIdx,
1290 this->gravity_[dim - 1],
1291 perm[dim - 1][dim - 1],
1292 distZ,
1293 pvtRegionIdx);
1294 }
1295 );
1296
1297 return true;
1298 }
1299
1301 {
1302 // Throw an exception if the grid has LGRs. Refined grid are not supported for restart.
1303 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1304 throw std::invalid_argument("Refined grids are not yet supported for restart ");
1305 }
1306
1307 // Set the start time of the simulation
1308 auto& simulator = this->simulator();
1309 const auto& schedule = simulator.vanguard().schedule();
1310 const auto& eclState = simulator.vanguard().eclState();
1311 const auto& initconfig = eclState.getInitConfig();
1312 const int restart_step = initconfig.getRestartStep();
1313 {
1314 simulator.setTime(schedule.seconds(restart_step));
1315
1316 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1317 schedule.stepLength(restart_step));
1318 simulator.setEpisodeIndex(restart_step);
1319 }
1320 this->eclWriter_->beginRestart();
1321
1322 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1323 simulator.setTimeStepSize(dt);
1324
1325 this->readSolutionFromOutputModule(restart_step, false);
1326
1327 this->eclWriter_->endRestart();
1328 }
1329
1331 {
1332 const auto& simulator = this->simulator();
1333
1334 // initial condition corresponds to hydrostatic conditions.
1335 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1336
1337 std::size_t numElems = this->model().numGridDof();
1338 this->initialFluidStates_.resize(numElems);
1339 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1340 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1341 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1342 }
1343 }
1344
1346 {
1347 const auto& simulator = this->simulator();
1348 const auto& vanguard = simulator.vanguard();
1349 const auto& eclState = vanguard.eclState();
1350 const auto& fp = eclState.fieldProps();
1351 bool has_swat = fp.has_double("SWAT");
1352 bool has_sgas = fp.has_double("SGAS");
1353 bool has_rs = fp.has_double("RS");
1354 bool has_rsw = fp.has_double("RSW");
1355 bool has_rv = fp.has_double("RV");
1356 bool has_rvw = fp.has_double("RVW");
1357 bool has_pressure = fp.has_double("PRESSURE");
1358 bool has_salt = fp.has_double("SALT");
1359 bool has_saltp = fp.has_double("SALTP");
1360
1361 // make sure all required quantities are enables
1362 if (Indices::numPhases > 1) {
1363 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1364 throw std::runtime_error("The ECL input file requires the presence of the SWAT keyword if "
1365 "the water phase is active");
1366 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1367 throw std::runtime_error("The ECL input file requires the presence of the SGAS keyword if "
1368 "the gas phase is active");
1369 }
1370 if (!has_pressure)
1371 throw std::runtime_error("The ECL input file requires the presence of the PRESSURE "
1372 "keyword if the model is initialized explicitly");
1373 if (FluidSystem::enableDissolvedGas() && !has_rs)
1374 throw std::runtime_error("The ECL input file requires the RS keyword to be present if"
1375 " dissolved gas is enabled and the model is initialized explicitly");
1376 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1377 OpmLog::warning("The model is initialized explicitly and the RSW keyword is not present in the"
1378 " ECL input file. The RSW values are set equal to 0");
1379 if (FluidSystem::enableVaporizedOil() && !has_rv)
1380 throw std::runtime_error("The ECL input file requires the RV keyword to be present if"
1381 " vaporized oil is enabled and the model is initialized explicitly");
1382 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1383 throw std::runtime_error("The ECL input file requires the RVW keyword to be present if"
1384 " vaporized water is enabled and the model is initialized explicitly");
1385 if (enableBrine && !has_salt)
1386 throw std::runtime_error("The ECL input file requires the SALT keyword to be present if"
1387 " brine is enabled and the model is initialized explicitly");
1388 if (enableSaltPrecipitation && !has_saltp)
1389 throw std::runtime_error("The ECL input file requires the SALTP keyword to be present if"
1390 " salt precipitation is enabled and the model is initialized explicitly");
1391
1392 std::size_t numDof = this->model().numGridDof();
1393
1394 initialFluidStates_.resize(numDof);
1395
1396 std::vector<double> waterSaturationData;
1397 std::vector<double> gasSaturationData;
1398 std::vector<double> pressureData;
1399 std::vector<double> rsData;
1400 std::vector<double> rswData;
1401 std::vector<double> rvData;
1402 std::vector<double> rvwData;
1403 std::vector<double> tempiData;
1404 std::vector<double> saltData;
1405 std::vector<double> saltpData;
1406
1407 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1408 waterSaturationData = fp.get_double("SWAT");
1409 else
1410 waterSaturationData.resize(numDof);
1411
1412 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1413 gasSaturationData = fp.get_double("SGAS");
1414 else
1415 gasSaturationData.resize(numDof);
1416
1417 pressureData = fp.get_double("PRESSURE");
1418 if (FluidSystem::enableDissolvedGas())
1419 rsData = fp.get_double("RS");
1420
1421 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1422 rswData = fp.get_double("RSW");
1423
1424 if (FluidSystem::enableVaporizedOil())
1425 rvData = fp.get_double("RV");
1426
1427 if (FluidSystem::enableVaporizedWater())
1428 rvwData = fp.get_double("RVW");
1429
1430 // initial reservoir temperature
1431 tempiData = fp.get_double("TEMPI");
1432
1433 // initial salt concentration data
1434 if constexpr (enableBrine)
1435 saltData = fp.get_double("SALT");
1436
1437 // initial precipitated salt saturation data
1438 if constexpr (enableSaltPrecipitation)
1439 saltpData = fp.get_double("SALTP");
1440
1441 // calculate the initial fluid states
1442 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1443 auto& dofFluidState = initialFluidStates_[dofIdx];
1444
1445 dofFluidState.setPvtRegionIndex(pvtRegionIndex(dofIdx));
1446
1448 // set temperature
1450 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1451 Scalar temperatureLoc = tempiData[dofIdx];
1452 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1453 temperatureLoc = FluidSystem::surfaceTemperature;
1454 dofFluidState.setTemperature(temperatureLoc);
1455 }
1456
1458 // set salt concentration
1460 if constexpr (enableBrine)
1461 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1462
1464 // set precipitated salt saturation
1466 if constexpr (enableSaltPrecipitation)
1467 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1468
1470 // set saturations
1472 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1473 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1474 waterSaturationData[dofIdx]);
1475
1476 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1477 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1478 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1479 1.0
1480 - waterSaturationData[dofIdx]);
1481 }
1482 else
1483 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1484 gasSaturationData[dofIdx]);
1485 }
1486 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1487 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1488 if (soil < smallSaturationTolerance_) {
1489 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1490 }
1491 else {
1492 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1493 }
1494 }
1495
1497 // set phase pressures
1499 Scalar pressure = pressureData[dofIdx]; // oil pressure (or gas pressure for water-gas system or water pressure for single phase)
1500
1501 // this assumes that capillary pressures only depend on the phase saturations
1502 // and possibly on temperature. (this is always the case for ECL problems.)
1503 std::array<Scalar, numPhases> pc = {0};
1504 const auto& matParams = this->materialLawParams(dofIdx);
1505 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1506 Valgrind::CheckDefined(pressure);
1507 Valgrind::CheckDefined(pc);
1508 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1509 if (!FluidSystem::phaseIsActive(phaseIdx))
1510 continue;
1511
1512 if (Indices::oilEnabled)
1513 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1514 else if (Indices::gasEnabled)
1515 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1516 else if (Indices::waterEnabled)
1517 //single (water) phase
1518 dofFluidState.setPressure(phaseIdx, pressure);
1519 }
1520
1521 if constexpr (enableDissolvedGas) {
1522 if (FluidSystem::enableDissolvedGas())
1523 dofFluidState.setRs(rsData[dofIdx]);
1524 else if (Indices::gasEnabled && Indices::oilEnabled)
1525 dofFluidState.setRs(0.0);
1526 if (FluidSystem::enableVaporizedOil())
1527 dofFluidState.setRv(rvData[dofIdx]);
1528 else if (Indices::gasEnabled && Indices::oilEnabled)
1529 dofFluidState.setRv(0.0);
1530 }
1531
1532 if constexpr (enableDisgasInWater) {
1533 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1534 dofFluidState.setRsw(rswData[dofIdx]);
1535 }
1536
1537 if constexpr (enableVapwat) {
1538 if (FluidSystem::enableVaporizedWater())
1539 dofFluidState.setRvw(rvwData[dofIdx]);
1540 }
1541
1543 // set invB_
1545 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1546 if (!FluidSystem::phaseIsActive(phaseIdx))
1547 continue;
1548
1549 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1550 dofFluidState.setInvB(phaseIdx, b);
1551
1552 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1553 dofFluidState.setDensity(phaseIdx, rho);
1554
1555 }
1556 }
1557 }
1558
1559
1560 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar& solventSaturation)
1561 {
1562 // each phase needs to be above certain value to be claimed to be existing
1563 // this is used to recover some RESTART running with the defaulted single-precision format
1564 Scalar sumSaturation = 0.0;
1565 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1566 if (FluidSystem::phaseIsActive(phaseIdx)) {
1567 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1568 elemFluidState.setSaturation(phaseIdx, 0.0);
1569
1570 sumSaturation += elemFluidState.saturation(phaseIdx);
1571 }
1572
1573 }
1574 if constexpr (enableSolvent) {
1575 if (solventSaturation < smallSaturationTolerance_)
1576 solventSaturation = 0.0;
1577
1578 sumSaturation += solventSaturation;
1579 }
1580
1581 assert(sumSaturation > 0.0);
1582
1583 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1584 if (FluidSystem::phaseIsActive(phaseIdx)) {
1585 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1586 elemFluidState.setSaturation(phaseIdx, saturation);
1587 }
1588 }
1589 if constexpr (enableSolvent) {
1590 solventSaturation = solventSaturation / sumSaturation;
1591 }
1592 }
1593
1595 {
1596 FlowProblemType::readInitialCondition_();
1597
1598 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1599 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1600 enableSolvent,
1601 enablePolymer,
1602 enablePolymerMolarWeight,
1603 enableBioeffects,
1604 enableMICP);
1605
1606 }
1607
1608 void handleSolventBC(const BCProp::BCFace& bc, RateVector& rate) const override
1609 {
1610 if constexpr (!enableSolvent)
1611 throw std::logic_error("solvent is disabled and you're trying to add solvent to BC");
1612
1613 rate[Indices::solventSaturationIdx] = bc.rate;
1614 }
1615
1616 void handlePolymerBC(const BCProp::BCFace& bc, RateVector& rate) const override
1617 {
1618 if constexpr (!enablePolymer)
1619 throw std::logic_error("polymer is disabled and you're trying to add polymer to BC");
1620
1621 rate[Indices::polymerConcentrationIdx] = bc.rate;
1622 }
1623
1624 void handleMicrBC(const BCProp::BCFace& bc, RateVector& rate) const override
1625 {
1626 if constexpr (!enableMICP)
1627 throw std::logic_error("MICP is disabled and you're trying to add microbes to BC");
1628
1629 rate[Indices::microbialConcentrationIdx] = bc.rate;
1630 }
1631
1632 void handleOxygBC(const BCProp::BCFace& bc, RateVector& rate) const override
1633 {
1634 if constexpr (!enableMICP)
1635 throw std::logic_error("MICP is disabled and you're trying to add oxygen to BC");
1636
1637 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1638 }
1639
1640 void handleUreaBC(const BCProp::BCFace& bc, RateVector& rate) const override
1641 {
1642 if constexpr (!enableMICP)
1643 throw std::logic_error("MICP is disabled and you're trying to add urea to BC");
1644
1645 rate[Indices::ureaConcentrationIdx] = bc.rate;
1646 // since the urea concentration can be much larger than 1, then we apply a scaling factor
1647 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1648 }
1649
1650 void updateExplicitQuantities_(const bool first_step_after_restart)
1651 {
1652 OPM_TIMEBLOCK(updateExplicitQuantities);
1653 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1654 const bool invalidateFromMinPressure = this->updateMinPressure_();
1655
1656 // update hysteresis and max oil saturation used in vappars
1657 const bool invalidateFromHyst = this->updateHysteresis_();
1658 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1659
1660 // deal with DRSDT and DRVDT
1661 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1662
1663 // the derivatives may have changed
1664 const bool invalidateIntensiveQuantities
1665 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1666 if (invalidateIntensiveQuantities) {
1667 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1668 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1669 }
1670
1671 this->updateRockCompTransMultVal_();
1672 }
1673
1675 {
1676 if (const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1677 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1678 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1679 nph < 2)
1680 {
1681 // Single phase runs don't need saturation functions and there's
1682 // nothing to do here. Return 'true' to tell caller that the
1683 // consistency requirements are Met.
1684 return true;
1685 }
1686
1687 const auto numSamplePoints = static_cast<std::size_t>
1688 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1689
1690 auto sfuncConsistencyChecks =
1692 numSamplePoints, this->simulator().vanguard().eclState(),
1693 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](const int elemIdx)
1694 { return cmap.cartesianIndex(elemIdx); }
1695 };
1696
1697 const auto ioRank = 0;
1698 const auto isIoRank = this->simulator().vanguard()
1699 .grid().comm().rank() == ioRank;
1700
1701 // Note: Run saturation function consistency checks on main grid
1702 // only (i.e., levelGridView(0)). These checks are not supported
1703 // for LGRs at this time.
1704 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1705 .run(this->simulator().vanguard().grid().levelGridView(0),
1706 [&vg = this->simulator().vanguard(),
1707 &emap = this->simulator().model().elementMapper()]
1708 (const auto& elem)
1709 { return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1710
1711 using ViolationLevel = typename Satfunc::PhaseChecks::
1712 SatfuncConsistencyCheckManager<Scalar>::ViolationLevel;
1713
1714 auto reportFailures = [&sfuncConsistencyChecks]
1715 (const ViolationLevel level)
1716 {
1717 sfuncConsistencyChecks.reportFailures
1718 (level, [](std::string_view record)
1719 { OpmLog::info(std::string { record }); });
1720 };
1721
1722 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1723 if (isIoRank) {
1724 OpmLog::warning("Saturation Function "
1725 "End-point Consistency Problems");
1726
1727 reportFailures(ViolationLevel::Standard);
1728 }
1729 }
1730
1731 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1732 if (isIoRank) {
1733 OpmLog::error("Saturation Function "
1734 "End-point Consistency Failures");
1735
1736 reportFailures(ViolationLevel::Critical);
1737 }
1738
1739 // There are "critical" check failures. Report that consistency
1740 // requirements are not Met.
1741 return false;
1742 }
1743
1744 // If we get here then there are no critical failures. Report
1745 // Met = true, i.e., that the consistency requirements ARE met.
1746 return true;
1747 }
1748
1750
1751 std::vector<InitialFluidState> initialFluidStates_;
1752
1754 std::unique_ptr<EclWriterType> eclWriter_;
1755
1756 const Scalar smallSaturationTolerance_ = 1.e-6;
1757#if HAVE_DAMARIS
1758 bool enableDamarisOutput_ = false ;
1759 std::unique_ptr<DamarisWriterType> damarisWriter_;
1760#endif
1762
1764
1766
1768
1769private:
1780 bool episodeWillBeOver() const override
1781 {
1782 const auto currTime = this->simulator().time()
1783 + this->simulator().timeStepSize();
1784
1785 const auto nextReportStep =
1786 this->simulator().vanguard().schedule()
1787 .seconds(this->simulator().episodeIndex() + 1);
1788
1789 const auto isSubStep = (nextReportStep - currTime)
1790 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;
1791
1792 return !isSubStep;
1793 }
1794};
1795
1796} // namespace Opm
1797
1798#endif // OPM_FLOW_PROBLEM_BLACK_HPP
Classes required for dynamic convective mixing.
Contains classes extending the black-oil model. \detail This file holds dummy definitions,...
Class handling Action support in simulator.
Definition: ActionHandler.hpp:52
Provides the auxiliary methods required for consideration of the diffusion equation.
Provides the auxiliary methods required for consideration of the dispersion equation.
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:60
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:101
Collects necessary output values and pass it to opm-common's ECL output.
Definition: EclWriter.hpp:123
static void registerParameters()
Definition: EclWriter.hpp:151
Computes the initial condition based on the EQUIL keyword from ECL.
Definition: EquilInitializer.hpp:59
const ScalarFluidState & initialFluidState(unsigned elemIdx) const
Return the initial thermodynamic state which should be used as the initial condition.
Definition: EquilInitializer.hpp:202
BlackOilFluidState< Scalar, FluidSystem, energyModuleType !=EnergyModules::NoTemperature, energyModuleType==EnergyModules::FullyImplicitThermal, enableDissolution, enableVapwat, enableBrine, enableSaltPrecipitation, enableDisgasInWater, enableSolvent, Indices::numPhases > ScalarFluidState
Definition: EquilInitializer.hpp:102
void readRockParameters_(const std::vector< Scalar > &cellCenterDepths, std::function< std::array< int, 3 >(const unsigned)> ijkIndex)
Definition: FlowGenericProblem_impl.hpp:153
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblemBlackoil.hpp:87
HybridNewton hybridNewton_
Definition: FlowProblemBlackoil.hpp:1767
void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
Definition: FlowProblemBlackoil.hpp:1201
bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblemBlackoil.hpp:1221
void handlePolymerBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1616
void writeOutput(const bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition: FlowProblemBlackoil.hpp:591
void readInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1594
void handleOxygBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1632
void readEquilInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1330
void handleSolventBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1608
Scalar maxGasDissolutionFactor(unsigned timeIdx, unsigned globalDofIdx) const
Returns the maximum value of the gas dissolution factor at the current time for a given degree of fre...
Definition: FlowProblemBlackoil.hpp:917
const std::vector< InitialFluidState > & initialFluidStates() const
Definition: FlowProblemBlackoil.hpp:781
void processRestartSaturations_(InitialFluidState &elemFluidState, Scalar &solventSaturation)
Definition: FlowProblemBlackoil.hpp:1560
std::vector< InitialFluidState > & initialFluidStates()
Definition: FlowProblemBlackoil.hpp:778
FlowProblemBlackoil(Simulator &simulator)
Definition: FlowProblemBlackoil.hpp:189
bool enableEclOutput_
Definition: FlowProblemBlackoil.hpp:1753
Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:1012
void endStepApplyAction()
Definition: FlowProblemBlackoil.hpp:512
bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:1018
Scalar maxOilVaporizationFactor(unsigned timeIdx, unsigned globalDofIdx) const
Returns the maximum value of the oil vaporization factor at the current time for a given degree of fr...
Definition: FlowProblemBlackoil.hpp:928
std::vector< InitialFluidState > initialFluidStates_
Definition: FlowProblemBlackoil.hpp:1751
void endTimeStep() override
Called by the simulator after each time integration.
Definition: FlowProblemBlackoil.hpp:506
void updateMaxPolymerAdsorption_()
Definition: FlowProblemBlackoil.hpp:1211
const InitialFluidState & initialFluidState(unsigned globalDofIdx) const
Definition: FlowProblemBlackoil.hpp:775
void endEpisode() override
Called by the simulator after the end of an episode.
Definition: FlowProblemBlackoil.hpp:559
void setSubStepReport(const SimulatorReportSingle &report)
Definition: FlowProblemBlackoil.hpp:787
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemBlackoil.hpp:968
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: FlowProblemBlackoil.hpp:324
void handleMicrBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1624
const FlowThresholdPressure< TypeTag > & thresholdPressure() const
Definition: FlowProblemBlackoil.hpp:1181
void finalizeOutput()
Definition: FlowProblemBlackoil.hpp:614
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemBlackoil.hpp:1029
InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
Definition: FlowProblemBlackoil.hpp:793
std::unique_ptr< EclWriterType > eclWriter_
Definition: FlowProblemBlackoil.hpp:1754
void initialSolutionApplied() override
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblemBlackoil.hpp:626
const ModuleParams & moduleParams() const
Definition: FlowProblemBlackoil.hpp:1187
void readEclRestartSolution_()
Definition: FlowProblemBlackoil.hpp:1300
FlowThresholdPressure< TypeTag > & thresholdPressure()
Definition: FlowProblemBlackoil.hpp:1184
FlowThresholdPressure< TypeTag > thresholdPressures_
Definition: FlowProblemBlackoil.hpp:1749
void readExplicitInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1345
void beginEpisode() override
Called by the simulator before an episode begins.
Definition: FlowProblemBlackoil.hpp:282
bool recycleFirstIterationStorage() const
Return if the storage term of the first iteration is identical to the storage term for the solution o...
Definition: FlowProblemBlackoil.hpp:946
LhsEval permFactTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Calculate the transmissibility multiplier due to porosity reduction.
Definition: FlowProblemBlackoil.hpp:755
void serializeOp(Serializer &serializer)
Definition: FlowProblemBlackoil.hpp:1193
MixingRateControls< FluidSystem > mixControls_
Definition: FlowProblemBlackoil.hpp:1761
void writeReports(const SimulatorTimer &timer)
Definition: FlowProblemBlackoil.hpp:579
ModuleParams moduleParams_
Definition: FlowProblemBlackoil.hpp:1765
const EclWriterType & eclWriter() const
Definition: FlowProblemBlackoil.hpp:907
void setSimulationReport(const SimulatorReport &report)
Definition: FlowProblemBlackoil.hpp:790
void addToSourceDense(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const override
Definition: FlowProblemBlackoil.hpp:648
void computeAndSetEqWeights_()
Definition: FlowProblemBlackoil.hpp:1233
void beginTimeStep() override
Called by the simulator before each time integration.
Definition: FlowProblemBlackoil.hpp:315
void updateExplicitQuantities_(const bool first_step_after_restart)
Definition: FlowProblemBlackoil.hpp:1650
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblemBlackoil.hpp:175
ActionHandler< Scalar, IndexTraits > actionHandler_
Definition: FlowProblemBlackoil.hpp:1763
void readSolutionFromOutputModule(const int restart_step, bool fip_init)
Read simulator solution state from the outputmodule (used with restart)
Definition: FlowProblemBlackoil.hpp:1070
const EclipseIO & eclIO() const
Definition: FlowProblemBlackoil.hpp:784
Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
Definition: FlowProblemBlackoil.hpp:1178
void handleUreaBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1640
EclWriterType & eclWriter()
Definition: FlowProblemBlackoil.hpp:910
bool satfuncConsistencyRequirementsMet() const
Definition: FlowProblemBlackoil.hpp:1674
bool updateCompositionChangeLimits_()
Definition: FlowProblemBlackoil.hpp:1267
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:95
static constexpr bool enableFoam
Definition: FlowProblem.hpp:126
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:523
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:906
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:706
GetPropType< TypeTag, Properties::Vanguard > Vanguard
Definition: FlowProblem.hpp:108
@ numComponents
Definition: FlowProblem.hpp:118
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: FlowProblem.hpp:102
void initGravity_(const EclipseState &eclState)
Set the gravity vector from the run's configuration.
Definition: FlowProblem.hpp:1627
GetPropType< TypeTag, Properties::EqVector > EqVector
Definition: FlowProblem.hpp:107
GetPropType< TypeTag, Properties::ElementContext > ElementContext
Definition: FlowProblem.hpp:152
GlobalEqVector drift_
Definition: FlowProblem.hpp:1856
@ gasCompIdx
Definition: FlowProblem.hpp:144
GetPropType< TypeTag, Properties::RateVector > RateVector
Definition: FlowProblem.hpp:149
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: FlowProblem.hpp:166
@ waterPhaseIdx
Definition: FlowProblem.hpp:140
int episodeIndex() const
Definition: FlowProblem.hpp:304
GetPropType< TypeTag, Properties::Indices > Indices
Definition: FlowProblem.hpp:109
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: FlowProblem.hpp:106
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: FlowProblem.hpp:150
@ enableExperiments
Definition: FlowProblem.hpp:133
static constexpr bool enableDiffusion
Definition: FlowProblem.hpp:123
@ dimWorld
Definition: FlowProblem.hpp:113
TracerModel tracerModel_
Definition: FlowProblem.hpp:1862
@ enableThermalFluxBoundaries
Definition: FlowProblem.hpp:136
WellModel wellModel_
Definition: FlowProblem.hpp:1858
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:312
static constexpr bool enablePolymerMolarWeight
Definition: FlowProblem.hpp:128
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:371
@ gasPhaseIdx
Definition: FlowProblem.hpp:138
static constexpr bool enableSolvent
Definition: FlowProblem.hpp:129
@ numPhases
Definition: FlowProblem.hpp:117
static constexpr bool enablePolymer
Definition: FlowProblem.hpp:127
@ numEq
Definition: FlowProblem.hpp:116
void readThermalParameters_()
Definition: FlowProblem.hpp:1481
@ dim
Definition: FlowProblem.hpp:112
GetPropType< TypeTag, Properties::IntensiveQuantities > IntensiveQuantities
Definition: FlowProblem.hpp:161
@ enableSaltPrecipitation
Definition: FlowProblem.hpp:135
TemperatureModel temperatureModel_
Definition: FlowProblem.hpp:1863
static constexpr bool enableExtbo
Definition: FlowProblem.hpp:125
static constexpr bool enableConvectiveMixing
Definition: FlowProblem.hpp:122
GetPropType< TypeTag, Properties::GridView > GridView
Definition: FlowProblem.hpp:103
@ oilCompIdx
Definition: FlowProblem.hpp:145
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:191
void updatePffDofData_()
Definition: FlowProblem.hpp:1649
static constexpr bool enableDispersion
Definition: FlowProblem.hpp:124
@ oilPhaseIdx
Definition: FlowProblem.hpp:139
GetPropType< TypeTag, Properties::PrimaryVariables > PrimaryVariables
Definition: FlowProblem.hpp:148
void readBoundaryConditions_()
Definition: FlowProblem.hpp:1680
Vanguard::TransmissibilityType transmissibilities_
Definition: FlowProblem.hpp:1851
static constexpr EnergyModules energyModuleType
Definition: FlowProblem.hpp:131
GetPropType< TypeTag, Properties::FluidSystem > FluidSystem
Definition: FlowProblem.hpp:105
GetPropType< TypeTag, Properties::MaterialLaw > MaterialLaw
Definition: FlowProblem.hpp:158
static constexpr bool enableBioeffects
Definition: FlowProblem.hpp:120
void readMaterialParameters_()
Definition: FlowProblem.hpp:1441
static constexpr bool enableBrine
Definition: FlowProblem.hpp:121
@ waterCompIdx
Definition: FlowProblem.hpp:146
@ enableMICP
Definition: FlowProblem.hpp:134
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Definition: FlowThresholdPressure.hpp:59
Class handling mixing rate controls for a FlowProblemBlackoil.
Definition: MixingRateControls.hpp:46
Definition: SatfuncConsistencyCheckManager.hpp:58
SatfuncConsistencyCheckManager & collectFailuresTo(const int root)
Definition: SatfuncConsistencyCheckManager.hpp:99
void run(const GridView &gv, GetCellIndex &&getCellIndex)
Definition: SatfuncConsistencyCheckManager.hpp:128
Definition: SimulatorTimer.hpp:38
VTK output module for the tracer model's parameters.
Definition: VtkTracerModule.hpp:58
static void registerParameters()
Register all run-time parameters for the tracer VTK output module.
Definition: VtkTracerModule.hpp:84
@ NONE
Definition: DeferredLogger.hpp:46
static constexpr int dim
Definition: structuredgridvanguard.hh:68
Definition: blackoilbioeffectsmodules.hh:45
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
Struct holding the parameters for the BlackOilBioeffectsModule class.
Definition: blackoilbioeffectsparams.hpp:42
Struct holding the parameters for the BlackoilBrineModule class.
Definition: blackoilbrineparams.hpp:42
Struct holding the parameters for the BlackoilExtboModule class.
Definition: blackoilextboparams.hpp:47
Struct holding the parameters for the BlackoilFoamModule class.
Definition: blackoilfoamparams.hpp:44
Struct holding the parameters for the BlackOilPolymerModule class.
Definition: blackoilpolymerparams.hpp:43
Struct holding the parameters for the BlackOilSolventModule class.
Definition: blackoilsolventparams.hpp:47
Definition: SimulatorReport.hpp:125
A struct for returning timing data from a simulator to its caller.
Definition: SimulatorReport.hpp:34