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 // the "NOGRAV" keyword from Frontsim or setting the EnableGravity to false
380 // disables gravity, else the standard value of the gravity constant at sea level
381 // on earth is used
382 this->gravity_ = 0.0;
383 if (Parameters::Get<Parameters::EnableGravity>() &&
384 eclState.getInitConfig().hasGravity())
385 {
386 // unit::gravity is 9.80665 m^2/s--i.e., standard measure at Tellus equator.
387 this->gravity_[dim - 1] = unit::gravity;
388 }
389
390 if (this->enableTuning_) {
391 // if support for the TUNING keyword is enabled, we get the initial time
392 // steping parameters from it instead of from command line parameters
393 const auto& tuning = schedule[0].tuning();
394 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
395 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
396 }
397
398 // conserve inner energy instead of enthalpy if TEMP is used
399 // or THERMAL and parameter ConserveInnerEnergyThermal is true (default false)
400 bool isThermal = eclState.getSimulationConfig().isThermal();
401 bool isTemp = eclState.getSimulationConfig().isTemp();
402 bool conserveInnerEnergy = isTemp || (isThermal && Parameters::Get<Parameters::ConserveInnerEnergyThermal>());
403 FluidSystem::setEnergyEqualEnthalpy(conserveInnerEnergy);
404
405 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
406 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
407 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
408 }
409
410 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
411 [&simulator](const unsigned idx)
412 {
413 std::array<int,dim> coords;
414 simulator.vanguard().cartesianCoordinate(idx, coords);
415 std::ranges::transform(coords, coords.begin(),
416 [](const auto c) { return c + 1; });
417 return coords;
418 });
419
422
423 // write the static output files (EGRID, INIT)
424 if (enableEclOutput_) {
425 this->eclWriter_->writeInit();
426 }
427
428 finishTransmissibilities();
429
430 const auto& initconfig = eclState.getInitConfig();
431 this->tracerModel_.init(initconfig.restartRequested());
432 if (initconfig.restartRequested()) {
434 }
435 else {
436 this->readInitialCondition_();
437 }
438 this->temperatureModel_.init();
439 this->tracerModel_.prepareTracerBatches();
440
441 this->updatePffDofData_();
442
443 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
444 const auto& vanguard = this->simulator().vanguard();
445 const auto& gridView = vanguard.gridView();
446 const int numElements = gridView.size(/*codim=*/0);
447 this->polymer_.maxAdsorption.resize(numElements, 0.0);
448 }
449
451
452 // compute and set eq weights based on initial b values
454
456 this->drift_.resize(this->model().numGridDof());
457 this->drift_ = 0.0;
458 }
459
460 // after finishing the initialization and writing the initial solution, we move
461 // to the first "real" episode/report step
462 // for restart the episode index and start is already set
463 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
464 simulator.startNextEpisode(schedule.seconds(1));
465 simulator.setEpisodeIndex(0);
466 simulator.setTimeStepIndex(0);
467 }
468
469 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
471 {
472 // User requested that saturation functions be checked for
473 // consistency and essential/critical requirements are not met.
474 // Abort simulation run.
475 //
476 // Note: We need synchronisation here lest ranks other than the
477 // I/O rank throw exceptions too early thereby risking an
478 // incomplete failure report being shown to the user.
479 this->simulator().vanguard().grid().comm().barrier();
480
481 throw std::domain_error {
482 "Saturation function end-points do not "
483 "meet requisite consistency conditions"
484 };
485 }
486
487 // TODO: move to the end for later refactoring of the function finishInit()
488 //
489 // deal with DRSDT
490 this->mixControls_.init(this->model().numGridDof(),
491 this->episodeIndex(),
492 eclState.runspec().tabdims().getNumPVTTables());
493
494 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
495 simulator.setTimeStepSize(0.0);
496 simulator.model().applyInitialSolution();
498 }
499
500 if (!eclState.getIOConfig().initOnly()) {
501 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
502 OpmLog::info("\nThe deck has TUNING in the SCHEDULE section, but "
503 "it is ignored due\nto the flag --enable-tuning=false. "
504 "Set this flag to true to activate it.\n"
505 "Manually tuning the simulator with the TUNING keyword may "
506 "increase run time.\nIt is recommended using the simulator's "
507 "default tuning (--enable-tuning=false).");
508 }
509 }
510 }
511
515 void endTimeStep() override
516 {
517 FlowProblemType::endTimeStep();
518 this->endStepApplyAction();
519 }
520
522 {
523 // After the solution is updated, the values in output module needs
524 // also updated.
525 this->eclWriter().mutableOutputModule().invalidateLocalData();
526
527 // For CpGrid with LGRs, ecl/vtk output is not supported yet.
528 const auto& grid = this->simulator().vanguard().gridView().grid();
529
530 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
531 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
532 if (!isCpGrid || (grid.maxLevel() == 0)) {
533 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
534 }
535
536 {
537 OPM_TIMEBLOCK(applyActions);
538
539 const int episodeIdx = this->episodeIndex();
540 auto& simulator = this->simulator();
541
542 // Clear out any existing events as these have already been
543 // processed when we're running an action block
544 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
545
546 // Re-ordering in case of Alugrid
547 this->actionHandler_
548 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
549 [this](const bool global)
550 {
551 using TransUpdateQuantities = typename
552 Vanguard::TransmissibilityType::TransUpdateQuantities;
553
554 this->transmissibilities_
555 .update(global, TransUpdateQuantities::All,
556 [&vg = this->simulator().vanguard()]
557 (const unsigned int i)
558 {
559 return vg.gridIdxToEquilGridIdx(i);
560 });
561 });
562 }
563 }
564
568 void endEpisode() override
569 {
570 OPM_TIMEBLOCK(endEpisode);
571
572 // Rerun UDQ assignents following action processing on the final
573 // time step of this episode to make sure that any UDQ ASSIGN
574 // operations triggered in action blocks take effect. This is
575 // mainly to work around a shortcoming of the ScheduleState copy
576 // constructor which clears pending UDQ assignments under the
577 // assumption that all such assignments have been processed. If an
578 // action block happens to trigger on the final time step of an
579 // episode and that action block runs a UDQ assignment, then that
580 // assignment would be dropped and the rest of the simulator will
581 // never see its effect without this hack.
582 this->actionHandler_
583 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
584
585 FlowProblemType::endEpisode();
586 }
587
588 void writeReports(const SimulatorTimer& timer)
589 {
590 if (this->enableEclOutput_) {
591 this->eclWriter_->writeReports(timer);
592 }
593 }
594
595
600 void writeOutput(const bool verbose) override
601 {
602 FlowProblemType::writeOutput(verbose);
603
604 const auto isSubStep = !this->episodeWillBeOver();
605
606 auto localCellData = data::Solution {};
607
608#if HAVE_DAMARIS
609 // N.B. the Damaris output has to be done before the ECL output as the ECL one
610 // does all kinds of std::move() relocation of data
611 if (this->enableDamarisOutput_ && (this->damarisWriter_ != nullptr)) {
612 this->damarisWriter_->writeOutput(localCellData, isSubStep);
613 }
614#endif
615
616 if (this->enableEclOutput_ && (this->eclWriter_ != nullptr)) {
617 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep,
618 this->simulator().vanguard().schedule()
619 .exitStatus().has_value());
620 }
621 }
622
624 {
625 OPM_TIMEBLOCK(finalizeOutput);
626 // this will write all pending output to disk
627 // to avoid corruption of output files
628 eclWriter_.reset();
629 }
630
631
636 {
637 FlowProblemType::initialSolutionApplied();
638
639 // let the object for threshold pressures initialize itself. this is done only at
640 // this point, because determining the threshold pressures may require to access
641 // the initial solution.
642 this->thresholdPressures_.finishInit();
643
644 // For CpGrid with LGRs, ecl-output is not supported yet.
645 const auto& grid = this->simulator().vanguard().gridView().grid();
646
647 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
648 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
649 // Skip - for now - calculate the initial fip values for CpGrid with LGRs.
650 if (!isCpGrid || (grid.maxLevel() == 0)) {
651 if (this->simulator().episodeIndex() == 0) {
652 eclWriter_->writeInitialFIPReport();
653 }
654 }
655 }
656
658 unsigned globalDofIdx,
659 unsigned timeIdx) const override
660 {
661 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
662
663 // Add source term from deck
664 const auto& source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
665 std::array<int,3> ijk;
666 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
667
668 if (source.hasSource(ijk)) {
669 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
670 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
671 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
672 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
673
674 for (unsigned i = 0; i < phidx_map.size(); ++i) {
675 const auto phaseIdx = phidx_map[i];
676 const auto sourceComp = sc_map[i];
677 const auto compIdx = cidx_map[i];
678 if (!FluidSystem::phaseIsActive(phaseIdx)) {
679 continue;
680 }
681 Scalar mass_rate = source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
682 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
683 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
684 }
685 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
686 }
687
688 if constexpr (enableSolvent) {
689 Scalar mass_rate = source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
690 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
691 const auto& solventPvt = SolventModule::solventPvt();
692 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
693 }
694 rate[Indices::contiSolventEqIdx] += mass_rate;
695 }
696 if constexpr (enablePolymer) {
697 rate[Indices::polymerConcentrationIdx] += source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
698 }
699 if constexpr (enableMICP) {
700 rate[Indices::microbialConcentrationIdx] += source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
701 rate[Indices::oxygenConcentrationIdx] += source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
702 rate[Indices::ureaConcentrationIdx] += source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
703 }
704 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
705 for (unsigned i = 0; i < phidx_map.size(); ++i) {
706 const auto phaseIdx = phidx_map[i];
707 if (!FluidSystem::phaseIsActive(phaseIdx)) {
708 continue;
709 }
710 const auto sourceComp = sc_map[i];
711 const auto source_hrate = source.hrate(ijk, sourceComp);
712 if (source_hrate) {
713 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
714 } else {
715 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, /*timeIdx*/ 0);
716 auto fs = intQuants.fluidState();
717 // if temperature is not set, use cell temperature as default
718 const auto source_temp = source.temperature(ijk, sourceComp);
719 if (source_temp) {
720 Scalar temperature = source_temp.value();
721 fs.setTemperature(temperature);
722 }
723 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
724 Scalar mass_rate = source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
725 Scalar energy_rate = getValue(h)*mass_rate;
726 rate[Indices::contiEnergyEqIdx] += energy_rate;
727 }
728 }
729 }
730 }
731
732 // if requested, compensate systematic mass loss for cells which were "well
733 // behaved" in the last time step
734 if (this->enableDriftCompensation_) {
735 const auto& simulator = this->simulator();
736 const auto& model = this->model();
737
738 // we use a lower tolerance for the compensation too
739 // assure the added drift from the last step does not
740 // cause convergence issues on the current step
741 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
742 Scalar poro = this->porosity(globalDofIdx, timeIdx);
743 Scalar dt = simulator.timeStepSize();
744 EqVector dofDriftRate = this->drift_[globalDofIdx];
745 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
746
747 // restrict drift compensation to the CNV tolerance
748 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
749 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
750 if (cnv > maxCompensation) {
751 dofDriftRate[eqIdx] *= maxCompensation/cnv;
752 }
753 }
754
755 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
756 rate[eqIdx] -= dofDriftRate[eqIdx];
757 }
758 }
759
763 template <class LhsEval, class Callback>
764 LhsEval permFactTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
765 {
766 OPM_TIMEBLOCK_LOCAL(permFactTransMultiplier, Subsystem::PvtProps);
767 if constexpr (enableSaltPrecipitation) {
768 const auto& fs = intQuants.fluidState();
769 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
770 LhsEval porosityFactor = obtain(1. - fs.saltSaturation());
771 porosityFactor = min(porosityFactor, 1.0);
772 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
773 return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
774 }
775 else if constexpr (enableBioeffects) {
776 return obtain(intQuants.permFactor());
777 }
778 else {
779 return 1.0;
780 }
781 }
782
783 // temporary solution to facilitate output of initial state from flow
784 const InitialFluidState& initialFluidState(unsigned globalDofIdx) const
785 { return initialFluidStates_[globalDofIdx]; }
786
787 std::vector<InitialFluidState>& initialFluidStates()
788 { return initialFluidStates_; }
789
790 const std::vector<InitialFluidState>& initialFluidStates() const
791 { return initialFluidStates_; }
792
793 const EclipseIO& eclIO() const
794 { return eclWriter_->eclIO(); }
795
797 { return eclWriter_->setSubStepReport(report); }
798
800 { return eclWriter_->setSimulationReport(report); }
801
802 InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
803 {
804 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
805 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
806 if (bcprop.size() > 0) {
807 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
808
809 // index == 0: no boundary conditions for this
810 // global cell and direction
811 if (this->bcindex_(dir)[globalDofIdx] == 0)
812 return initialFluidStates_[globalDofIdx];
813
814 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
815 if (bc.bctype == BCType::DIRICHLET )
816 {
817 InitialFluidState fluidState;
818 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
819 fluidState.setPvtRegionIndex(pvtRegionIdx);
820
821 switch (bc.component) {
822 case BCComponent::OIL:
823 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
824 throw std::logic_error("oil is not active and you're trying to add oil BC");
825
826 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
827 break;
828 case BCComponent::GAS:
829 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
830 throw std::logic_error("gas is not active and you're trying to add gas BC");
831
832 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
833 break;
834 case BCComponent::WATER:
835 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
836 throw std::logic_error("water is not active and you're trying to add water BC");
837
838 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
839 break;
840 case BCComponent::SOLVENT:
841 case BCComponent::POLYMER:
842 case BCComponent::MICR:
843 case BCComponent::OXYG:
844 case BCComponent::UREA:
846 throw std::logic_error("you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
847 }
848 fluidState.setTotalSaturation(1.0);
849 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
850 const auto pressure_input = bc.pressure;
851 if (pressure_input) {
852 pressure = *pressure_input;
853 }
854
855 std::array<Scalar, numPhases> pc = {0};
856 const auto& matParams = this->materialLawParams(globalDofIdx);
857 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
858 Valgrind::CheckDefined(pressure);
859 Valgrind::CheckDefined(pc);
860 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
861 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
862 if (Indices::oilEnabled)
863 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
864 else if (Indices::gasEnabled)
865 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
866 else if (Indices::waterEnabled)
867 //single (water) phase
868 fluidState.setPressure(phaseIdx, pressure);
869 }
870 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
871 double temperature = initialFluidStates_[globalDofIdx].temperature(0); // we only have one temperature
872 const auto temperature_input = bc.temperature;
873 if(temperature_input)
874 temperature = *temperature_input;
875 fluidState.setTemperature(temperature);
876 }
877
878 if constexpr (enableDissolvedGas) {
879 if (FluidSystem::enableDissolvedGas()) {
880 fluidState.setRs(0.0);
881 fluidState.setRv(0.0);
882 }
883 }
884 if constexpr (enableDisgasInWater) {
885 if (FluidSystem::enableDissolvedGasInWater()) {
886 fluidState.setRsw(0.0);
887 }
888 }
889 if constexpr (enableVapwat) {
890 if (FluidSystem::enableVaporizedWater()) {
891 fluidState.setRvw(0.0);
892 }
893 }
894
895 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
896 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
897
898 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
899 fluidState.setInvB(phaseIdx, b);
900
901 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
902 fluidState.setDensity(phaseIdx, rho);
903 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
904 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
905 fluidState.setEnthalpy(phaseIdx, h);
906 }
907 }
908 fluidState.checkDefined();
909 return fluidState;
910 }
911 }
912 return initialFluidStates_[globalDofIdx];
913 }
914
915
917 { return *eclWriter_; }
918
920 { return *eclWriter_; }
921
926 Scalar maxGasDissolutionFactor(unsigned timeIdx, unsigned globalDofIdx) const
927 {
928 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
929 this->episodeIndex(),
930 this->pvtRegionIndex(globalDofIdx));
931 }
932
937 Scalar maxOilVaporizationFactor(unsigned timeIdx, unsigned globalDofIdx) const
938 {
939 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
940 this->episodeIndex(),
941 this->pvtRegionIndex(globalDofIdx));
942 }
943
956 {
957 const auto& rspec = this->simulator().vanguard().eclState().runspec();
958 const bool tpsaActive = rspec.mech() && rspec.mechSolver().tpsa();
959 if (tpsaActive) {
960 return false;
961 }
962
963 int episodeIdx = this->episodeIndex();
964 return !this->mixControls_.drsdtActive(episodeIdx) &&
965 !this->mixControls_.drvdtActive(episodeIdx) &&
966 this->rockCompPoroMultWc_.empty() &&
967 this->rockCompPoroMult_.empty();
968 }
969
976 template <class Context>
977 void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
978 {
979 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
980
981 values.setPvtRegionIndex(pvtRegionIndex(context, spaceIdx, timeIdx));
982 values.assignNaive(initialFluidStates_[globalDofIdx]);
983
984 if constexpr (enableSolvent) {
985 SolventModule::assignPrimaryVars(values,
986 this->solventSaturation_[globalDofIdx],
987 this->solventRsw_[globalDofIdx]);
988 }
989
990 if constexpr (enablePolymer) {
991 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
992 }
993
994 if constexpr (enablePolymerMolarWeight) {
995 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
996 }
997
998 if constexpr (enableBrine) {
999 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
1000 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
1001 }
1002 else {
1003 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
1004 }
1005 }
1006
1007 if constexpr (enableBioeffects) {
1008 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
1009 values[Indices::biofilmVolumeFractionIdx] = this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
1010 if constexpr (enableMICP) {
1011 values[Indices::oxygenConcentrationIdx] = this->bioeffects_.oxygenConcentration[globalDofIdx];
1012 values[Indices::ureaConcentrationIdx] = this->bioeffects_.ureaConcentration[globalDofIdx];
1013 values[Indices::calciteVolumeFractionIdx] = this->bioeffects_.calciteVolumeFraction[globalDofIdx];
1014 }
1015 }
1016
1017 values.checkDefined();
1018 }
1019
1020
1021 Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
1022 {
1023 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
1024 this->pvtRegionIndex(elemIdx));
1025 }
1026
1027 bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
1028 {
1029 return this->mixControls_.drsdtConvective(episodeIdx, this->pvtRegionIndex(elemIdx));
1030 }
1031
1037 template <class Context>
1038 void boundary(BoundaryRateVector& values,
1039 const Context& context,
1040 unsigned spaceIdx,
1041 unsigned timeIdx) const
1042 {
1043 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
1044 if (!context.intersection(spaceIdx).boundary())
1045 return;
1046
1047 if constexpr (energyModuleType != EnergyModules::FullyImplicitThermal || !enableThermalFluxBoundaries)
1048 values.setNoFlow();
1049 else {
1050 // in the energy case we need to specify a non-trivial boundary condition
1051 // because the geothermal gradient needs to be maintained. for this, we
1052 // simply assume the initial temperature at the boundary and specify the
1053 // thermal flow accordingly. in this context, "thermal flow" means energy
1054 // flow due to a temerature gradient while assuming no-flow for mass
1055 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1056 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1057 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
1058 }
1059
1060 if (this->nonTrivialBoundaryConditions()) {
1061 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1062 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1063 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1064 unsigned pvtRegionIdx = pvtRegionIndex(context, spaceIdx, timeIdx);
1065 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1066 if (type == BCType::THERMAL)
1067 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1068 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1069 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1070 else if (type == BCType::RATE)
1071 values.setMassRate(massrate, pvtRegionIdx);
1072 }
1073 }
1074
1079 void readSolutionFromOutputModule(const int restart_step, bool fip_init)
1080 {
1081 auto& simulator = this->simulator();
1082 const auto& eclState = simulator.vanguard().eclState();
1083
1084 std::size_t numElems = this->model().numGridDof();
1085 this->initialFluidStates_.resize(numElems);
1086 if constexpr (enableSolvent) {
1087 this->solventSaturation_.resize(numElems, 0.0);
1088 this->solventRsw_.resize(numElems, 0.0);
1089 }
1090
1091 if constexpr (enablePolymer)
1092 this->polymer_.concentration.resize(numElems, 0.0);
1093
1094 if constexpr (enablePolymerMolarWeight) {
1095 const std::string msg {"Support of the RESTART for polymer molecular weight "
1096 "is not implemented yet. The polymer weight value will be "
1097 "zero when RESTART begins"};
1098 OpmLog::warning("NO_POLYMW_RESTART", msg);
1099 this->polymer_.moleWeight.resize(numElems, 0.0);
1100 }
1101
1102 if constexpr (enableBioeffects) {
1103 this->bioeffects_.resize(numElems);
1104 }
1105
1106 // Initialize mixing controls before trying to set any lastRx valuesx
1107 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1108
1109 if constexpr (enableBioeffects) {
1110 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1111 }
1112
1113 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1114 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1115 elemFluidState.setPvtRegionIndex(pvtRegionIndex(elemIdx));
1116 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1117 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1118
1119 // Note: Function processRestartSaturations_() mutates the
1120 // 'ssol' argument--the value from the restart file--if solvent
1121 // is enabled. Then, store the updated solvent saturation into
1122 // 'solventSaturation_'. Otherwise, just pass a dummy value to
1123 // the function and discard the unchanged result. Do not index
1124 // into 'solventSaturation_' unless solvent is enabled.
1125 {
1126 auto ssol = enableSolvent
1127 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1128 : Scalar(0);
1129
1130 this->processRestartSaturations_(elemFluidState, ssol);
1131
1132 if constexpr (enableSolvent) {
1133 this->solventSaturation_[elemIdx] = ssol;
1134 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1135 }
1136 }
1137
1138 // For CO2STORE and H2STORE we need to set the initial temperature for isothermal simulations
1139 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1140 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1141 if (needTemperature) {
1142 const auto& fp = simulator.vanguard().eclState().fieldProps();
1143 elemFluidState.setTemperature(fp.get_double("TEMPI")[elemIdx]);
1144 }
1145 }
1146
1147 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1148
1149 if constexpr (enablePolymer)
1150 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1151 // if we need to restart for polymer molecular weight simulation, we need to add related here
1152 }
1153
1154 const int episodeIdx = this->episodeIndex();
1155 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1156
1157 // assign the restart solution to the current solution. note that we still need
1158 // to compute real initial solution after this because the initial fluid states
1159 // need to be correct for stuff like boundary conditions.
1160 auto& sol = this->model().solution(/*timeIdx=*/0);
1161 const auto& gridView = this->gridView();
1162 ElementContext elemCtx(simulator);
1163 for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1164 elemCtx.updatePrimaryStencil(elem);
1165 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1166 this->initial(sol[elemIdx], elemCtx, /*spaceIdx=*/0, /*timeIdx=*/0);
1167 }
1168
1169 // make sure that the ghost and overlap entities exhibit the correct
1170 // solution. alternatively, this could be done in the loop above by also
1171 // considering non-interior elements. Since the initial() method might not work
1172 // 100% correctly for such elements, let's play safe and explicitly synchronize
1173 // using message passing.
1174 this->model().syncOverlap();
1175
1176 if (fip_init) {
1177 this->updateReferencePorosity_();
1178 this->mixControls_.init(this->model().numGridDof(),
1179 this->episodeIndex(),
1180 eclState.runspec().tabdims().getNumPVTTables());
1181 }
1182 }
1183
1187 Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
1188 { return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1189
1191 { return thresholdPressures_; }
1192
1194 { return thresholdPressures_; }
1195
1197 {
1198 return moduleParams_;
1199 }
1200
1201 template<class Serializer>
1202 void serializeOp(Serializer& serializer)
1203 {
1204 serializer(static_cast<FlowProblemType&>(*this));
1205 serializer(mixControls_);
1206 serializer(*eclWriter_);
1207 }
1208
1209protected:
1210 void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
1211 {
1212 this->updateExplicitQuantities_(first_step_after_restart);
1213
1214 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1215 updateMaxPolymerAdsorption_();
1216
1217 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1218 }
1219
1221 {
1222 // we need to update the max polymer adsoption data for all elements
1223 this->updateProperty_("FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1224 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1225 {
1226 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1227 });
1228 }
1229
1230 bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1231 {
1232 const Scalar pa = scalarValue(iq.polymerAdsorption());
1233 auto& mpa = this->polymer_.maxAdsorption;
1234 if (mpa[compressedDofIdx] < pa) {
1235 mpa[compressedDofIdx] = pa;
1236 return true;
1237 } else {
1238 return false;
1239 }
1240 }
1241
1243 {
1244 std::vector<Scalar> sumInvB(numPhases, 0.0);
1245 const auto& gridView = this->gridView();
1246 ElementContext elemCtx(this->simulator());
1247 for(const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1248 elemCtx.updatePrimaryStencil(elem);
1249 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1250 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1251 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1252 if (!FluidSystem::phaseIsActive(phaseIdx))
1253 continue;
1254
1255 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1256 }
1257 }
1258
1259 std::size_t numDof = this->model().numGridDof();
1260 const auto& comm = this->simulator().vanguard().grid().comm();
1261 comm.sum(sumInvB.data(),sumInvB.size());
1262 Scalar numTotalDof = comm.sum(numDof);
1263
1264 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1265 if (!FluidSystem::phaseIsActive(phaseIdx))
1266 continue;
1267
1268 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1269 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1270 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1271 this->model().setEqWeight(activeSolventCompIdx, avgB);
1272 }
1273 }
1274
1275 // update the parameters needed for DRSDT and DRVDT
1277 {
1278 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1279 // update the "last Rs" values for all elements, including the ones in the ghost
1280 // and overlap regions
1281 int episodeIdx = this->episodeIndex();
1282 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1283 this->mixControls_.drsdtActive(episodeIdx),
1284 this->mixControls_.drvdtActive(episodeIdx)};
1285 if (!active[0] && !active[1] && !active[2]) {
1286 return false;
1287 }
1288
1289 this->updateProperty_("FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1290 [this,episodeIdx,active](unsigned compressedDofIdx,
1291 const IntensiveQuantities& iq)
1292 {
1293 const DimMatrix& perm = this->intrinsicPermeability(compressedDofIdx);
1294 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1295 const int pvtRegionIdx = this->pvtRegionIndex(compressedDofIdx);
1296 this->mixControls_.update(compressedDofIdx,
1297 iq,
1298 episodeIdx,
1299 this->gravity_[dim - 1],
1300 perm[dim - 1][dim - 1],
1301 distZ,
1302 pvtRegionIdx);
1303 }
1304 );
1305
1306 return true;
1307 }
1308
1310 {
1311 // Throw an exception if the grid has LGRs. Refined grid are not supported for restart.
1312 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1313 throw std::invalid_argument("Refined grids are not yet supported for restart ");
1314 }
1315
1316 // Set the start time of the simulation
1317 auto& simulator = this->simulator();
1318 const auto& schedule = simulator.vanguard().schedule();
1319 const auto& eclState = simulator.vanguard().eclState();
1320 const auto& initconfig = eclState.getInitConfig();
1321 const int restart_step = initconfig.getRestartStep();
1322 {
1323 simulator.setTime(schedule.seconds(restart_step));
1324
1325 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1326 schedule.stepLength(restart_step));
1327 simulator.setEpisodeIndex(restart_step);
1328 }
1329 this->eclWriter_->beginRestart();
1330
1331 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1332 simulator.setTimeStepSize(dt);
1333
1334 this->readSolutionFromOutputModule(restart_step, false);
1335
1336 this->eclWriter_->endRestart();
1337 }
1338
1340 {
1341 const auto& simulator = this->simulator();
1342
1343 // initial condition corresponds to hydrostatic conditions.
1344 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1345
1346 std::size_t numElems = this->model().numGridDof();
1347 this->initialFluidStates_.resize(numElems);
1348 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1349 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1350 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1351 }
1352 }
1353
1355 {
1356 const auto& simulator = this->simulator();
1357 const auto& vanguard = simulator.vanguard();
1358 const auto& eclState = vanguard.eclState();
1359 const auto& fp = eclState.fieldProps();
1360 bool has_swat = fp.has_double("SWAT");
1361 bool has_sgas = fp.has_double("SGAS");
1362 bool has_rs = fp.has_double("RS");
1363 bool has_rsw = fp.has_double("RSW");
1364 bool has_rv = fp.has_double("RV");
1365 bool has_rvw = fp.has_double("RVW");
1366 bool has_pressure = fp.has_double("PRESSURE");
1367 bool has_salt = fp.has_double("SALT");
1368 bool has_saltp = fp.has_double("SALTP");
1369
1370 // make sure all required quantities are enables
1371 if (Indices::numPhases > 1) {
1372 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1373 throw std::runtime_error("The ECL input file requires the presence of the SWAT keyword if "
1374 "the water phase is active");
1375 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1376 throw std::runtime_error("The ECL input file requires the presence of the SGAS keyword if "
1377 "the gas phase is active");
1378 }
1379 if (!has_pressure)
1380 throw std::runtime_error("The ECL input file requires the presence of the PRESSURE "
1381 "keyword if the model is initialized explicitly");
1382 if (FluidSystem::enableDissolvedGas() && !has_rs)
1383 throw std::runtime_error("The ECL input file requires the RS keyword to be present if"
1384 " dissolved gas is enabled and the model is initialized explicitly");
1385 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1386 OpmLog::warning("The model is initialized explicitly and the RSW keyword is not present in the"
1387 " ECL input file. The RSW values are set equal to 0");
1388 if (FluidSystem::enableVaporizedOil() && !has_rv)
1389 throw std::runtime_error("The ECL input file requires the RV keyword to be present if"
1390 " vaporized oil is enabled and the model is initialized explicitly");
1391 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1392 throw std::runtime_error("The ECL input file requires the RVW keyword to be present if"
1393 " vaporized water is enabled and the model is initialized explicitly");
1394 if (enableBrine && !has_salt)
1395 throw std::runtime_error("The ECL input file requires the SALT keyword to be present if"
1396 " brine is enabled and the model is initialized explicitly");
1397 if (enableSaltPrecipitation && !has_saltp)
1398 throw std::runtime_error("The ECL input file requires the SALTP keyword to be present if"
1399 " salt precipitation is enabled and the model is initialized explicitly");
1400
1401 std::size_t numDof = this->model().numGridDof();
1402
1403 initialFluidStates_.resize(numDof);
1404
1405 std::vector<double> waterSaturationData;
1406 std::vector<double> gasSaturationData;
1407 std::vector<double> pressureData;
1408 std::vector<double> rsData;
1409 std::vector<double> rswData;
1410 std::vector<double> rvData;
1411 std::vector<double> rvwData;
1412 std::vector<double> tempiData;
1413 std::vector<double> saltData;
1414 std::vector<double> saltpData;
1415
1416 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1417 waterSaturationData = fp.get_double("SWAT");
1418 else
1419 waterSaturationData.resize(numDof);
1420
1421 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1422 gasSaturationData = fp.get_double("SGAS");
1423 else
1424 gasSaturationData.resize(numDof);
1425
1426 pressureData = fp.get_double("PRESSURE");
1427 if (FluidSystem::enableDissolvedGas())
1428 rsData = fp.get_double("RS");
1429
1430 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1431 rswData = fp.get_double("RSW");
1432
1433 if (FluidSystem::enableVaporizedOil())
1434 rvData = fp.get_double("RV");
1435
1436 if (FluidSystem::enableVaporizedWater())
1437 rvwData = fp.get_double("RVW");
1438
1439 // initial reservoir temperature
1440 tempiData = fp.get_double("TEMPI");
1441
1442 // initial salt concentration data
1443 if constexpr (enableBrine)
1444 saltData = fp.get_double("SALT");
1445
1446 // initial precipitated salt saturation data
1447 if constexpr (enableSaltPrecipitation)
1448 saltpData = fp.get_double("SALTP");
1449
1450 // calculate the initial fluid states
1451 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1452 auto& dofFluidState = initialFluidStates_[dofIdx];
1453
1454 dofFluidState.setPvtRegionIndex(pvtRegionIndex(dofIdx));
1455
1457 // set temperature
1459 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1460 Scalar temperatureLoc = tempiData[dofIdx];
1461 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1462 temperatureLoc = FluidSystem::surfaceTemperature;
1463 dofFluidState.setTemperature(temperatureLoc);
1464 }
1465
1467 // set salt concentration
1469 if constexpr (enableBrine)
1470 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1471
1473 // set precipitated salt saturation
1475 if constexpr (enableSaltPrecipitation)
1476 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1477
1479 // set saturations
1481 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1482 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1483 waterSaturationData[dofIdx]);
1484
1485 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1486 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1487 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1488 1.0
1489 - waterSaturationData[dofIdx]);
1490 }
1491 else
1492 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1493 gasSaturationData[dofIdx]);
1494 }
1495 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1496 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1497 if (soil < smallSaturationTolerance_) {
1498 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1499 }
1500 else {
1501 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1502 }
1503 }
1504
1506 // set phase pressures
1508 Scalar pressure = pressureData[dofIdx]; // oil pressure (or gas pressure for water-gas system or water pressure for single phase)
1509
1510 // this assumes that capillary pressures only depend on the phase saturations
1511 // and possibly on temperature. (this is always the case for ECL problems.)
1512 std::array<Scalar, numPhases> pc = {0};
1513 const auto& matParams = this->materialLawParams(dofIdx);
1514 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1515 Valgrind::CheckDefined(pressure);
1516 Valgrind::CheckDefined(pc);
1517 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1518 if (!FluidSystem::phaseIsActive(phaseIdx))
1519 continue;
1520
1521 if (Indices::oilEnabled)
1522 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1523 else if (Indices::gasEnabled)
1524 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1525 else if (Indices::waterEnabled)
1526 //single (water) phase
1527 dofFluidState.setPressure(phaseIdx, pressure);
1528 }
1529
1530 if constexpr (enableDissolvedGas) {
1531 if (FluidSystem::enableDissolvedGas())
1532 dofFluidState.setRs(rsData[dofIdx]);
1533 else if (Indices::gasEnabled && Indices::oilEnabled)
1534 dofFluidState.setRs(0.0);
1535 if (FluidSystem::enableVaporizedOil())
1536 dofFluidState.setRv(rvData[dofIdx]);
1537 else if (Indices::gasEnabled && Indices::oilEnabled)
1538 dofFluidState.setRv(0.0);
1539 }
1540
1541 if constexpr (enableDisgasInWater) {
1542 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1543 dofFluidState.setRsw(rswData[dofIdx]);
1544 }
1545
1546 if constexpr (enableVapwat) {
1547 if (FluidSystem::enableVaporizedWater())
1548 dofFluidState.setRvw(rvwData[dofIdx]);
1549 }
1550
1552 // set invB_
1554 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1555 if (!FluidSystem::phaseIsActive(phaseIdx))
1556 continue;
1557
1558 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1559 dofFluidState.setInvB(phaseIdx, b);
1560
1561 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1562 dofFluidState.setDensity(phaseIdx, rho);
1563
1564 }
1565 }
1566 }
1567
1568
1569 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar& solventSaturation)
1570 {
1571 // each phase needs to be above certain value to be claimed to be existing
1572 // this is used to recover some RESTART running with the defaulted single-precision format
1573 Scalar sumSaturation = 0.0;
1574 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1575 if (FluidSystem::phaseIsActive(phaseIdx)) {
1576 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1577 elemFluidState.setSaturation(phaseIdx, 0.0);
1578
1579 sumSaturation += elemFluidState.saturation(phaseIdx);
1580 }
1581
1582 }
1583 if constexpr (enableSolvent) {
1584 if (solventSaturation < smallSaturationTolerance_)
1585 solventSaturation = 0.0;
1586
1587 sumSaturation += solventSaturation;
1588 }
1589
1590 assert(sumSaturation > 0.0);
1591
1592 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1593 if (FluidSystem::phaseIsActive(phaseIdx)) {
1594 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1595 elemFluidState.setSaturation(phaseIdx, saturation);
1596 }
1597 }
1598 if constexpr (enableSolvent) {
1599 solventSaturation = solventSaturation / sumSaturation;
1600 }
1601 }
1602
1604 {
1605 FlowProblemType::readInitialCondition_();
1606
1607 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1608 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1609 enableSolvent,
1610 enablePolymer,
1611 enablePolymerMolarWeight,
1612 enableBioeffects,
1613 enableMICP);
1614
1615 }
1616
1617 void handleSolventBC(const BCProp::BCFace& bc, RateVector& rate) const override
1618 {
1619 if constexpr (!enableSolvent)
1620 throw std::logic_error("solvent is disabled and you're trying to add solvent to BC");
1621
1622 rate[Indices::solventSaturationIdx] = bc.rate;
1623 }
1624
1625 void handlePolymerBC(const BCProp::BCFace& bc, RateVector& rate) const override
1626 {
1627 if constexpr (!enablePolymer)
1628 throw std::logic_error("polymer is disabled and you're trying to add polymer to BC");
1629
1630 rate[Indices::polymerConcentrationIdx] = bc.rate;
1631 }
1632
1633 void handleMicrBC(const BCProp::BCFace& bc, RateVector& rate) const override
1634 {
1635 if constexpr (!enableMICP)
1636 throw std::logic_error("MICP is disabled and you're trying to add microbes to BC");
1637
1638 rate[Indices::microbialConcentrationIdx] = bc.rate;
1639 }
1640
1641 void handleOxygBC(const BCProp::BCFace& bc, RateVector& rate) const override
1642 {
1643 if constexpr (!enableMICP)
1644 throw std::logic_error("MICP is disabled and you're trying to add oxygen to BC");
1645
1646 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1647 }
1648
1649 void handleUreaBC(const BCProp::BCFace& bc, RateVector& rate) const override
1650 {
1651 if constexpr (!enableMICP)
1652 throw std::logic_error("MICP is disabled and you're trying to add urea to BC");
1653
1654 rate[Indices::ureaConcentrationIdx] = bc.rate;
1655 // since the urea concentration can be much larger than 1, then we apply a scaling factor
1656 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1657 }
1658
1659 void updateExplicitQuantities_(const bool first_step_after_restart)
1660 {
1661 OPM_TIMEBLOCK(updateExplicitQuantities);
1662 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1663 const bool invalidateFromMinPressure = this->updateMinPressure_();
1664
1665 // update hysteresis and max oil saturation used in vappars
1666 const bool invalidateFromHyst = this->updateHysteresis_();
1667 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1668
1669 // deal with DRSDT and DRVDT
1670 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1671
1672 // the derivatives may have changed
1673 const bool invalidateIntensiveQuantities
1674 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1675 if (invalidateIntensiveQuantities) {
1676 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1677 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1678 }
1679
1680 this->updateRockCompTransMultVal_();
1681 }
1682
1684 {
1685 if (const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1686 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1687 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1688 nph < 2)
1689 {
1690 // Single phase runs don't need saturation functions and there's
1691 // nothing to do here. Return 'true' to tell caller that the
1692 // consistency requirements are Met.
1693 return true;
1694 }
1695
1696 const auto numSamplePoints = static_cast<std::size_t>
1697 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1698
1699 auto sfuncConsistencyChecks =
1701 numSamplePoints, this->simulator().vanguard().eclState(),
1702 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](const int elemIdx)
1703 { return cmap.cartesianIndex(elemIdx); }
1704 };
1705
1706 const auto ioRank = 0;
1707 const auto isIoRank = this->simulator().vanguard()
1708 .grid().comm().rank() == ioRank;
1709
1710 // Note: Run saturation function consistency checks on main grid
1711 // only (i.e., levelGridView(0)). These checks are not supported
1712 // for LGRs at this time.
1713 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1714 .run(this->simulator().vanguard().grid().levelGridView(0),
1715 [&vg = this->simulator().vanguard(),
1716 &emap = this->simulator().model().elementMapper()]
1717 (const auto& elem)
1718 { return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1719
1720 using ViolationLevel = typename Satfunc::PhaseChecks::
1721 SatfuncConsistencyCheckManager<Scalar>::ViolationLevel;
1722
1723 auto reportFailures = [&sfuncConsistencyChecks]
1724 (const ViolationLevel level)
1725 {
1726 sfuncConsistencyChecks.reportFailures
1727 (level, [](std::string_view record)
1728 { OpmLog::info(std::string { record }); });
1729 };
1730
1731 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1732 if (isIoRank) {
1733 OpmLog::warning("Saturation Function "
1734 "End-point Consistency Problems");
1735
1736 reportFailures(ViolationLevel::Standard);
1737 }
1738 }
1739
1740 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1741 if (isIoRank) {
1742 OpmLog::error("Saturation Function "
1743 "End-point Consistency Failures");
1744
1745 reportFailures(ViolationLevel::Critical);
1746 }
1747
1748 // There are "critical" check failures. Report that consistency
1749 // requirements are not Met.
1750 return false;
1751 }
1752
1753 // If we get here then there are no critical failures. Report
1754 // Met = true, i.e., that the consistency requirements ARE met.
1755 return true;
1756 }
1757
1759
1760 std::vector<InitialFluidState> initialFluidStates_;
1761
1763 std::unique_ptr<EclWriterType> eclWriter_;
1764
1765 const Scalar smallSaturationTolerance_ = 1.e-6;
1766#if HAVE_DAMARIS
1767 bool enableDamarisOutput_ = false ;
1768 std::unique_ptr<DamarisWriterType> damarisWriter_;
1769#endif
1771
1773
1775
1777
1778private:
1789 bool episodeWillBeOver() const override
1790 {
1791 const auto currTime = this->simulator().time()
1792 + this->simulator().timeStepSize();
1793
1794 const auto nextReportStep =
1795 this->simulator().vanguard().schedule()
1796 .seconds(this->simulator().episodeIndex() + 1);
1797
1798 const auto isSubStep = (nextReportStep - currTime)
1799 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;
1800
1801 return !isSubStep;
1802 }
1803};
1804
1805} // namespace Opm
1806
1807#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:119
static void registerParameters()
Definition: EclWriter.hpp:144
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:137
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:1776
void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
Definition: FlowProblemBlackoil.hpp:1210
bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblemBlackoil.hpp:1230
void handlePolymerBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1625
void writeOutput(const bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition: FlowProblemBlackoil.hpp:600
void readInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1603
void handleOxygBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1641
void readEquilInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1339
void handleSolventBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1617
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:926
const std::vector< InitialFluidState > & initialFluidStates() const
Definition: FlowProblemBlackoil.hpp:790
void processRestartSaturations_(InitialFluidState &elemFluidState, Scalar &solventSaturation)
Definition: FlowProblemBlackoil.hpp:1569
std::vector< InitialFluidState > & initialFluidStates()
Definition: FlowProblemBlackoil.hpp:787
FlowProblemBlackoil(Simulator &simulator)
Definition: FlowProblemBlackoil.hpp:189
bool enableEclOutput_
Definition: FlowProblemBlackoil.hpp:1762
Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:1021
void endStepApplyAction()
Definition: FlowProblemBlackoil.hpp:521
bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:1027
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:937
std::vector< InitialFluidState > initialFluidStates_
Definition: FlowProblemBlackoil.hpp:1760
void endTimeStep() override
Called by the simulator after each time integration.
Definition: FlowProblemBlackoil.hpp:515
void updateMaxPolymerAdsorption_()
Definition: FlowProblemBlackoil.hpp:1220
const InitialFluidState & initialFluidState(unsigned globalDofIdx) const
Definition: FlowProblemBlackoil.hpp:784
void endEpisode() override
Called by the simulator after the end of an episode.
Definition: FlowProblemBlackoil.hpp:568
void setSubStepReport(const SimulatorReportSingle &report)
Definition: FlowProblemBlackoil.hpp:796
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemBlackoil.hpp:977
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:1633
const FlowThresholdPressure< TypeTag > & thresholdPressure() const
Definition: FlowProblemBlackoil.hpp:1190
void finalizeOutput()
Definition: FlowProblemBlackoil.hpp:623
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemBlackoil.hpp:1038
InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
Definition: FlowProblemBlackoil.hpp:802
std::unique_ptr< EclWriterType > eclWriter_
Definition: FlowProblemBlackoil.hpp:1763
void initialSolutionApplied() override
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblemBlackoil.hpp:635
const ModuleParams & moduleParams() const
Definition: FlowProblemBlackoil.hpp:1196
void readEclRestartSolution_()
Definition: FlowProblemBlackoil.hpp:1309
FlowThresholdPressure< TypeTag > & thresholdPressure()
Definition: FlowProblemBlackoil.hpp:1193
FlowThresholdPressure< TypeTag > thresholdPressures_
Definition: FlowProblemBlackoil.hpp:1758
void readExplicitInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1354
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:955
LhsEval permFactTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Calculate the transmissibility multiplier due to porosity reduction.
Definition: FlowProblemBlackoil.hpp:764
void serializeOp(Serializer &serializer)
Definition: FlowProblemBlackoil.hpp:1202
MixingRateControls< FluidSystem > mixControls_
Definition: FlowProblemBlackoil.hpp:1770
void writeReports(const SimulatorTimer &timer)
Definition: FlowProblemBlackoil.hpp:588
ModuleParams moduleParams_
Definition: FlowProblemBlackoil.hpp:1774
const EclWriterType & eclWriter() const
Definition: FlowProblemBlackoil.hpp:916
void setSimulationReport(const SimulatorReport &report)
Definition: FlowProblemBlackoil.hpp:799
void addToSourceDense(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const override
Definition: FlowProblemBlackoil.hpp:657
void computeAndSetEqWeights_()
Definition: FlowProblemBlackoil.hpp:1242
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:1659
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblemBlackoil.hpp:175
ActionHandler< Scalar, IndexTraits > actionHandler_
Definition: FlowProblemBlackoil.hpp:1772
void readSolutionFromOutputModule(const int restart_step, bool fip_init)
Read simulator solution state from the outputmodule (used with restart)
Definition: FlowProblemBlackoil.hpp:1079
const EclipseIO & eclIO() const
Definition: FlowProblemBlackoil.hpp:793
Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
Definition: FlowProblemBlackoil.hpp:1187
void handleUreaBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1649
EclWriterType & eclWriter()
Definition: FlowProblemBlackoil.hpp:919
bool satfuncConsistencyRequirementsMet() const
Definition: FlowProblemBlackoil.hpp:1683
bool updateCompositionChangeLimits_()
Definition: FlowProblemBlackoil.hpp:1276
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:518
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:901
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:701
GetPropType< TypeTag, Properties::Vanguard > Vanguard
Definition: FlowProblem.hpp:108
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: FlowProblem.hpp:102
GetPropType< TypeTag, Properties::EqVector > EqVector
Definition: FlowProblem.hpp:107
@ waterCompIdx
Definition: FlowProblem.hpp:146
GetPropType< TypeTag, Properties::ElementContext > ElementContext
Definition: FlowProblem.hpp:152
@ gasCompIdx
Definition: FlowProblem.hpp:144
GlobalEqVector drift_
Definition: FlowProblem.hpp:1832
@ enableSaltPrecipitation
Definition: FlowProblem.hpp:135
GetPropType< TypeTag, Properties::RateVector > RateVector
Definition: FlowProblem.hpp:149
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: FlowProblem.hpp:166
@ enableMICP
Definition: FlowProblem.hpp:134
int episodeIndex() const
Definition: FlowProblem.hpp:299
GetPropType< TypeTag, Properties::Indices > Indices
Definition: FlowProblem.hpp:109
@ dim
Definition: FlowProblem.hpp:112
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: FlowProblem.hpp:106
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: FlowProblem.hpp:150
@ dimWorld
Definition: FlowProblem.hpp:113
static constexpr bool enableDiffusion
Definition: FlowProblem.hpp:123
TracerModel tracerModel_
Definition: FlowProblem.hpp:1838
@ numComponents
Definition: FlowProblem.hpp:118
WellModel wellModel_
Definition: FlowProblem.hpp:1834
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:307
static constexpr bool enablePolymerMolarWeight
Definition: FlowProblem.hpp:128
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:366
static constexpr bool enableSolvent
Definition: FlowProblem.hpp:129
@ waterPhaseIdx
Definition: FlowProblem.hpp:140
static constexpr bool enablePolymer
Definition: FlowProblem.hpp:127
void readThermalParameters_()
Definition: FlowProblem.hpp:1477
GetPropType< TypeTag, Properties::IntensiveQuantities > IntensiveQuantities
Definition: FlowProblem.hpp:161
@ oilCompIdx
Definition: FlowProblem.hpp:145
@ numPhases
Definition: FlowProblem.hpp:117
TemperatureModel temperatureModel_
Definition: FlowProblem.hpp:1839
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
@ enableThermalFluxBoundaries
Definition: FlowProblem.hpp:136
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:186
void updatePffDofData_()
Definition: FlowProblem.hpp:1625
static constexpr bool enableDispersion
Definition: FlowProblem.hpp:124
@ enableExperiments
Definition: FlowProblem.hpp:133
GetPropType< TypeTag, Properties::PrimaryVariables > PrimaryVariables
Definition: FlowProblem.hpp:148
void readBoundaryConditions_()
Definition: FlowProblem.hpp:1656
Vanguard::TransmissibilityType transmissibilities_
Definition: FlowProblem.hpp:1827
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
@ oilPhaseIdx
Definition: FlowProblem.hpp:139
static constexpr bool enableBioeffects
Definition: FlowProblem.hpp:120
void readMaterialParameters_()
Definition: FlowProblem.hpp:1437
static constexpr bool enableBrine
Definition: FlowProblem.hpp:121
@ gasPhaseIdx
Definition: FlowProblem.hpp:138
@ numEq
Definition: FlowProblem.hpp:116
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:39
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:122
A struct for returning timing data from a simulator to its caller.
Definition: SimulatorReport.hpp:34