FlowProblem.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
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20
21 Consult the COPYING file in the top-level source directory of this
22 module for the precise wording of the license and the list of
23 copyright holders.
24*/
30#ifndef OPM_FLOW_PROBLEM_HPP
31#define OPM_FLOW_PROBLEM_HPP
32
33#include <dune/common/version.hh>
34#include <dune/common/fvector.hh>
35#include <dune/common/fmatrix.hh>
36
37#include <opm/common/utility/TimeService.hpp>
38
39#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
40#include <opm/input/eclipse/Schedule/Schedule.hpp>
41#include <opm/input/eclipse/Units/Units.hpp>
42
43#include <opm/material/common/ConditionalStorage.hpp>
44#include <opm/material/common/Valgrind.hpp>
45#include <opm/material/densead/Evaluation.hpp>
46#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
47#include <opm/material/thermal/EclThermalLawManager.hpp>
48
52
53#include <opm/output/eclipse/EclipseIO.hpp>
54
60// TODO: maybe we can name it FlowProblemProperties.hpp
68
72
73#include <opm/utility/CopyablePtr.hpp>
74
75#include <algorithm>
76#include <cstddef>
77#include <functional>
78#include <set>
79#include <stdexcept>
80#include <string>
81#include <vector>
82
83namespace Opm {
84
91template <class TypeTag>
92class FlowProblem : public GetPropType<TypeTag, Properties::BaseProblem>
93 , public FlowGenericProblem<GetPropType<TypeTag, Properties::GridView>,
94 GetPropType<TypeTag, Properties::FluidSystem>>
95{
96protected:
101
110
111 // Grid and world dimension
112 enum { dim = GridView::dimension };
113 enum { dimWorld = GridView::dimensionworld };
114
115 // copy some indices for convenience
116 enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
117 enum { numPhases = FluidSystem::numPhases };
118 enum { numComponents = FluidSystem::numComponents };
119
120 static constexpr bool enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>();
121 static constexpr bool enableBrine = getPropValue<TypeTag, Properties::EnableBrine>();
122 static constexpr bool enableConvectiveMixing = getPropValue<TypeTag, Properties::EnableConvectiveMixing>();
123 static constexpr bool enableDiffusion = getPropValue<TypeTag, Properties::EnableDiffusion>();
124 static constexpr bool enableDispersion = getPropValue<TypeTag, Properties::EnableDispersion>();
125 static constexpr bool enableExtbo = getPropValue<TypeTag, Properties::EnableExtbo>();
126 static constexpr bool enableFoam = getPropValue<TypeTag, Properties::EnableFoam>();
127 static constexpr bool enablePolymer = getPropValue<TypeTag, Properties::EnablePolymer>();
128 static constexpr bool enablePolymerMolarWeight = getPropValue<TypeTag, Properties::EnablePolymerMW>();
129 static constexpr bool enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>();
130
131 static constexpr EnergyModules energyModuleType = getPropValue<TypeTag, Properties::EnergyModuleType>();
132 enum { enableFullyImplicitThermal = getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal };
133 enum { enableExperiments = getPropValue<TypeTag, Properties::EnableExperiments>() };
134 enum { enableMICP = Indices::enableMICP };
135 enum { enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>() };
136 enum { enableThermalFluxBoundaries = getPropValue<TypeTag, Properties::EnableThermalFluxBoundaries>() };
137
138 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
139 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
140 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
141
142 // TODO: later, gasCompIdx, oilCompIdx and waterCompIdx should go to the FlowProblemBlackoil in the future
143 // we do not want them in the compositional setting
144 enum { gasCompIdx = FluidSystem::gasCompIdx };
145 enum { oilCompIdx = FluidSystem::oilCompIdx };
146 enum { waterCompIdx = FluidSystem::waterCompIdx };
147
151 using Element = typename GridView::template Codim<0>::Entity;
155 using MaterialLawParams = typename EclMaterialLawManager::MaterialLawParams;
156 using SolidEnergyLawParams = typename EclThermalLawManager::SolidEnergyLawParams;
157 using ThermalConductionLawParams = typename EclThermalLawManager::ThermalConductionLawParams;
164
165 using Toolbox = MathToolbox<Evaluation>;
166 using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
167
170 using DirectionalMobilityPtr = Utility::CopyablePtr<DirectionalMobility<TypeTag>>;
171
172public:
178 using BaseType::lame;
181 using BaseType::porosity;
182
186 static void registerParameters()
187 {
188 ParentType::registerParameters();
189
190 registerFlowProblemParameters<Scalar>();
191 }
192
202 static int handlePositionalParameter(std::function<void(const std::string&,
203 const std::string&)> addKey,
204 std::set<std::string>& seenParams,
205 std::string& errorMsg,
206 int,
207 const char** argv,
208 int paramIdx,
209 int)
210 {
211 return detail::eclPositionalParameter(addKey,
212 seenParams,
213 errorMsg,
214 argv,
215 paramIdx);
216 }
217
221 explicit FlowProblem(Simulator& simulator)
222 : ParentType(simulator)
223 , BaseType(simulator.vanguard().eclState(),
224 simulator.vanguard().schedule(),
225 simulator.vanguard().gridView())
226 , transmissibilities_(simulator.vanguard().eclState(),
227 simulator.vanguard().gridView(),
228 simulator.vanguard().cartesianIndexMapper(),
229 simulator.vanguard().grid(),
230 simulator.vanguard().cellCentroids(),
231 (energyModuleType == EnergyModules::FullyImplicitThermal ||
232 energyModuleType == EnergyModules::SequentialImplicitThermal),
235 , wellModel_(simulator, this->iterationContext())
236 , aquiferModel_(simulator)
237 , pffDofData_(simulator.gridView(), this->elementMapper())
238 , tracerModel_(simulator)
239 , temperatureModel_(simulator)
240 {
241 if (! Parameters::Get<Parameters::CheckSatfuncConsistency>()) {
242 // User did not enable the "new" saturation function consistency
243 // check module. Run the original checker instead. This is a
244 // temporary measure.
245 RelpermDiagnostics relpermDiagnostics{};
246 relpermDiagnostics.diagnosis(simulator.vanguard().eclState(),
247 simulator.vanguard().levelCartesianIndexMapper());
248 }
249
250 if (energyModuleType == EnergyModules::SequentialImplicitThermal) {
251 this->enableDriftCompensationTemp_ = Parameters::Get<Parameters::EnableDriftCompensationTemp>();
252 }
253
254 }
255
256 virtual ~FlowProblem() = default;
257
258 void prefetch(const Element& elem) const
259 { this->pffDofData_.prefetch(elem); }
260
272 template <class Restarter>
273 void deserialize(Restarter& res)
274 {
275 // reload the current episode/report step from the deck
276 this->beginEpisode();
277
278 // deserialize the wells
279 wellModel_.deserialize(res);
280
281 // deserialize the aquifer
282 aquiferModel_.deserialize(res);
283 }
284
291 template <class Restarter>
292 void serialize(Restarter& res)
293 {
294 wellModel_.serialize(res);
295
296 aquiferModel_.serialize(res);
297 }
298
299 int episodeIndex() const
300 {
301 return std::max(this->simulator().episodeIndex(), 0);
302 }
303
307 virtual void beginEpisode()
308 {
309 OPM_TIMEBLOCK(beginEpisode);
310 // Proceed to the next report step
311 auto& simulator = this->simulator();
312 int episodeIdx = simulator.episodeIndex();
313 auto& eclState = simulator.vanguard().eclState();
314 const auto& schedule = simulator.vanguard().schedule();
315 const auto& events = schedule[episodeIdx].events();
316
317 if (episodeIdx >= 0 && events.hasEvent(ScheduleEvents::GEO_MODIFIER)) {
318 // bring the contents of the keywords to the current state of the SCHEDULE
319 // section.
320 //
321 // TODO (?): make grid topology changes possible (depending on what exactly
322 // has changed, the grid may need be re-created which has some serious
323 // implications on e.g., the solution of the simulation.)
324 const auto& miniDeck = schedule[episodeIdx].geo_keywords();
325 const auto& cc = simulator.vanguard().grid().comm();
326 eclState.apply_schedule_keywords( miniDeck );
327 eclBroadcast(cc, eclState.getTransMult() );
328
329 // Re-ordering in case of ALUGrid
330 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
331 return simulator.vanguard().gridEquilIdxToGridIdx(i);
332 };
333
334 // re-compute all quantities which may possibly be affected.
335 using TransUpdateQuantities = typename Vanguard::TransmissibilityType::TransUpdateQuantities;
336 transmissibilities_.update(true, TransUpdateQuantities::All, equilGridToGrid);
337 this->referencePorosity_[1] = this->referencePorosity_[0];
339 this->rockFraction_[1] = this->rockFraction_[0];
342 this->model().linearizer().updateDiscretizationParameters();
343 }
344
345 bool tuningEvent = this->beginEpisode_(enableExperiments, this->episodeIndex());
346
347 // set up the wells for the next episode.
348 wellModel_.beginEpisode();
349
350 // set up the aquifers for the next episode.
351 aquiferModel_.beginEpisode();
352
353 // set the size of the initial time step of the episode
354 Scalar dt = limitNextTimeStepSize_(simulator.episodeLength());
355 // negative value of initialTimeStepSize_ indicates no active limit from TSINIT or NEXTSTEP
356 if ( (episodeIdx == 0 || tuningEvent) && this->initialTimeStepSize_ > 0)
357 // allow the size of the initial time step to be set via an external parameter
358 // if TUNING is enabled, also limit the time step size after a tuning event to TSINIT
359 dt = std::min(dt, this->initialTimeStepSize_);
360 simulator.setTimeStepSize(dt);
361 }
362
366 virtual void beginTimeStep()
367 {
368 OPM_TIMEBLOCK(beginTimeStep);
369 const int episodeIdx = this->episodeIndex();
370 const int timeStepSize = this->simulator().timeStepSize();
371
373 episodeIdx,
374 this->simulator().timeStepIndex(),
375 this->simulator().startTime(),
376 this->simulator().time(),
377 timeStepSize,
378 this->simulator().endTime());
379
380 // update maximum water saturation and minimum pressure
381 // used when ROCKCOMP is activated
382 // Do not update max RS first step after a restart
383 this->updateExplicitQuantities_(episodeIdx, timeStepSize, first_step_ && (episodeIdx > 0));
384 first_step_ = false;
385
387 this->model().linearizer().updateBoundaryConditionData();
388 }
389
390 wellModel_.beginTimeStep();
391 aquiferModel_.beginTimeStep();
392 tracerModel_.beginTimeStep();
393 temperatureModel_.beginTimeStep();
394
395 }
396
402 {
403 this->model().updateFailed();
404 }
405
411 {
412 this->model().advanceTimeLevel();
413 }
414
419 {
420 OPM_TIMEBLOCK(beginIteration);
421 wellModel_.beginIteration();
422 aquiferModel_.beginIteration();
423 }
424
429 {
430 OPM_TIMEBLOCK(endIteration);
431 wellModel_.endIteration();
432 aquiferModel_.endIteration();
433 }
434
438 virtual void endTimeStep()
439 {
440 OPM_TIMEBLOCK(endTimeStep);
441
442#ifndef NDEBUG
443 if constexpr (getPropValue<TypeTag, Properties::EnableDebuggingChecks>()) {
444 // in debug mode, we don't care about performance, so we check
445 // if the model does the right thing (i.e., the mass change
446 // inside the whole reservoir must be equivalent to the fluxes
447 // over the grid's boundaries plus the source rates specified by
448 // the problem).
449 const int rank = this->simulator().gridView().comm().rank();
450 if (rank == 0) {
451 std::cout << "checking conservativeness of solution\n";
452 }
453
454 this->model().checkConservativeness(/*tolerance=*/-1, /*verbose=*/true);
455 if (rank == 0) {
456 std::cout << "solution is sufficiently conservative\n";
457 }
458 }
459#endif // NDEBUG
460
461 auto& simulator = this->simulator();
462 simulator.setTimeStepIndex(simulator.timeStepIndex()+1);
463
464 this->wellModel_.endTimeStep();
465 this->aquiferModel_.endTimeStep();
466 this->tracerModel_.endTimeStep();
467
468 // Compute flux for output
469 this->model().linearizer().updateFlowsInfo();
470
472 OPM_TIMEBLOCK(driftCompansation);
473
474 const auto& residual = this->model().linearizer().residual();
475
476 for (unsigned globalDofIdx = 0; globalDofIdx < residual.size(); globalDofIdx ++) {
477 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(globalDofIdx);
478 this->drift_[sfcdofIdx] = residual[sfcdofIdx] * simulator.timeStepSize();
479
480 if constexpr (getPropValue<TypeTag, Properties::UseVolumetricResidual>()) {
481 this->drift_[sfcdofIdx] *= this->model().dofTotalVolume(sfcdofIdx);
482 }
483 }
484 }
485
486 // Drift compensation needs to be updated before calling the temperature equation
487 if constexpr(energyModuleType == EnergyModules::SequentialImplicitThermal) {
488 this->temperatureModel_.endTimeStep(wellModel_.wellState());
489 }
490 }
491
495 virtual void endEpisode()
496 {
497 const int episodeIdx = this->episodeIndex();
498
499 this->wellModel_.endEpisode();
500 this->aquiferModel_.endEpisode();
501
502 const auto& schedule = this->simulator().vanguard().schedule();
503
504 // End simulation when completed.
505 if (episodeIdx + 1 >= static_cast<int>(schedule.size()) - 1) {
506 this->simulator().setFinished(true);
507 return;
508 }
509
510 // Otherwise, start next episode (report step).
511 this->simulator().startNextEpisode(schedule.stepLength(episodeIdx + 1));
512 }
513
518 virtual void writeOutput(bool verbose)
519 {
520 OPM_TIMEBLOCK(problemWriteOutput);
521
522 if (Parameters::Get<Parameters::EnableWriteAllSolutions>() ||
523 this->episodeWillBeOver())
524 {
525 // Create VTK output as needed.
526 ParentType::writeOutput(verbose);
527 }
528 }
529
533 template <class Context>
534 const DimMatrix& intrinsicPermeability(const Context& context,
535 unsigned spaceIdx,
536 unsigned timeIdx) const
537 {
538 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
539 return transmissibilities_.permeability(globalSpaceIdx);
540 }
541
548 const DimMatrix& intrinsicPermeability(unsigned globalElemIdx) const
549 { return transmissibilities_.permeability(globalElemIdx); }
550
554 template <class Context>
555 Scalar transmissibility(const Context& context,
556 [[maybe_unused]] unsigned fromDofLocalIdx,
557 unsigned toDofLocalIdx) const
558 {
559 assert(fromDofLocalIdx == 0);
560 return pffDofData_.get(context.element(), toDofLocalIdx).transmissibility;
561 }
562
566 Scalar transmissibility(unsigned globalCenterElemIdx, unsigned globalElemIdx) const
567 {
568 return transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
569 }
570
574 template <class Context>
575 Scalar diffusivity(const Context& context,
576 [[maybe_unused]] unsigned fromDofLocalIdx,
577 unsigned toDofLocalIdx) const
578 {
579 assert(fromDofLocalIdx == 0);
580 return *pffDofData_.get(context.element(), toDofLocalIdx).diffusivity;
581 }
582
586 Scalar diffusivity(const unsigned globalCellIn, const unsigned globalCellOut) const{
587 return transmissibilities_.diffusivity(globalCellIn, globalCellOut);
588 }
589
593 Scalar dispersivity(const unsigned globalCellIn, const unsigned globalCellOut) const{
594 return transmissibilities_.dispersivity(globalCellIn, globalCellOut);
595 }
596
600 Scalar thermalTransmissibilityBoundary(const unsigned globalSpaceIdx,
601 const unsigned boundaryFaceIdx) const
602 {
603 return transmissibilities_.thermalTransmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
604 }
605
606
607
608
612 template <class Context>
613 Scalar transmissibilityBoundary(const Context& elemCtx,
614 unsigned boundaryFaceIdx) const
615 {
616 unsigned elemIdx = elemCtx.globalSpaceIndex(/*dofIdx=*/0, /*timeIdx=*/0);
617 return transmissibilities_.transmissibilityBoundary(elemIdx, boundaryFaceIdx);
618 }
619
623 Scalar transmissibilityBoundary(const unsigned globalSpaceIdx,
624 const unsigned boundaryFaceIdx) const
625 {
626 return transmissibilities_.transmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
627 }
628
629
633 Scalar thermalHalfTransmissibility(const unsigned globalSpaceIdxIn,
634 const unsigned globalSpaceIdxOut) const
635 {
636 return transmissibilities_.thermalHalfTrans(globalSpaceIdxIn,globalSpaceIdxOut);
637 }
638
642 template <class Context>
643 Scalar thermalHalfTransmissibilityIn(const Context& context,
644 unsigned faceIdx,
645 unsigned timeIdx) const
646 {
647 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
648 unsigned toDofLocalIdx = face.exteriorIndex();
649 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransIn;
650 }
651
655 template <class Context>
657 unsigned faceIdx,
658 unsigned timeIdx) const
659 {
660 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
661 unsigned toDofLocalIdx = face.exteriorIndex();
662 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransOut;
663 }
664
668 template <class Context>
670 unsigned boundaryFaceIdx) const
671 {
672 unsigned elemIdx = elemCtx.globalSpaceIndex(/*dofIdx=*/0, /*timeIdx=*/0);
673 return transmissibilities_.thermalHalfTransBoundary(elemIdx, boundaryFaceIdx);
674 }
675
679 const typename Vanguard::TransmissibilityType& eclTransmissibilities() const
680 { return transmissibilities_; }
681
682
684 { return tracerModel_; }
685
687 { return tracerModel_; }
688
689 TemperatureModel& temperatureModel() // need for restart
690 { return temperatureModel_; }
691
700 template <class Context>
701 Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
702 {
703 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
704 return this->porosity(globalSpaceIdx, timeIdx);
705 }
706
713 template <class Context>
714 Scalar dofCenterDepth(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
715 {
716 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
717 return this->dofCenterDepth(globalSpaceIdx);
718 }
719
726 Scalar dofCenterDepth(unsigned globalSpaceIdx) const
727 {
728 return this->simulator().vanguard().cellCenterDepth(globalSpaceIdx);
729 }
730
734 template <class Context>
735 Scalar rockCompressibility(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
736 {
737 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
738 return this->rockCompressibility(globalSpaceIdx);
739 }
740
744 template <class Context>
745 Scalar rockBiotComp(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
746 {
747 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
748 return this->rockBiotComp(globalSpaceIdx);
749 }
750
754 template <class Context>
755 Scalar lame(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
756 {
757 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
758 return this->lame(globalSpaceIdx);
759 }
760
764 template <class Context>
765 Scalar biotCoeff(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
766 {
767 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
768 return this->biotCoeff(globalSpaceIdx);
769 }
770
774 template <class Context>
775 Scalar rockReferencePressure(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
776 {
777 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
778 return rockReferencePressure(globalSpaceIdx);
779 }
780
784 Scalar rockReferencePressure(unsigned globalSpaceIdx) const
785 {
786 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
787 if (rock_config.store()) {
788 return asImp_().initialFluidState(globalSpaceIdx).pressure(refPressurePhaseIdx_());
789 }
790 else {
791 if (this->rockParams_.empty())
792 return 1e5;
793
794 unsigned tableIdx = 0;
795 if (!this->rockTableIdx_.empty()) {
796 tableIdx = this->rockTableIdx_[globalSpaceIdx];
797 }
798 return this->rockParams_[tableIdx].referencePressure;
799 }
800 }
801
805 template <class Context>
806 const MaterialLawParams& materialLawParams(const Context& context,
807 unsigned spaceIdx, unsigned timeIdx) const
808 {
809 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
810 return this->materialLawParams(globalSpaceIdx);
811 }
812
813 const MaterialLawParams& materialLawParams(unsigned globalDofIdx) const
814 {
815 return materialLawManager_->materialLawParams(globalDofIdx);
816 }
817
818 const MaterialLawParams& materialLawParams(unsigned globalDofIdx, FaceDir::DirEnum facedir) const
819 {
820 return materialLawManager_->materialLawParams(globalDofIdx, facedir);
821 }
822
826 template <class Context>
828 solidEnergyLawParams(const Context& context,
829 unsigned spaceIdx,
830 unsigned timeIdx) const
831 {
832 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
833 return thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
834 }
835
839 template <class Context>
841 thermalConductionLawParams(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
842 {
843 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
844 return thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
845 }
846
853 std::shared_ptr<const EclMaterialLawManager> materialLawManager() const
854 { return materialLawManager_; }
855
856 std::shared_ptr<const EclThermalLawManager> thermalLawManager() const
857 { return thermalLawManager_; }
858
859 template <class FluidState, class ...Args>
861 std::array<Evaluation,numPhases> &mobility,
863 FluidState &fluidState,
864 unsigned globalSpaceIdx) const
865 {
866 using ContainerT = std::array<Evaluation, numPhases>;
867 OPM_TIMEBLOCK_LOCAL(updateRelperms, Subsystem::SatProps);
868 {
869 // calculate relative permeabilities. note that we store the result into the
870 // mobility_ class attribute. the division by the phase viscosity happens later.
871 const auto& materialParams = materialLawParams(globalSpaceIdx);
872 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mobility, materialParams, fluidState);
873 Valgrind::CheckDefined(mobility);
874 }
875 if (materialLawManager_->hasDirectionalRelperms()
876 || materialLawManager_->hasDirectionalImbnum())
877 {
878 using Dir = FaceDir::DirEnum;
879 constexpr int ndim = 3;
880 dirMob = std::make_unique<DirectionalMobility<TypeTag>>();
881 Dir facedirs[ndim] = {Dir::XPlus, Dir::YPlus, Dir::ZPlus};
882 for (int i = 0; i<ndim; i++) {
883 const auto& materialParams = materialLawParams(globalSpaceIdx, facedirs[i]);
884 auto& mob_array = dirMob->getArray(i);
885 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mob_array, materialParams, fluidState);
886 }
887 }
888 }
889
893 std::shared_ptr<EclMaterialLawManager> materialLawManager()
894 { return materialLawManager_; }
895
900 template <class Context>
901 unsigned pvtRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
902 { return pvtRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
903
908 template <class Context>
909 unsigned satnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
910 { return this->satnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
911
916 template <class Context>
917 unsigned miscnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
918 { return this->miscnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
919
924 template <class Context>
925 unsigned plmixnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
926 { return this->plmixnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
927
928 // TODO: polymer related might need to go to the blackoil side
933 template <class Context>
934 Scalar maxPolymerAdsorption(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
935 { return this->maxPolymerAdsorption(context.globalSpaceIndex(spaceIdx, timeIdx)); }
936
940 std::string name() const
941 { return this->simulator().vanguard().caseName(); }
942
946 template <class Context>
947 Scalar temperature(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
948 {
949 // use the initial temperature of the DOF if temperature is not a primary
950 // variable
951 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
952 if constexpr (energyModuleType == EnergyModules::SequentialImplicitThermal)
953 return temperatureModel_.temperature(globalDofIdx);
954
955 return asImp_().initialFluidState(globalDofIdx).temperature(/*phaseIdx=*/0);
956 }
957
958
959 Scalar temperature(unsigned globalDofIdx, unsigned /*timeIdx*/) const
960 {
961 // use the initial temperature of the DOF if temperature is not a primary
962 // variable
963 if constexpr (energyModuleType == EnergyModules::SequentialImplicitThermal)
964 return temperatureModel_.temperature(globalDofIdx);
965
966 return asImp_().initialFluidState(globalDofIdx).temperature(/*phaseIdx=*/0);
967 }
968
970 solidEnergyLawParams(unsigned globalSpaceIdx,
971 unsigned /*timeIdx*/) const
972 {
973 return this->thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
974 }
976 thermalConductionLawParams(unsigned globalSpaceIdx,
977 unsigned /*timeIdx*/)const
978 {
979 return this->thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
980 }
981
991 Scalar maxOilSaturation(unsigned globalDofIdx) const
992 {
993 if (!this->vapparsActive(this->episodeIndex()))
994 return 0.0;
995
996 return this->maxOilSaturation_[globalDofIdx];
997 }
998
1008 void setMaxOilSaturation(unsigned globalDofIdx, Scalar value)
1009 {
1010 if (!this->vapparsActive(this->episodeIndex()))
1011 return;
1012
1013 this->maxOilSaturation_[globalDofIdx] = value;
1014 }
1015
1020 {
1021 // Calculate all intensive quantities.
1022 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx*/0);
1023
1024 // We also need the intensive quantities for timeIdx == 1
1025 // corresponding to the start of the current timestep, if we
1026 // do not use the storage cache, or if we cannot recycle the
1027 // first iteration storage.
1028 if (!this->model().enableStorageCache() || !this->recycleFirstIterationStorage()) {
1029 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx*/1);
1030 }
1031
1032 // initialize the wells. Note that this needs to be done after initializing the
1033 // intrinsic permeabilities and the after applying the initial solution because
1034 // the well model uses these...
1035 wellModel_.init();
1036
1037 aquiferModel_.initialSolutionApplied();
1038
1039 const bool invalidateFromHyst = updateHysteresis_();
1040 if (invalidateFromHyst) {
1041 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1042 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1043 }
1044 }
1045
1051 template <class Context>
1052 void source(RateVector& rate,
1053 const Context& context,
1054 unsigned spaceIdx,
1055 unsigned timeIdx) const
1056 {
1057 const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
1058 source(rate, globalDofIdx, timeIdx);
1059 }
1060
1061 void source(RateVector& rate,
1062 unsigned globalDofIdx,
1063 unsigned timeIdx) const
1064 {
1065 OPM_TIMEBLOCK_LOCAL(eclProblemSource, Subsystem::Assembly);
1066 rate = 0.0;
1067
1068 // Add well contribution to source here.
1069 wellModel_.computeTotalRatesForDof(rate, globalDofIdx);
1070
1071 // convert the source term from the total mass rate of the
1072 // cell to the one per unit of volume as used by the model.
1073 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
1074 rate[eqIdx] /= this->model().dofTotalVolume(globalDofIdx);
1075
1076 Valgrind::CheckDefined(rate[eqIdx]);
1077 assert(isfinite(rate[eqIdx]));
1078 }
1079
1080 // Add non-well sources.
1081 addToSourceDense(rate, globalDofIdx, timeIdx);
1082 }
1083
1084 virtual void addToSourceDense(RateVector& rate,
1085 unsigned globalDofIdx,
1086 unsigned timeIdx) const = 0;
1087
1093 const WellModel& wellModel() const
1094 { return wellModel_; }
1095
1097 { return wellModel_; }
1098
1100 { return aquiferModel_; }
1101
1103 { return aquiferModel_; }
1104
1107
1115 {
1116 OPM_TIMEBLOCK(nexTimeStepSize);
1117 // allow external code to do the timestepping
1118 if (this->nextTimeStepSize_ > 0.0)
1119 return this->nextTimeStepSize_;
1120
1121 const auto& simulator = this->simulator();
1122 int episodeIdx = simulator.episodeIndex();
1123
1124 // for the initial episode, we use a fixed time step size
1125 if (episodeIdx < 0)
1126 return this->initialTimeStepSize_;
1127
1128 // ask the newton method for a suggestion. This suggestion will be based on how
1129 // well the previous time step converged. After that, apply the runtime time
1130 // stepping constraints.
1131 const auto& newtonMethod = this->model().newtonMethod();
1132 return limitNextTimeStepSize_(newtonMethod.suggestTimeStepSize(simulator.timeStepSize()));
1133 }
1134
1140 template <class LhsEval>
1141 LhsEval rockCompPoroMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1142 {
1143 OPM_TIMEBLOCK_LOCAL(rockCompPoroMultiplier, Subsystem::PvtProps);
1144 if (this->rockCompPoroMult_.empty() && this->rockCompPoroMultWc_.empty())
1145 return 1.0;
1146
1147 unsigned tableIdx = 0;
1148 if (!this->rockTableIdx_.empty())
1149 tableIdx = this->rockTableIdx_[elementIdx];
1150
1151 const auto& fs = intQuants.fluidState();
1152 LhsEval effectivePressure = decay<LhsEval>(fs.pressure(refPressurePhaseIdx_()));
1153 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1154 if (!this->minRefPressure_.empty())
1155 // The pore space change is irreversible
1156 effectivePressure =
1157 min(decay<LhsEval>(fs.pressure(refPressurePhaseIdx_())),
1158 this->minRefPressure_[elementIdx]);
1159
1160 if (!this->overburdenPressure_.empty())
1161 effectivePressure -= this->overburdenPressure_[elementIdx];
1162
1163 if (rock_config.store()) {
1164 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1165 }
1166
1167 if (!this->rockCompPoroMult_.empty()) {
1168 return this->rockCompPoroMult_[tableIdx].eval(effectivePressure, /*extrapolation=*/true);
1169 }
1170
1171 // water compaction
1172 assert(!this->rockCompPoroMultWc_.empty());
1173 LhsEval SwMax = max(decay<LhsEval>(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1174 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1175
1176 return this->rockCompPoroMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax, /*extrapolation=*/true);
1177 }
1178
1184 template <class LhsEval>
1185 LhsEval rockCompTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1186 {
1187 auto obtain = [](const auto& value)
1188 {
1189 if constexpr (std::is_same_v<LhsEval, Scalar>) {
1190 return getValue(value);
1191 } else {
1192 return value;
1193 }
1194 };
1195 return rockCompTransMultiplier<LhsEval>(intQuants, elementIdx, obtain);
1196 }
1197
1198 template <class LhsEval, class Callback>
1199 LhsEval rockCompTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1200 {
1201 const bool implicit = !this->explicitRockCompaction_;
1202 return implicit ? this->simulator().problem().template computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain)
1203 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1204 }
1205
1206 template <class LhsEval, class Callback>
1207 LhsEval wellTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1208 {
1209 OPM_TIMEBLOCK_LOCAL(wellTransMultiplier, Subsystem::Wells);
1210
1211 const bool implicit = !this->explicitRockCompaction_;
1212 LhsEval trans_mult = implicit ? this->simulator().problem().template computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain)
1213 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1214 trans_mult *= this->simulator().problem().template permFactTransMultiplier<LhsEval>(intQuants, elementIdx, obtain);
1215
1216 return trans_mult;
1217 }
1218
1219 std::pair<BCType, RateVector> boundaryCondition(const unsigned int globalSpaceIdx, const int directionId) const
1220 {
1221 OPM_TIMEBLOCK_LOCAL(boundaryCondition, Subsystem::Assembly);
1223 return { BCType::NONE, RateVector(0.0) };
1224 }
1225 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
1226 const auto& schedule = this->simulator().vanguard().schedule();
1227 if (bcindex_(dir)[globalSpaceIdx] == 0) {
1228 return { BCType::NONE, RateVector(0.0) };
1229 }
1230 if (schedule[this->episodeIndex()].bcprop.size() == 0) {
1231 return { BCType::NONE, RateVector(0.0) };
1232 }
1233 const auto& bc = schedule[this->episodeIndex()].bcprop[bcindex_(dir)[globalSpaceIdx]];
1234 if (bc.bctype!=BCType::RATE) {
1235 return { bc.bctype, RateVector(0.0) };
1236 }
1237
1238 RateVector rate = 0.0;
1239 switch (bc.component) {
1240 case BCComponent::OIL:
1241 rate[FluidSystem::canonicalToActiveCompIdx(oilCompIdx)] = bc.rate;
1242 break;
1243 case BCComponent::GAS:
1244 rate[FluidSystem::canonicalToActiveCompIdx(gasCompIdx)] = bc.rate;
1245 break;
1246 case BCComponent::WATER:
1247 rate[FluidSystem::canonicalToActiveCompIdx(waterCompIdx)] = bc.rate;
1248 break;
1249 case BCComponent::SOLVENT:
1250 this->handleSolventBC(bc, rate);
1251 break;
1252 case BCComponent::POLYMER:
1253 this->handlePolymerBC(bc, rate);
1254 break;
1255 case BCComponent::MICR:
1256 this->handleMicrBC(bc, rate);
1257 break;
1258 case BCComponent::OXYG:
1259 this->handleOxygBC(bc, rate);
1260 break;
1261 case BCComponent::UREA:
1262 this->handleUreaBC(bc, rate);
1263 break;
1264 case BCComponent::NONE:
1265 throw std::logic_error("you need to specify the component when RATE type is set in BC");
1266 break;
1267 }
1268 //TODO add support for enthalpy rate
1269 return {bc.bctype, rate};
1270 }
1271
1272
1273 template<class Serializer>
1274 void serializeOp(Serializer& serializer)
1275 {
1276 serializer(static_cast<BaseType&>(*this));
1277 serializer(drift_);
1278 serializer(wellModel_);
1279 serializer(aquiferModel_);
1280 serializer(tracerModel_);
1281 serializer(*materialLawManager_);
1282 }
1283
1284 const GlobalEqVector& drift() const
1285 {
1286 return drift_;
1287 }
1288
1289private:
1290 Implementation& asImp_()
1291 { return *static_cast<Implementation *>(this); }
1292
1293 const Implementation& asImp_() const
1294 { return *static_cast<const Implementation *>(this); }
1295
1296protected:
1297 template<class UpdateFunc>
1298 void updateProperty_(const std::string& failureMsg,
1299 UpdateFunc func)
1300 {
1301 OPM_TIMEBLOCK(updateProperty);
1302 const auto& model = this->simulator().model();
1303 const auto& primaryVars = model.solution(/*timeIdx*/0);
1304 const auto& vanguard = this->simulator().vanguard();
1305 std::size_t numGridDof = primaryVars.size();
1307#ifdef _OPENMP
1308#pragma omp parallel for
1309#endif
1310 for (unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
1311 const auto& iq = *model.cachedIntensiveQuantities(dofIdx, /*timeIdx=*/ 0);
1312 func(dofIdx, iq);
1313 }
1314 OPM_END_PARALLEL_TRY_CATCH(failureMsg, vanguard.grid().comm());
1315 }
1316
1318 {
1319 OPM_TIMEBLOCK(updateMaxOilSaturation);
1320 int episodeIdx = this->episodeIndex();
1321
1322 // we use VAPPARS
1323 if (this->vapparsActive(episodeIdx)) {
1324 this->updateProperty_("FlowProblem::updateMaxOilSaturation_() failed:",
1325 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1326 {
1327 this->updateMaxOilSaturation_(compressedDofIdx,iq);
1328 });
1329 return true;
1330 }
1331
1332 return false;
1333 }
1334
1335 bool updateMaxOilSaturation_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1336 {
1337 OPM_TIMEBLOCK_LOCAL(updateMaxOilSaturation, Subsystem::SatProps);
1338 const auto& fs = iq.fluidState();
1339 const Scalar So = decay<Scalar>(fs.saturation(refPressurePhaseIdx_()));
1340 auto& mos = this->maxOilSaturation_;
1341 if(mos[compressedDofIdx] < So){
1342 mos[compressedDofIdx] = So;
1343 return true;
1344 }else{
1345 return false;
1346 }
1347 }
1348
1350 {
1351 OPM_TIMEBLOCK(updateMaxWaterSaturation);
1352 // water compaction is activated in ROCKCOMP
1353 if (this->maxWaterSaturation_.empty())
1354 return false;
1355
1356 this->maxWaterSaturation_[/*timeIdx=*/1] = this->maxWaterSaturation_[/*timeIdx=*/0];
1357 this->updateProperty_("FlowProblem::updateMaxWaterSaturation_() failed:",
1358 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1359 {
1360 this->updateMaxWaterSaturation_(compressedDofIdx,iq);
1361 });
1362 return true;
1363 }
1364
1365
1366 bool updateMaxWaterSaturation_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1367 {
1368 OPM_TIMEBLOCK_LOCAL(updateMaxWaterSaturation, Subsystem::SatProps);
1369 const auto& fs = iq.fluidState();
1370 const Scalar Sw = decay<Scalar>(fs.saturation(waterPhaseIdx));
1371 auto& mow = this->maxWaterSaturation_;
1372 if(mow[compressedDofIdx]< Sw){
1373 mow[compressedDofIdx] = Sw;
1374 return true;
1375 }else{
1376 return false;
1377 }
1378 }
1379
1381 {
1382 OPM_TIMEBLOCK(updateMinPressure);
1383 // IRREVERS option is used in ROCKCOMP
1384 if (this->minRefPressure_.empty())
1385 return false;
1386
1387 this->updateProperty_("FlowProblem::updateMinPressure_() failed:",
1388 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1389 {
1390 this->updateMinPressure_(compressedDofIdx,iq);
1391 });
1392 return true;
1393 }
1394
1395 bool updateMinPressure_(unsigned compressedDofIdx, const IntensiveQuantities& iq){
1396 OPM_TIMEBLOCK_LOCAL(updateMinPressure, Subsystem::PvtProps);
1397 const auto& fs = iq.fluidState();
1398 const Scalar min_pressure = getValue(fs.pressure(refPressurePhaseIdx_()));
1399 auto& min_pressures = this->minRefPressure_;
1400 if(min_pressures[compressedDofIdx]> min_pressure){
1401 min_pressures[compressedDofIdx] = min_pressure;
1402 return true;
1403 }else{
1404 return false;
1405 }
1406 }
1407
1408 // \brief Function to assign field properties of type double, on the leaf grid view.
1409 //
1410 // For CpGrid with local grid refinement, the field property of a cell on the leaf
1411 // is inherited from its parent or equivalent (when has no parent) cell on level zero.
1412 std::function<std::vector<double>(const FieldPropsManager&, const std::string&)>
1414 {
1415 const auto& lookup = this->lookUpData_;
1416 return [&lookup](const FieldPropsManager& fieldPropManager, const std::string& propString)
1417 {
1418 return lookup.assignFieldPropsDoubleOnLeaf(fieldPropManager, propString);
1419 };
1420 }
1421
1422 // \brief Function to assign field properties of type int, unsigned int, ..., on the leaf grid view.
1423 //
1424 // For CpGrid with local grid refinement, the field property of a cell on the leaf
1425 // is inherited from its parent or equivalent (when has no parent) cell on level zero.
1426 template<typename IntType>
1427 std::function<std::vector<IntType>(const FieldPropsManager&, const std::string&, bool)>
1429 {
1430 const auto& lookup = this->lookUpData_;
1431 return [&lookup](const FieldPropsManager& fieldPropManager, const std::string& propString, bool needsTranslation)
1432 {
1433 return lookup.template assignFieldPropsIntOnLeaf<IntType>(fieldPropManager, propString, needsTranslation);
1434 };
1435 }
1436
1438 {
1439 OPM_TIMEBLOCK(readMaterialParameters);
1440 const auto& simulator = this->simulator();
1441 const auto& vanguard = simulator.vanguard();
1442 const auto& eclState = vanguard.eclState();
1443
1444 // the PVT and saturation region numbers
1446 this->updatePvtnum_();
1447 this->updateSatnum_();
1448
1449 // the MISC region numbers (solvent model)
1450 this->updateMiscnum_();
1451 // the PLMIX region numbers (polymer model)
1452 this->updatePlmixnum_();
1453
1454 OPM_END_PARALLEL_TRY_CATCH("Invalid region numbers: ", vanguard.gridView().comm());
1456 // porosity
1458 this->referencePorosity_[1] = this->referencePorosity_[0];
1460
1462 // rock fraction
1464 this->rockFraction_[1] = this->rockFraction_[0];
1466
1468 // fluid-matrix interactions (saturation functions; relperm/capillary pressure)
1469 materialLawManager_ = std::make_shared<EclMaterialLawManager>();
1470 materialLawManager_->initFromState(eclState);
1471 materialLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1472 this-> template fieldPropIntTypeOnLeafAssigner_<int>(),
1475 }
1476
1478 {
1479 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal ||
1480 energyModuleType == EnergyModules::SequentialImplicitThermal )
1481 {
1482 const auto& simulator = this->simulator();
1483 const auto& vanguard = simulator.vanguard();
1484 const auto& eclState = vanguard.eclState();
1485
1486 // fluid-matrix interactions (saturation functions; relperm/capillary pressure)
1487 thermalLawManager_ = std::make_shared<EclThermalLawManager>();
1488 thermalLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1490 this-> template fieldPropIntTypeOnLeafAssigner_<unsigned int>());
1491 }
1492 }
1493
1495 {
1496 const auto& simulator = this->simulator();
1497 const auto& vanguard = simulator.vanguard();
1498 const auto& eclState = vanguard.eclState();
1499
1500 std::size_t numDof = this->model().numGridDof();
1501
1502 this->referencePorosity_[/*timeIdx=*/0].resize(numDof);
1503
1504 const auto& fp = eclState.fieldProps();
1505 const std::vector<double> porvData = this -> fieldPropDoubleOnLeafAssigner_()(fp, "PORV");
1506 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1507 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(dofIdx);
1508 Scalar poreVolume = porvData[dofIdx];
1509
1510 // we define the porosity as the accumulated pore volume divided by the
1511 // geometric volume of the element. Note that -- in pathetic cases -- it can
1512 // be larger than 1.0!
1513 Scalar dofVolume = simulator.model().dofTotalVolume(sfcdofIdx);
1514 assert(dofVolume > 0.0);
1515 this->referencePorosity_[/*timeIdx=*/0][sfcdofIdx] = poreVolume/dofVolume;
1516 }
1517 }
1518
1520
1521 const bool solveEnergyEquation = (energyModuleType == EnergyModules::FullyImplicitThermal ||
1522 energyModuleType == EnergyModules::SequentialImplicitThermal);
1523 if (!solveEnergyEquation)
1524 return;
1525
1526 const auto& simulator = this->simulator();
1527 const auto& vanguard = simulator.vanguard();
1528 const auto& eclState = vanguard.eclState();
1529
1530 std::size_t numDof = this->model().numGridDof();
1531 this->rockFraction_[/*timeIdx=*/0].resize(numDof);
1532 // For the energy equation, we need the volume of the rock.
1533 // The volume of the rock is computed by rockFraction * geometric volume of the element.
1534 // The reference porosity is defined as porosity * ntg * pore-volume-multiplier.
1535 // A common practice in reservoir simulation is to use large pore-volume-multipliers in boundary cells
1536 // to model boundary conditions other than no-flow. This may result in reference porosities that are larger than 1.
1537 // A simple (1-reference porosity) * geometric volume of the element may give unphysical results.
1538 // We therefore instead consider the pore-volume-multiplier as a volume multiplier. The rock fraction is thus given by
1539 // (1 - porosity * ntg) * pore-volume-multiplier = (1 - porosity * ntg) * reference porosity / (porosity * ntg)
1540 const auto& fp = eclState.fieldProps();
1541 const std::vector<double> poroData = this->fieldPropDoubleOnLeafAssigner_()(fp, "PORO");
1542 const std::vector<double> ntgData = this->fieldPropDoubleOnLeafAssigner_()(fp, "NTG");
1543
1544 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1545 const auto ntg = ntgData[dofIdx];
1546 const auto poro_eff = ntg * poroData[dofIdx];
1547 const int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(dofIdx);
1548 const auto rock_fraction = (1 - poro_eff) * this->referencePorosity_[/*timeIdx=*/0][sfcdofIdx] / poro_eff;
1549 this->rockFraction_[/*timeIdx=*/0][sfcdofIdx] = rock_fraction;
1550 }
1551 }
1552
1554 {
1555 // TODO: whether we should move this to FlowProblemBlackoil
1556 const auto& simulator = this->simulator();
1557 const auto& vanguard = simulator.vanguard();
1558 const auto& eclState = vanguard.eclState();
1559
1560 if (eclState.getInitConfig().hasEquil())
1562 else
1564
1565 //initialize min/max values
1566 std::size_t numElems = this->model().numGridDof();
1567 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1568 const auto& fs = asImp_().initialFluidStates()[elemIdx];
1569 if (!this->maxWaterSaturation_.empty() && waterPhaseIdx > -1)
1570 this->maxWaterSaturation_[elemIdx] = std::max(this->maxWaterSaturation_[elemIdx], fs.saturation(waterPhaseIdx));
1571 if (!this->maxOilSaturation_.empty() && oilPhaseIdx > -1)
1572 this->maxOilSaturation_[elemIdx] = std::max(this->maxOilSaturation_[elemIdx], fs.saturation(oilPhaseIdx));
1573 if (!this->minRefPressure_.empty() && refPressurePhaseIdx_() > -1)
1574 this->minRefPressure_[elemIdx] = std::min(this->minRefPressure_[elemIdx], fs.pressure(refPressurePhaseIdx_()));
1575 }
1576 }
1577
1578 virtual void readEquilInitialCondition_() = 0;
1580
1581 // update the hysteresis parameters of the material laws for the whole grid
1583 {
1584 if (!materialLawManager_->enableHysteresis())
1585 return false;
1586
1587 // we need to update the hysteresis data for _all_ elements (i.e., not just the
1588 // interior ones) to avoid desynchronization of the processes in the parallel case!
1589 this->updateProperty_("FlowProblem::updateHysteresis_() failed:",
1590 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1591 {
1592 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1593 });
1594 return true;
1595 }
1596
1597
1598 bool updateHysteresis_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1599 {
1600 OPM_TIMEBLOCK_LOCAL(updateHysteresis_, Subsystem::SatProps);
1601 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1602 //TODO change materials to give a bool
1603 return true;
1604 }
1605
1606 Scalar getRockCompTransMultVal(std::size_t dofIdx) const
1607 {
1608 if (this->rockCompTransMultVal_.empty())
1609 return 1.0;
1610
1611 return this->rockCompTransMultVal_[dofIdx];
1612 }
1613
1614protected:
1616 {
1617 ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransIn;
1618 ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransOut;
1619 ConditionalStorage<enableDiffusion, Scalar> diffusivity;
1620 ConditionalStorage<enableDispersion, Scalar> dispersivity;
1622 };
1623
1624 // update the prefetch friendly data object
1626 {
1627 const auto& distFn =
1628 [this](PffDofData_& dofData,
1629 const Stencil& stencil,
1630 unsigned localDofIdx)
1631 -> void
1632 {
1633 const auto& elementMapper = this->model().elementMapper();
1634
1635 unsigned globalElemIdx = elementMapper.index(stencil.entity(localDofIdx));
1636 if (localDofIdx != 0) {
1637 unsigned globalCenterElemIdx = elementMapper.index(stencil.entity(/*dofIdx=*/0));
1638 dofData.transmissibility = transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
1639
1640 if constexpr (enableFullyImplicitThermal) {
1641 *dofData.thermalHalfTransIn = transmissibilities_.thermalHalfTrans(globalCenterElemIdx, globalElemIdx);
1642 *dofData.thermalHalfTransOut = transmissibilities_.thermalHalfTrans(globalElemIdx, globalCenterElemIdx);
1643 }
1644 if constexpr (enableDiffusion)
1645 *dofData.diffusivity = transmissibilities_.diffusivity(globalCenterElemIdx, globalElemIdx);
1646 if (enableDispersion)
1647 dofData.dispersivity = transmissibilities_.dispersivity(globalCenterElemIdx, globalElemIdx);
1648 }
1649 };
1650
1651 pffDofData_.update(distFn);
1652 }
1653
1654 virtual void updateExplicitQuantities_(int episodeIdx, int timeStepSize, bool first_step_after_restart) = 0;
1655
1657 {
1658 const auto& simulator = this->simulator();
1659 const auto& vanguard = simulator.vanguard();
1660 const auto& bcconfig = vanguard.eclState().getSimulationConfig().bcconfig();
1661 if (bcconfig.size() > 0) {
1663
1664 std::size_t numCartDof = vanguard.cartesianSize();
1665 unsigned numElems = vanguard.gridView().size(/*codim=*/0);
1666 std::vector<int> cartesianToCompressedElemIdx(numCartDof, -1);
1667
1668 for (unsigned elemIdx = 0; elemIdx < numElems; ++elemIdx)
1669 cartesianToCompressedElemIdx[vanguard.cartesianIndex(elemIdx)] = elemIdx;
1670
1671 bcindex_.resize(numElems, 0);
1672 auto loopAndApply = [&cartesianToCompressedElemIdx,
1673 &vanguard](const auto& bcface,
1674 auto apply)
1675 {
1676 for (int i = bcface.i1; i <= bcface.i2; ++i) {
1677 for (int j = bcface.j1; j <= bcface.j2; ++j) {
1678 for (int k = bcface.k1; k <= bcface.k2; ++k) {
1679 std::array<int, 3> tmp = {i,j,k};
1680 auto elemIdx = cartesianToCompressedElemIdx[vanguard.cartesianIndex(tmp)];
1681 if (elemIdx >= 0)
1682 apply(elemIdx);
1683 }
1684 }
1685 }
1686 };
1687 for (const auto& bcface : bcconfig) {
1688 std::vector<int>& data = bcindex_(bcface.dir);
1689 const int index = bcface.index;
1690 loopAndApply(bcface,
1691 [&data,index](int elemIdx)
1692 { data[elemIdx] = index; });
1693 }
1694 }
1695 }
1696
1697 // this method applies the runtime constraints specified via the deck and/or command
1698 // line parameters for the size of the next time step.
1700 {
1701 if constexpr (enableExperiments) {
1702 const auto& simulator = this->simulator();
1703 const auto& schedule = simulator.vanguard().schedule();
1704 int episodeIdx = simulator.episodeIndex();
1705
1706 // first thing in the morning, limit the time step size to the maximum size
1707 Scalar maxTimeStepSize = Parameters::Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60;
1708 int reportStepIdx = std::max(episodeIdx, 0);
1709 if (this->enableTuning_) {
1710 const auto& tuning = schedule[reportStepIdx].tuning();
1711 maxTimeStepSize = tuning.TSMAXZ;
1712 }
1713
1714 dtNext = std::min(dtNext, maxTimeStepSize);
1715
1716 Scalar remainingEpisodeTime =
1717 simulator.episodeStartTime() + simulator.episodeLength()
1718 - (simulator.startTime() + simulator.time());
1719 assert(remainingEpisodeTime >= 0.0);
1720
1721 // if we would have a small amount of time left over in the current episode, make
1722 // two equal time steps instead of a big and a small one
1723 if (remainingEpisodeTime/2.0 < dtNext && dtNext < remainingEpisodeTime*(1.0 - 1e-5))
1724 // note: limiting to the maximum time step size here is probably not strictly
1725 // necessary, but it should not hurt and is more fool-proof
1726 dtNext = std::min(maxTimeStepSize, remainingEpisodeTime/2.0);
1727
1728 if (simulator.episodeStarts()) {
1729 // if a well event occurred, respect the limit for the maximum time step after
1730 // that, too
1731 const auto& events = simulator.vanguard().schedule()[reportStepIdx].events();
1732 bool wellEventOccured =
1733 events.hasEvent(ScheduleEvents::NEW_WELL)
1734 || events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE)
1735 || events.hasEvent(ScheduleEvents::INJECTION_UPDATE)
1736 || events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
1737 if (episodeIdx >= 0 && wellEventOccured && this->maxTimeStepAfterWellEvent_ > 0)
1738 dtNext = std::min(dtNext, this->maxTimeStepAfterWellEvent_);
1739 }
1740 }
1741
1742 return dtNext;
1743 }
1744
1746 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1747 return oilPhaseIdx;
1748 }
1749 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1750 return gasPhaseIdx;
1751 }
1752 else {
1753 return waterPhaseIdx;
1754 }
1755 }
1756
1758 {
1759 const auto& model = this->simulator().model();
1760 std::size_t numGridDof = this->model().numGridDof();
1761 this->rockCompTransMultVal_.resize(numGridDof, 1.0);
1762 for (std::size_t elementIdx = 0; elementIdx < numGridDof; ++elementIdx) {
1763 const auto& iq = *model.cachedIntensiveQuantities(elementIdx, /*timeIdx=*/ 0);
1764 Scalar trans_mult = computeRockCompTransMultiplier_<Scalar>(iq, elementIdx);
1765 this->rockCompTransMultVal_[elementIdx] = trans_mult;
1766 }
1767 }
1768
1774 template <class LhsEval>
1775 LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1776 {
1777 auto obtain = [](const auto& value)
1778 {
1779 if constexpr (std::is_same_v<LhsEval, Scalar>) {
1780 return getValue(value);
1781 } else {
1782 return value;
1783 }
1784 };
1785
1786 return computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain);
1787 }
1788
1789 template <class LhsEval, class Callback>
1790 LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1791 {
1792 OPM_TIMEBLOCK_LOCAL(computeRockCompTransMultiplier, Subsystem::PvtProps);
1793 if (this->rockCompTransMult_.empty() && this->rockCompTransMultWc_.empty())
1794 return 1.0;
1795
1796 unsigned tableIdx = 0;
1797 if (!this->rockTableIdx_.empty())
1798 tableIdx = this->rockTableIdx_[elementIdx];
1799
1800 const auto& fs = intQuants.fluidState();
1801 LhsEval effectivePressure = obtain(fs.pressure(refPressurePhaseIdx_()));
1802 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1803 if (!this->minRefPressure_.empty())
1804 // The pore space change is irreversible
1805 effectivePressure =
1806 min(obtain(fs.pressure(refPressurePhaseIdx_())),
1807 this->minRefPressure_[elementIdx]);
1808
1809 if (!this->overburdenPressure_.empty())
1810 effectivePressure -= this->overburdenPressure_[elementIdx];
1811
1812 if (rock_config.store()) {
1813 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1814 }
1815
1816 if (!this->rockCompTransMult_.empty())
1817 return this->rockCompTransMult_[tableIdx].eval(effectivePressure, /*extrapolation=*/true);
1818
1819 // water compaction
1820 assert(!this->rockCompTransMultWc_.empty());
1821 LhsEval SwMax = max(obtain(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1822 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1823
1824 return this->rockCompTransMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax, /*extrapolation=*/true);
1825 }
1826
1827 typename Vanguard::TransmissibilityType transmissibilities_;
1828
1829 std::shared_ptr<EclMaterialLawManager> materialLawManager_;
1830 std::shared_ptr<EclThermalLawManager> thermalLawManager_;
1831
1833
1836
1840
1841 template<class T>
1842 struct BCData
1843 {
1844 std::array<std::vector<T>,6> data;
1845
1846 void resize(std::size_t size, T defVal)
1847 {
1848 for (auto& d : data)
1849 d.resize(size, defVal);
1850 }
1851
1852 const std::vector<T>& operator()(FaceDir::DirEnum dir) const
1853 {
1854 if (dir == FaceDir::DirEnum::Unknown)
1855 throw std::runtime_error("Tried to access BC data for the 'Unknown' direction");
1856 int idx = 0;
1857 int div = static_cast<int>(dir);
1858 while ((div /= 2) >= 1)
1859 ++idx;
1860 assert(idx >= 0 && idx <= 5);
1861 return data[idx];
1862 }
1863
1864 std::vector<T>& operator()(FaceDir::DirEnum dir)
1865 {
1866 return const_cast<std::vector<T>&>(std::as_const(*this)(dir));
1867 }
1868 };
1869
1870 virtual void handleSolventBC(const BCProp::BCFace&, RateVector&) const = 0;
1871
1872 virtual void handlePolymerBC(const BCProp::BCFace&, RateVector&) const = 0;
1873
1874 virtual void handleMicrBC(const BCProp::BCFace&, RateVector&) const = 0;
1875
1876 virtual void handleOxygBC(const BCProp::BCFace&, RateVector&) const = 0;
1877
1878 virtual void handleUreaBC(const BCProp::BCFace&, RateVector&) const = 0;
1879
1882 bool first_step_ = true;
1883
1886 virtual bool episodeWillBeOver() const
1887 {
1888 return this->simulator().episodeWillBeOver();
1889 }
1890};
1891
1892} // namespace Opm
1893
1894#endif // OPM_FLOW_PROBLEM_HPP
#define OPM_END_PARALLEL_TRY_CATCH(prefix, comm)
Catch exception and throw in a parallel try-catch clause.
Definition: DeferredLoggingErrorHelpers.hpp:192
#define OPM_BEGIN_PARALLEL_TRY_CATCH()
Macro to setup the try of a parallel try-catch.
Definition: DeferredLoggingErrorHelpers.hpp:158
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowGenericProblem.hpp:61
Scalar maxPolymerAdsorption(unsigned elemIdx) const
Returns the max polymer adsorption value.
Definition: FlowGenericProblem_impl.hpp:797
unsigned pvtRegionIndex(unsigned elemIdx) const
Returns the index the relevant PVT region given a cell index.
Definition: FlowGenericProblem_impl.hpp:756
std::array< std::vector< Scalar >, 2 > rockFraction_
Definition: FlowGenericProblem.hpp:338
std::function< unsigned(unsigned)> lookupIdxOnLevelZeroAssigner_()
Definition: FlowGenericProblem.hpp:384
std::vector< TabulatedTwoDFunction > rockCompPoroMultWc_
Definition: FlowGenericProblem.hpp:347
Scalar porosity(unsigned globalSpaceIdx, unsigned timeIdx) const
Direct indexed access to the porosity.
Definition: FlowGenericProblem_impl.hpp:338
Scalar rockCompressibility(unsigned globalSpaceIdx) const
Definition: FlowGenericProblem_impl.hpp:323
unsigned miscnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant MISC region given a cell index.
Definition: FlowGenericProblem_impl.hpp:776
unsigned satnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant saturation function region given a cell index.
Definition: FlowGenericProblem_impl.hpp:766
Scalar lame(unsigned elementIdx) const
Direct access to Lame's second parameter in an element.
Definition: FlowGenericProblem_impl.hpp:357
void beginTimeStep_(bool enableExperiments, int episodeIdx, int timeStepIndex, Scalar startTime, Scalar time, Scalar timeStepSize, Scalar endTime)
Definition: FlowGenericProblem_impl.hpp:508
std::vector< TabulatedTwoDFunction > rockCompTransMultWc_
Definition: FlowGenericProblem.hpp:348
unsigned plmixnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant PLMIXNUM (for polymer module) region given a cell index.
Definition: FlowGenericProblem_impl.hpp:786
std::array< std::vector< Scalar >, 2 > referencePorosity_
Definition: FlowGenericProblem.hpp:337
Scalar rockBiotComp(unsigned elementIdx) const
Returns the rock compressibility of an element due to poroelasticity.
Definition: FlowGenericProblem_impl.hpp:346
bool beginEpisode_(bool enableExperiments, int episodeIdx)
Definition: FlowGenericProblem_impl.hpp:471
bool shouldWriteOutput() const
Always returns true. The ecl output writer takes care of the rest.
Definition: FlowGenericProblem.hpp:294
static std::string helpPreamble(int, const char **argv)
Definition: FlowGenericProblem_impl.hpp:115
bool shouldWriteRestartFile() const
Returns true if an eWoms restart file should be written to disk.
Definition: FlowGenericProblem.hpp:303
Scalar biotCoeff(unsigned elementIdx) const
Direct access to Biot coefficient in an element.
Definition: FlowGenericProblem_impl.hpp:388
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:95
virtual bool episodeWillBeOver() const
Definition: FlowProblem.hpp:1886
const WellModel & wellModel() const
Returns a reference to the ECL well manager used by the problem.
Definition: FlowProblem.hpp:1093
GetPropType< TypeTag, Properties::Evaluation > Evaluation
Definition: FlowProblem.hpp:160
Scalar transmissibility(unsigned globalCenterElemIdx, unsigned globalElemIdx) const
Direct access to the transmissibility between two elements.
Definition: FlowProblem.hpp:566
static constexpr bool enableFoam
Definition: FlowProblem.hpp:126
static int handlePositionalParameter(std::function< void(const std::string &, const std::string &)> addKey, std::set< std::string > &seenParams, std::string &errorMsg, int, const char **argv, int paramIdx, int)
Handles positional command line parameters.
Definition: FlowProblem.hpp:202
bool nonTrivialBoundaryConditions() const
Definition: FlowProblem.hpp:1105
const GlobalEqVector & drift() const
Definition: FlowProblem.hpp:1284
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:518
std::function< std::vector< IntType >(const FieldPropsManager &, const std::string &, bool)> fieldPropIntTypeOnLeafAssigner_()
Definition: FlowProblem.hpp:1428
const DimMatrix & intrinsicPermeability(unsigned globalElemIdx) const
This method returns the intrinsic permeability tensor given a global element index.
Definition: FlowProblem.hpp:548
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:901
LhsEval wellTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1207
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:701
void beginIteration()
Called by the simulator before each Newton-Raphson iteration.
Definition: FlowProblem.hpp:418
GetPropType< TypeTag, Properties::Vanguard > Vanguard
Definition: FlowProblem.hpp:108
GetPropType< TypeTag, Properties::DofMapper > DofMapper
Definition: FlowProblem.hpp:159
Scalar rockBiotComp(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:745
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: FlowProblem.hpp:102
typename EclThermalLawManager::SolidEnergyLawParams SolidEnergyLawParams
Definition: FlowProblem.hpp:156
bool updateHysteresis_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1598
GetPropType< TypeTag, Properties::BaseProblem > ParentType
Definition: FlowProblem.hpp:99
GetPropType< TypeTag, Properties::EqVector > EqVector
Definition: FlowProblem.hpp:107
@ waterCompIdx
Definition: FlowProblem.hpp:146
unsigned satnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:909
virtual void handleOxygBC(const BCProp::BCFace &, RateVector &) const =0
virtual void updateExplicitQuantities_(int episodeIdx, int timeStepSize, bool first_step_after_restart)=0
virtual void handleUreaBC(const BCProp::BCFace &, RateVector &) const =0
Scalar thermalHalfTransmissibilityOut(const Context &context, unsigned faceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:656
bool first_step_
Definition: FlowProblem.hpp:1882
GetPropType< TypeTag, Properties::ElementContext > ElementContext
Definition: FlowProblem.hpp:152
const ThermalConductionLawParams & thermalConductionLawParams(unsigned globalSpaceIdx, unsigned) const
Definition: FlowProblem.hpp:976
@ gasCompIdx
Definition: FlowProblem.hpp:144
AquiferModel aquiferModel_
Definition: FlowProblem.hpp:1835
GlobalEqVector drift_
Definition: FlowProblem.hpp:1832
bool updateMinPressure_()
Definition: FlowProblem.hpp:1380
std::function< std::vector< double >(const FieldPropsManager &, const std::string &)> fieldPropDoubleOnLeafAssigner_()
Definition: FlowProblem.hpp:1413
@ enableSaltPrecipitation
Definition: FlowProblem.hpp:135
Scalar transmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:613
GetPropType< TypeTag, Properties::RateVector > RateVector
Definition: FlowProblem.hpp:149
void updateReferencePorosity_()
Definition: FlowProblem.hpp:1494
Scalar thermalHalfTransmissibility(const unsigned globalSpaceIdxIn, const unsigned globalSpaceIdxOut) const
Definition: FlowProblem.hpp:633
LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1790
BCData< int > bcindex_
Definition: FlowProblem.hpp:1880
GetPropType< TypeTag, Properties::TracerModel > TracerModel
Definition: FlowProblem.hpp:169
Scalar rockCompressibility(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:735
bool updateMaxWaterSaturation_()
Definition: FlowProblem.hpp:1349
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: FlowProblem.hpp:166
@ enableMICP
Definition: FlowProblem.hpp:134
void advanceTimeLevel()
Called by the simulator to accept the current state as the new time level after a successful timestep...
Definition: FlowProblem.hpp:410
Scalar maxOilSaturation(unsigned globalDofIdx) const
Returns an element's historic maximum oil phase saturation that was observed during the simulation.
Definition: FlowProblem.hpp:991
bool updateMinPressure_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1395
std::string name() const
The problem name.
Definition: FlowProblem.hpp:940
int episodeIndex() const
Definition: FlowProblem.hpp:299
LhsEval rockCompTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1185
void endIteration()
Called by the simulator after each Newton-Raphson iteration.
Definition: FlowProblem.hpp:428
GetPropType< TypeTag, Properties::Indices > Indices
Definition: FlowProblem.hpp:109
FlowProblem(Simulator &simulator)
Definition: FlowProblem.hpp:221
virtual void handleSolventBC(const BCProp::BCFace &, RateVector &) const =0
@ dim
Definition: FlowProblem.hpp:112
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: FlowProblem.hpp:106
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: FlowProblem.hpp:150
const Vanguard::TransmissibilityType & eclTransmissibilities() const
Return a reference to the object that handles the "raw" transmissibilities.
Definition: FlowProblem.hpp:679
void source(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:1061
@ dimWorld
Definition: FlowProblem.hpp:113
virtual void readEquilInitialCondition_()=0
Scalar nextTimeStepSize() const
Propose the size of the next time step to the simulator.
Definition: FlowProblem.hpp:1114
LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1775
std::pair< BCType, RateVector > boundaryCondition(const unsigned int globalSpaceIdx, const int directionId) const
Definition: FlowProblem.hpp:1219
typename EclMaterialLawManager::MaterialLawParams MaterialLawParams
Definition: FlowProblem.hpp:155
static constexpr bool enableDiffusion
Definition: FlowProblem.hpp:123
virtual ~FlowProblem()=default
PffGridVector< GridView, Stencil, PffDofData_, DofMapper > pffDofData_
Definition: FlowProblem.hpp:1837
const ThermalConductionLawParams & thermalConductionLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:841
Scalar transmissibility(const Context &context, unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:555
TracerModel tracerModel_
Definition: FlowProblem.hpp:1838
@ numComponents
Definition: FlowProblem.hpp:118
virtual void handlePolymerBC(const BCProp::BCFace &, RateVector &) const =0
const TracerModel & tracerModel() const
Definition: FlowProblem.hpp:683
WellModel wellModel_
Definition: FlowProblem.hpp:1834
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:307
const SolidEnergyLawParams & solidEnergyLawParams(unsigned globalSpaceIdx, unsigned) const
Definition: FlowProblem.hpp:970
static constexpr bool enablePolymerMolarWeight
Definition: FlowProblem.hpp:128
Scalar getRockCompTransMultVal(std::size_t dofIdx) const
Definition: FlowProblem.hpp:1606
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:366
@ enableFullyImplicitThermal
Definition: FlowProblem.hpp:132
Scalar dofCenterDepth(unsigned globalSpaceIdx) const
Direct indexed acces to the depth of an degree of freedom [m].
Definition: FlowProblem.hpp:726
typename GetProp< TypeTag, Properties::MaterialLaw >::EclMaterialLawManager EclMaterialLawManager
Definition: FlowProblem.hpp:153
static constexpr bool enableSolvent
Definition: FlowProblem.hpp:129
const MaterialLawParams & materialLawParams(unsigned globalDofIdx, FaceDir::DirEnum facedir) const
Definition: FlowProblem.hpp:818
std::shared_ptr< const EclMaterialLawManager > materialLawManager() const
Returns the ECL material law manager.
Definition: FlowProblem.hpp:853
unsigned plmixnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:925
const MaterialLawParams & materialLawParams(unsigned globalDofIdx) const
Definition: FlowProblem.hpp:813
Scalar temperature(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:947
Scalar thermalHalfTransmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:669
unsigned miscnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:917
void updateRockCompTransMultVal_()
Definition: FlowProblem.hpp:1757
std::shared_ptr< EclThermalLawManager > thermalLawManager_
Definition: FlowProblem.hpp:1830
Scalar limitNextTimeStepSize_(Scalar dtNext) const
Definition: FlowProblem.hpp:1699
@ waterPhaseIdx
Definition: FlowProblem.hpp:140
GetPropType< TypeTag, Properties::Stencil > Stencil
Definition: FlowProblem.hpp:104
typename GetProp< TypeTag, Properties::SolidEnergyLaw >::EclThermalLawManager EclThermalLawManager
Definition: FlowProblem.hpp:154
virtual void readExplicitInitialCondition_()=0
virtual void handleMicrBC(const BCProp::BCFace &, RateVector &) const =0
static constexpr bool enablePolymer
Definition: FlowProblem.hpp:127
GetPropType< TypeTag, Properties::WellModel > WellModel
Definition: FlowProblem.hpp:162
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:534
void updateFailed()
Called by the simulator to restore the state captured at the beginning of the timestep after a failed...
Definition: FlowProblem.hpp:401
bool updateHysteresis_()
Definition: FlowProblem.hpp:1582
void readThermalParameters_()
Definition: FlowProblem.hpp:1477
void serializeOp(Serializer &serializer)
Definition: FlowProblem.hpp:1274
Scalar maxPolymerAdsorption(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the max polymer adsorption value.
Definition: FlowProblem.hpp:934
Scalar thermalHalfTransmissibilityIn(const Context &context, unsigned faceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:643
void setMaxOilSaturation(unsigned globalDofIdx, Scalar value)
Sets an element's maximum oil phase saturation observed during the simulation.
Definition: FlowProblem.hpp:1008
const SolidEnergyLawParams & solidEnergyLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Return the parameters for the energy storage law of the rock.
Definition: FlowProblem.hpp:828
typename EclThermalLawManager::ThermalConductionLawParams ThermalConductionLawParams
Definition: FlowProblem.hpp:157
Scalar dispersivity(const unsigned globalCellIn, const unsigned globalCellOut) const
Definition: FlowProblem.hpp:593
AquiferModel & mutableAquiferModel()
Definition: FlowProblem.hpp:1102
GetPropType< TypeTag, Properties::IntensiveQuantities > IntensiveQuantities
Definition: FlowProblem.hpp:161
Scalar temperature(unsigned globalDofIdx, unsigned) const
Definition: FlowProblem.hpp:959
Scalar lame(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:755
@ oilCompIdx
Definition: FlowProblem.hpp:145
@ numPhases
Definition: FlowProblem.hpp:117
GetPropType< TypeTag, Properties::AquiferModel > AquiferModel
Definition: FlowProblem.hpp:163
TemperatureModel temperatureModel_
Definition: FlowProblem.hpp:1839
static constexpr bool enableExtbo
Definition: FlowProblem.hpp:125
std::shared_ptr< EclMaterialLawManager > materialLawManager_
Definition: FlowProblem.hpp:1829
WellModel & wellModel()
Definition: FlowProblem.hpp:1096
static constexpr bool enableConvectiveMixing
Definition: FlowProblem.hpp:122
GetPropType< TypeTag, Properties::GridView > GridView
Definition: FlowProblem.hpp:103
GetPropType< TypeTag, Properties::TemperatureModel > TemperatureModel
Definition: FlowProblem.hpp:168
void updateProperty_(const std::string &failureMsg, UpdateFunc func)
Definition: FlowProblem.hpp:1298
LhsEval rockCompTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1199
@ enableThermalFluxBoundaries
Definition: FlowProblem.hpp:136
bool updateMaxOilSaturation_()
Definition: FlowProblem.hpp:1317
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
virtual void endEpisode()
Called by the simulator after the end of an episode.
Definition: FlowProblem.hpp:495
@ enableExperiments
Definition: FlowProblem.hpp:133
GetPropType< TypeTag, Properties::PrimaryVariables > PrimaryVariables
Definition: FlowProblem.hpp:148
bool nonTrivialBoundaryConditions_
Definition: FlowProblem.hpp:1881
GetPropType< TypeTag, Properties::Problem > Implementation
Definition: FlowProblem.hpp:100
void readBoundaryConditions_()
Definition: FlowProblem.hpp:1656
void updateRelperms(std::array< Evaluation, numPhases > &mobility, DirectionalMobilityPtr &dirMob, FluidState &fluidState, unsigned globalSpaceIdx) const
Definition: FlowProblem.hpp:860
Vanguard::TransmissibilityType transmissibilities_
Definition: FlowProblem.hpp:1827
void source(RateVector &rate, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the source term for all phases within a given sub-control-volume.
Definition: FlowProblem.hpp:1052
virtual void addToSourceDense(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const =0
virtual void endTimeStep()
Called by the simulator after each time integration.
Definition: FlowProblem.hpp:438
TemperatureModel & temperatureModel()
Definition: FlowProblem.hpp:689
Utility::CopyablePtr< DirectionalMobility< TypeTag > > DirectionalMobilityPtr
Definition: FlowProblem.hpp:170
virtual void readInitialCondition_()
Definition: FlowProblem.hpp:1553
virtual void initialSolutionApplied()
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblem.hpp:1019
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:806
Scalar thermalTransmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:600
static constexpr EnergyModules energyModuleType
Definition: FlowProblem.hpp:131
Scalar diffusivity(const Context &context, unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:575
Scalar rockReferencePressure(unsigned globalSpaceIdx) const
Definition: FlowProblem.hpp:784
void deserialize(Restarter &res)
This method restores the complete state of the problem and its sub-objects from disk.
Definition: FlowProblem.hpp:273
Scalar biotCoeff(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:765
std::shared_ptr< EclMaterialLawManager > materialLawManager()
Definition: FlowProblem.hpp:893
std::shared_ptr< const EclThermalLawManager > thermalLawManager() const
Definition: FlowProblem.hpp:856
bool updateMaxWaterSaturation_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1366
typename GridView::template Codim< 0 >::Entity Element
Definition: FlowProblem.hpp:151
Scalar dofCenterDepth(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the depth of an degree of freedom [m].
Definition: FlowProblem.hpp:714
bool updateMaxOilSaturation_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1335
GetPropType< TypeTag, Properties::FluidSystem > FluidSystem
Definition: FlowProblem.hpp:105
GetPropType< TypeTag, Properties::MaterialLaw > MaterialLaw
Definition: FlowProblem.hpp:158
const AquiferModel & aquiferModel() const
Definition: FlowProblem.hpp:1099
@ oilPhaseIdx
Definition: FlowProblem.hpp:139
int refPressurePhaseIdx_() const
Definition: FlowProblem.hpp:1745
static constexpr bool enableBioeffects
Definition: FlowProblem.hpp:120
LhsEval rockCompPoroMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the porosity multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1141
Scalar transmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:623
TracerModel & tracerModel()
Definition: FlowProblem.hpp:686
void readMaterialParameters_()
Definition: FlowProblem.hpp:1437
static constexpr bool enableBrine
Definition: FlowProblem.hpp:121
void serialize(Restarter &res)
This method writes the complete state of the problem and its subobjects to disk.
Definition: FlowProblem.hpp:292
MathToolbox< Evaluation > Toolbox
Definition: FlowProblem.hpp:165
@ gasPhaseIdx
Definition: FlowProblem.hpp:138
Scalar rockReferencePressure(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:775
Scalar diffusivity(const unsigned globalCellIn, const unsigned globalCellOut) const
Definition: FlowProblem.hpp:586
@ numEq
Definition: FlowProblem.hpp:116
void updateRockFraction_()
Definition: FlowProblem.hpp:1519
void prefetch(const Element &elem) const
Definition: FlowProblem.hpp:258
A random-access container which stores data attached to a grid's degrees of freedom in a prefetch fri...
Definition: pffgridvector.hh:50
Definition: RelpermDiagnostics.hpp:51
void diagnosis(const EclipseState &eclState, const LevelCartesianIndexMapper &levelCartesianIndexMapper)
This file contains definitions related to directional mobilities.
@ NONE
Definition: DeferredLogger.hpp:46
int eclPositionalParameter(std::function< void(const std::string &, const std::string &)> addKey, std::set< std::string > &seenParams, std::string &errorMsg, const char **argv, int paramIdx)
Definition: blackoilbioeffectsmodules.hh:45
void eclBroadcast(Parallel::Communication, T &)
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
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property (equivalent to old macro GET_PROP(...))
Definition: propertysystem.hh:224
Definition: FlowProblem.hpp:1843
const std::vector< T > & operator()(FaceDir::DirEnum dir) const
Definition: FlowProblem.hpp:1852
void resize(std::size_t size, T defVal)
Definition: FlowProblem.hpp:1846
std::vector< T > & operator()(FaceDir::DirEnum dir)
Definition: FlowProblem.hpp:1864
std::array< std::vector< T >, 6 > data
Definition: FlowProblem.hpp:1844
Definition: FlowProblem.hpp:1616
ConditionalStorage< enableFullyImplicitThermal, Scalar > thermalHalfTransOut
Definition: FlowProblem.hpp:1618
ConditionalStorage< enableFullyImplicitThermal, Scalar > thermalHalfTransIn
Definition: FlowProblem.hpp:1617
ConditionalStorage< enableDiffusion, Scalar > diffusivity
Definition: FlowProblem.hpp:1619
ConditionalStorage< enableDispersion, Scalar > dispersivity
Definition: FlowProblem.hpp:1620
Scalar transmissibility
Definition: FlowProblem.hpp:1621