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