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:
173
176 std::string extraTrailerSummary() const
177 { return {}; }
183 using BaseType::lame;
186 using BaseType::porosity;
187
191 static void registerParameters()
192 {
193 ParentType::registerParameters();
194
195 registerFlowProblemParameters<Scalar>();
196 }
197
207 static int handlePositionalParameter(std::function<void(const std::string&,
208 const std::string&)> addKey,
209 std::set<std::string>& seenParams,
210 std::string& errorMsg,
211 int,
212 const char** argv,
213 int paramIdx,
214 int)
215 {
216 return detail::eclPositionalParameter(addKey,
217 seenParams,
218 errorMsg,
219 argv,
220 paramIdx);
221 }
222
226 explicit FlowProblem(Simulator& simulator)
227 : ParentType(simulator)
228 , BaseType(simulator.vanguard().eclState(),
229 simulator.vanguard().schedule(),
230 simulator.vanguard().gridView())
231 , transmissibilities_(simulator.vanguard().eclState(),
232 simulator.vanguard().gridView(),
233 simulator.vanguard().cartesianIndexMapper(),
234 simulator.vanguard().grid(),
235 simulator.vanguard().cellCentroids(),
236 (energyModuleType == EnergyModules::FullyImplicitThermal ||
237 energyModuleType == EnergyModules::SequentialImplicitThermal),
240 , wellModel_(simulator, this->iterationContext())
241 , aquiferModel_(simulator)
242 , pffDofData_(simulator.gridView(), this->elementMapper())
243 , tracerModel_(simulator)
244 , temperatureModel_(simulator)
245 {
246 if (! Parameters::Get<Parameters::CheckSatfuncConsistency>()) {
247 // User did not enable the "new" saturation function consistency
248 // check module. Run the original checker instead. This is a
249 // temporary measure.
250 RelpermDiagnostics relpermDiagnostics{};
251 relpermDiagnostics.diagnosis(simulator.vanguard().eclState(),
252 simulator.vanguard().levelCartesianIndexMapper());
253 }
254
255 if (energyModuleType == EnergyModules::SequentialImplicitThermal) {
256 this->enableDriftCompensationTemp_ = Parameters::Get<Parameters::EnableDriftCompensationTemp>();
257 }
258
259 }
260
261 virtual ~FlowProblem() = default;
262
263 void prefetch(const Element& elem) const
264 { this->pffDofData_.prefetch(elem); }
265
277 template <class Restarter>
278 void deserialize(Restarter& res)
279 {
280 // reload the current episode/report step from the deck
281 this->beginEpisode();
282
283 // deserialize the wells
284 wellModel_.deserialize(res);
285
286 // deserialize the aquifer
287 aquiferModel_.deserialize(res);
288 }
289
296 template <class Restarter>
297 void serialize(Restarter& res)
298 {
299 wellModel_.serialize(res);
300
301 aquiferModel_.serialize(res);
302 }
303
304 int episodeIndex() const
305 {
306 return std::max(this->simulator().episodeIndex(), 0);
307 }
308
312 virtual void beginEpisode()
313 {
314 OPM_TIMEBLOCK(beginEpisode);
315 // Proceed to the next report step
316 auto& simulator = this->simulator();
317 int episodeIdx = simulator.episodeIndex();
318 auto& eclState = simulator.vanguard().eclState();
319 const auto& schedule = simulator.vanguard().schedule();
320 const auto& events = schedule[episodeIdx].events();
321
322 if (episodeIdx >= 0 && events.hasEvent(ScheduleEvents::GEO_MODIFIER)) {
323 // bring the contents of the keywords to the current state of the SCHEDULE
324 // section.
325 //
326 // TODO (?): make grid topology changes possible (depending on what exactly
327 // has changed, the grid may need be re-created which has some serious
328 // implications on e.g., the solution of the simulation.)
329 const auto& miniDeck = schedule[episodeIdx].geo_keywords();
330 const auto& cc = simulator.vanguard().grid().comm();
331 eclState.apply_schedule_keywords( miniDeck );
332 eclBroadcast(cc, eclState.getTransMult() );
333
334 // Re-ordering in case of ALUGrid
335 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
336 return simulator.vanguard().gridEquilIdxToGridIdx(i);
337 };
338
339 // re-compute all quantities which may possibly be affected.
340 using TransUpdateQuantities = typename Vanguard::TransmissibilityType::TransUpdateQuantities;
341 transmissibilities_.update(true, TransUpdateQuantities::All, equilGridToGrid);
342 this->referencePorosity_[1] = this->referencePorosity_[0];
344 this->rockFraction_[1] = this->rockFraction_[0];
347 this->model().linearizer().updateDiscretizationParameters();
348 }
349
350 bool tuningEvent = this->beginEpisode_(enableExperiments, this->episodeIndex());
351
352 // set up the wells for the next episode.
353 wellModel_.beginEpisode();
354
355 // set up the aquifers for the next episode.
356 aquiferModel_.beginEpisode();
357
358 // set the size of the initial time step of the episode
359 Scalar dt = limitNextTimeStepSize_(simulator.episodeLength());
360 // negative value of initialTimeStepSize_ indicates no active limit from TSINIT or NEXTSTEP
361 if ( (episodeIdx == 0 || tuningEvent) && this->initialTimeStepSize_ > 0)
362 // allow the size of the initial time step to be set via an external parameter
363 // if TUNING is enabled, also limit the time step size after a tuning event to TSINIT
364 dt = std::min(dt, this->initialTimeStepSize_);
365 simulator.setTimeStepSize(dt);
366 }
367
371 virtual void beginTimeStep()
372 {
373 OPM_TIMEBLOCK(beginTimeStep);
374 const int episodeIdx = this->episodeIndex();
375 const int timeStepSize = this->simulator().timeStepSize();
376
378 episodeIdx,
379 this->simulator().timeStepIndex(),
380 this->simulator().startTime(),
381 this->simulator().time(),
382 timeStepSize,
383 this->simulator().endTime());
384
385 // update maximum water saturation and minimum pressure
386 // used when ROCKCOMP is activated
387 // Do not update max RS first step after a restart
388 this->updateExplicitQuantities_(episodeIdx, timeStepSize, first_step_ && (episodeIdx > 0));
389 first_step_ = false;
390
392 this->model().linearizer().updateBoundaryConditionData();
393 }
394
395 wellModel_.beginTimeStep();
396 aquiferModel_.beginTimeStep();
397 tracerModel_.beginTimeStep();
398 temperatureModel_.beginTimeStep();
399
400 }
401
407 {
408 this->model().updateFailed();
409 }
410
416 {
417 this->model().advanceTimeLevel();
418 }
419
424 {
425 OPM_TIMEBLOCK(beginIteration);
426 wellModel_.beginIteration();
427 aquiferModel_.beginIteration();
428 }
429
434 {
435 OPM_TIMEBLOCK(endIteration);
436 wellModel_.endIteration();
437 aquiferModel_.endIteration();
438 }
439
443 virtual void endTimeStep()
444 {
445 OPM_TIMEBLOCK(endTimeStep);
446
447#ifndef NDEBUG
448 if constexpr (getPropValue<TypeTag, Properties::EnableDebuggingChecks>()) {
449 // in debug mode, we don't care about performance, so we check
450 // if the model does the right thing (i.e., the mass change
451 // inside the whole reservoir must be equivalent to the fluxes
452 // over the grid's boundaries plus the source rates specified by
453 // the problem).
454 const int rank = this->simulator().gridView().comm().rank();
455 if (rank == 0) {
456 std::cout << "checking conservativeness of solution\n";
457 }
458
459 this->model().checkConservativeness(/*tolerance=*/-1, /*verbose=*/true);
460 if (rank == 0) {
461 std::cout << "solution is sufficiently conservative\n";
462 }
463 }
464#endif // NDEBUG
465
466 auto& simulator = this->simulator();
467 simulator.setTimeStepIndex(simulator.timeStepIndex()+1);
468
469 this->wellModel_.endTimeStep();
470 this->aquiferModel_.endTimeStep();
471 this->tracerModel_.endTimeStep();
472
473 // Compute flux for output
474 this->model().linearizer().updateFlowsInfo();
475
477 OPM_TIMEBLOCK(driftCompansation);
478
479 const auto& residual = this->model().linearizer().residual();
480
481 for (unsigned globalDofIdx = 0; globalDofIdx < residual.size(); globalDofIdx ++) {
482 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(globalDofIdx);
483 this->drift_[sfcdofIdx] = residual[sfcdofIdx] * simulator.timeStepSize();
484
485 if constexpr (getPropValue<TypeTag, Properties::UseVolumetricResidual>()) {
486 this->drift_[sfcdofIdx] *= this->model().dofTotalVolume(sfcdofIdx);
487 }
488 }
489 }
490
491 // Drift compensation needs to be updated before calling the temperature equation
492 if constexpr(energyModuleType == EnergyModules::SequentialImplicitThermal) {
493 this->temperatureModel_.endTimeStep(wellModel_.wellState());
494 }
495 }
496
500 virtual void endEpisode()
501 {
502 const int episodeIdx = this->episodeIndex();
503
504 this->wellModel_.endEpisode();
505 this->aquiferModel_.endEpisode();
506
507 const auto& schedule = this->simulator().vanguard().schedule();
508
509 // End simulation when completed.
510 if (episodeIdx + 1 >= static_cast<int>(schedule.size()) - 1) {
511 this->simulator().setFinished(true);
512 return;
513 }
514
515 // Otherwise, start next episode (report step).
516 this->simulator().startNextEpisode(schedule.stepLength(episodeIdx + 1));
517 }
518
523 virtual void writeOutput(bool verbose)
524 {
525 OPM_TIMEBLOCK(problemWriteOutput);
526
527 if (Parameters::Get<Parameters::EnableWriteAllSolutions>() ||
528 this->episodeWillBeOver())
529 {
530 // Create VTK output as needed.
531 ParentType::writeOutput(verbose);
532 }
533 }
534
538 template <class Context>
539 const DimMatrix& intrinsicPermeability(const Context& context,
540 unsigned spaceIdx,
541 unsigned timeIdx) const
542 {
543 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
544 return transmissibilities_.permeability(globalSpaceIdx);
545 }
546
553 const DimMatrix& intrinsicPermeability(unsigned globalElemIdx) const
554 { return transmissibilities_.permeability(globalElemIdx); }
555
559 template <class Context>
560 Scalar transmissibility(const Context& context,
561 [[maybe_unused]] unsigned fromDofLocalIdx,
562 unsigned toDofLocalIdx) const
563 {
564 assert(fromDofLocalIdx == 0);
565 return pffDofData_.get(context.element(), toDofLocalIdx).transmissibility;
566 }
567
571 Scalar transmissibility(unsigned globalCenterElemIdx, unsigned globalElemIdx) const
572 {
573 return transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
574 }
575
579 template <class Context>
580 Scalar diffusivity(const Context& context,
581 [[maybe_unused]] unsigned fromDofLocalIdx,
582 unsigned toDofLocalIdx) const
583 {
584 assert(fromDofLocalIdx == 0);
585 return *pffDofData_.get(context.element(), toDofLocalIdx).diffusivity;
586 }
587
591 Scalar diffusivity(const unsigned globalCellIn, const unsigned globalCellOut) const{
592 return transmissibilities_.diffusivity(globalCellIn, globalCellOut);
593 }
594
598 Scalar dispersivity(const unsigned globalCellIn, const unsigned globalCellOut) const{
599 return transmissibilities_.dispersivity(globalCellIn, globalCellOut);
600 }
601
605 Scalar thermalTransmissibilityBoundary(const unsigned globalSpaceIdx,
606 const unsigned boundaryFaceIdx) const
607 {
608 return transmissibilities_.thermalTransmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
609 }
610
611
612
613
617 template <class Context>
618 Scalar transmissibilityBoundary(const Context& elemCtx,
619 unsigned boundaryFaceIdx) const
620 {
621 unsigned elemIdx = elemCtx.globalSpaceIndex(/*dofIdx=*/0, /*timeIdx=*/0);
622 return transmissibilities_.transmissibilityBoundary(elemIdx, boundaryFaceIdx);
623 }
624
628 Scalar transmissibilityBoundary(const unsigned globalSpaceIdx,
629 const unsigned boundaryFaceIdx) const
630 {
631 return transmissibilities_.transmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
632 }
633
634
638 Scalar thermalHalfTransmissibility(const unsigned globalSpaceIdxIn,
639 const unsigned globalSpaceIdxOut) const
640 {
641 return transmissibilities_.thermalHalfTrans(globalSpaceIdxIn,globalSpaceIdxOut);
642 }
643
647 template <class Context>
648 Scalar thermalHalfTransmissibilityIn(const Context& context,
649 unsigned faceIdx,
650 unsigned timeIdx) const
651 {
652 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
653 unsigned toDofLocalIdx = face.exteriorIndex();
654 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransIn;
655 }
656
660 template <class Context>
662 unsigned faceIdx,
663 unsigned timeIdx) const
664 {
665 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
666 unsigned toDofLocalIdx = face.exteriorIndex();
667 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransOut;
668 }
669
673 template <class Context>
675 unsigned boundaryFaceIdx) const
676 {
677 unsigned elemIdx = elemCtx.globalSpaceIndex(/*dofIdx=*/0, /*timeIdx=*/0);
678 return transmissibilities_.thermalHalfTransBoundary(elemIdx, boundaryFaceIdx);
679 }
680
684 const typename Vanguard::TransmissibilityType& eclTransmissibilities() const
685 { return transmissibilities_; }
686
687
689 { return tracerModel_; }
690
692 { return tracerModel_; }
693
694 TemperatureModel& temperatureModel() // need for restart
695 { return temperatureModel_; }
696
705 template <class Context>
706 Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
707 {
708 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
709 return this->porosity(globalSpaceIdx, timeIdx);
710 }
711
718 template <class Context>
719 Scalar dofCenterDepth(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
720 {
721 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
722 return this->dofCenterDepth(globalSpaceIdx);
723 }
724
731 Scalar dofCenterDepth(unsigned globalSpaceIdx) const
732 {
733 return this->simulator().vanguard().cellCenterDepth(globalSpaceIdx);
734 }
735
739 template <class Context>
740 Scalar rockCompressibility(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
741 {
742 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
743 return this->rockCompressibility(globalSpaceIdx);
744 }
745
749 template <class Context>
750 Scalar rockBiotComp(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
751 {
752 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
753 return this->rockBiotComp(globalSpaceIdx);
754 }
755
759 template <class Context>
760 Scalar lame(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
761 {
762 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
763 return this->lame(globalSpaceIdx);
764 }
765
769 template <class Context>
770 Scalar biotCoeff(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
771 {
772 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
773 return this->biotCoeff(globalSpaceIdx);
774 }
775
779 template <class Context>
780 Scalar rockReferencePressure(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
781 {
782 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
783 return rockReferencePressure(globalSpaceIdx);
784 }
785
789 Scalar rockReferencePressure(unsigned globalSpaceIdx) const
790 {
791 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
792 if (rock_config.store()) {
793 return asImp_().initialFluidState(globalSpaceIdx).pressure(refPressurePhaseIdx_());
794 }
795 else {
796 if (this->rockParams_.empty())
797 return 1e5;
798
799 unsigned tableIdx = 0;
800 if (!this->rockTableIdx_.empty()) {
801 tableIdx = this->rockTableIdx_[globalSpaceIdx];
802 }
803 return this->rockParams_[tableIdx].referencePressure;
804 }
805 }
806
810 template <class Context>
811 const MaterialLawParams& materialLawParams(const Context& context,
812 unsigned spaceIdx, unsigned timeIdx) const
813 {
814 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
815 return this->materialLawParams(globalSpaceIdx);
816 }
817
818 const MaterialLawParams& materialLawParams(unsigned globalDofIdx) const
819 {
820 return materialLawManager_->materialLawParams(globalDofIdx);
821 }
822
823 const MaterialLawParams& materialLawParams(unsigned globalDofIdx, FaceDir::DirEnum facedir) const
824 {
825 return materialLawManager_->materialLawParams(globalDofIdx, facedir);
826 }
827
831 template <class Context>
833 solidEnergyLawParams(const Context& context,
834 unsigned spaceIdx,
835 unsigned timeIdx) const
836 {
837 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
838 return thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
839 }
840
844 template <class Context>
846 thermalConductionLawParams(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
847 {
848 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
849 return thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
850 }
851
858 std::shared_ptr<const EclMaterialLawManager> materialLawManager() const
859 { return materialLawManager_; }
860
861 std::shared_ptr<const EclThermalLawManager> thermalLawManager() const
862 { return thermalLawManager_; }
863
864 template <class FluidState, class ...Args>
866 std::array<Evaluation,numPhases> &mobility,
868 FluidState &fluidState,
869 unsigned globalSpaceIdx) const
870 {
871 using ContainerT = std::array<Evaluation, numPhases>;
872 OPM_TIMEBLOCK_LOCAL(updateRelperms, Subsystem::SatProps);
873 {
874 // calculate relative permeabilities. note that we store the result into the
875 // mobility_ class attribute. the division by the phase viscosity happens later.
876 const auto& materialParams = materialLawParams(globalSpaceIdx);
877 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mobility, materialParams, fluidState);
878 Valgrind::CheckDefined(mobility);
879 }
880 if (materialLawManager_->hasDirectionalRelperms()
881 || materialLawManager_->hasDirectionalImbnum())
882 {
883 using Dir = FaceDir::DirEnum;
884 constexpr int ndim = 3;
885 dirMob = std::make_unique<DirectionalMobility<TypeTag>>();
886 Dir facedirs[ndim] = {Dir::XPlus, Dir::YPlus, Dir::ZPlus};
887 for (int i = 0; i<ndim; i++) {
888 const auto& materialParams = materialLawParams(globalSpaceIdx, facedirs[i]);
889 auto& mob_array = dirMob->getArray(i);
890 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mob_array, materialParams, fluidState);
891 }
892 }
893 }
894
898 std::shared_ptr<EclMaterialLawManager> materialLawManager()
899 { return materialLawManager_; }
900
905 template <class Context>
906 unsigned pvtRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
907 { return pvtRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
908
913 template <class Context>
914 unsigned satnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
915 { return this->satnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
916
921 template <class Context>
922 unsigned miscnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
923 { return this->miscnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
924
929 template <class Context>
930 unsigned plmixnumRegionIndex(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
931 { return this->plmixnumRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
932
933 // TODO: polymer related might need to go to the blackoil side
938 template <class Context>
939 Scalar maxPolymerAdsorption(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
940 { return this->maxPolymerAdsorption(context.globalSpaceIndex(spaceIdx, timeIdx)); }
941
945 std::string name() const
946 { return this->simulator().vanguard().caseName(); }
947
951 template <class Context>
952 Scalar temperature(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
953 {
954 // use the initial temperature of the DOF if temperature is not a primary
955 // variable
956 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
957 if constexpr (energyModuleType == EnergyModules::SequentialImplicitThermal)
958 return temperatureModel_.temperature(globalDofIdx);
959
960 return asImp_().initialFluidState(globalDofIdx).temperature(/*phaseIdx=*/0);
961 }
962
963
964 Scalar temperature(unsigned globalDofIdx, unsigned /*timeIdx*/) const
965 {
966 // use the initial temperature of the DOF if temperature is not a primary
967 // variable
968 if constexpr (energyModuleType == EnergyModules::SequentialImplicitThermal)
969 return temperatureModel_.temperature(globalDofIdx);
970
971 return asImp_().initialFluidState(globalDofIdx).temperature(/*phaseIdx=*/0);
972 }
973
975 solidEnergyLawParams(unsigned globalSpaceIdx,
976 unsigned /*timeIdx*/) const
977 {
978 return this->thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
979 }
981 thermalConductionLawParams(unsigned globalSpaceIdx,
982 unsigned /*timeIdx*/)const
983 {
984 return this->thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
985 }
986
996 Scalar maxOilSaturation(unsigned globalDofIdx) const
997 {
998 if (!this->vapparsActive(this->episodeIndex()))
999 return 0.0;
1000
1001 return this->maxOilSaturation_[globalDofIdx];
1002 }
1003
1013 void setMaxOilSaturation(unsigned globalDofIdx, Scalar value)
1014 {
1015 if (!this->vapparsActive(this->episodeIndex()))
1016 return;
1017
1018 this->maxOilSaturation_[globalDofIdx] = value;
1019 }
1020
1025 {
1026 // Calculate all intensive quantities.
1027 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx*/0);
1028
1029 // We also need the intensive quantities for timeIdx == 1
1030 // corresponding to the start of the current timestep, if we
1031 // do not use the storage cache, or if we cannot recycle the
1032 // first iteration storage.
1033 if (!this->model().enableStorageCache() || !this->recycleFirstIterationStorage()) {
1034 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx*/1);
1035 }
1036
1037 // initialize the wells. Note that this needs to be done after initializing the
1038 // intrinsic permeabilities and the after applying the initial solution because
1039 // the well model uses these...
1040 wellModel_.init();
1041
1042 aquiferModel_.initialSolutionApplied();
1043
1044 const bool invalidateFromHyst = updateHysteresis_();
1045 if (invalidateFromHyst) {
1046 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1047 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1048 }
1049 }
1050
1056 template <class Context>
1057 void source(RateVector& rate,
1058 const Context& context,
1059 unsigned spaceIdx,
1060 unsigned timeIdx) const
1061 {
1062 const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
1063 source(rate, globalDofIdx, timeIdx);
1064 }
1065
1066 void source(RateVector& rate,
1067 unsigned globalDofIdx,
1068 unsigned timeIdx) const
1069 {
1070 OPM_TIMEBLOCK_LOCAL(eclProblemSource, Subsystem::Assembly);
1071 rate = 0.0;
1072
1073 // Add well contribution to source here.
1074 wellModel_.computeTotalRatesForDof(rate, globalDofIdx);
1075
1076 // convert the source term from the total mass rate of the
1077 // cell to the one per unit of volume as used by the model.
1078 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
1079 rate[eqIdx] /= this->model().dofTotalVolume(globalDofIdx);
1080
1081 Valgrind::CheckDefined(rate[eqIdx]);
1082 assert(isfinite(rate[eqIdx]));
1083 }
1084
1085 // Add non-well sources.
1086 addToSourceDense(rate, globalDofIdx, timeIdx);
1087 }
1088
1089 virtual void addToSourceDense(RateVector& rate,
1090 unsigned globalDofIdx,
1091 unsigned timeIdx) const = 0;
1092
1098 const WellModel& wellModel() const
1099 { return wellModel_; }
1100
1102 { return wellModel_; }
1103
1105 { return aquiferModel_; }
1106
1108 { return aquiferModel_; }
1109
1112
1120 {
1121 OPM_TIMEBLOCK(nexTimeStepSize);
1122 // allow external code to do the timestepping
1123 if (this->nextTimeStepSize_ > 0.0)
1124 return this->nextTimeStepSize_;
1125
1126 const auto& simulator = this->simulator();
1127 int episodeIdx = simulator.episodeIndex();
1128
1129 // for the initial episode, we use a fixed time step size
1130 if (episodeIdx < 0)
1131 return this->initialTimeStepSize_;
1132
1133 // ask the newton method for a suggestion. This suggestion will be based on how
1134 // well the previous time step converged. After that, apply the runtime time
1135 // stepping constraints.
1136 const auto& newtonMethod = this->model().newtonMethod();
1137 return limitNextTimeStepSize_(newtonMethod.suggestTimeStepSize(simulator.timeStepSize()));
1138 }
1139
1145 template <class LhsEval>
1146 LhsEval rockCompPoroMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1147 {
1148 OPM_TIMEBLOCK_LOCAL(rockCompPoroMultiplier, Subsystem::PvtProps);
1149 if (this->rockCompPoroMult_.empty() && this->rockCompPoroMultWc_.empty())
1150 return 1.0;
1151
1152 unsigned tableIdx = 0;
1153 if (!this->rockTableIdx_.empty())
1154 tableIdx = this->rockTableIdx_[elementIdx];
1155
1156 const auto& fs = intQuants.fluidState();
1157 LhsEval effectivePressure = decay<LhsEval>(fs.pressure(refPressurePhaseIdx_()));
1158 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1159 if (!this->minRefPressure_.empty())
1160 // The pore space change is irreversible
1161 effectivePressure =
1162 min(decay<LhsEval>(fs.pressure(refPressurePhaseIdx_())),
1163 this->minRefPressure_[elementIdx]);
1164
1165 if (!this->overburdenPressure_.empty())
1166 effectivePressure -= this->overburdenPressure_[elementIdx];
1167
1168 if (rock_config.store()) {
1169 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1170 }
1171
1172 if (!this->rockCompPoroMult_.empty()) {
1173 return this->rockCompPoroMult_[tableIdx].eval(effectivePressure, /*extrapolation=*/true);
1174 }
1175
1176 // water compaction
1177 assert(!this->rockCompPoroMultWc_.empty());
1178 LhsEval SwMax = max(decay<LhsEval>(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1179 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1180
1181 return this->rockCompPoroMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax, /*extrapolation=*/true);
1182 }
1183
1189 template <class LhsEval>
1190 LhsEval rockCompTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1191 {
1192 auto obtain = [](const auto& value)
1193 {
1194 if constexpr (std::is_same_v<LhsEval, Scalar>) {
1195 return getValue(value);
1196 } else {
1197 return value;
1198 }
1199 };
1200 return rockCompTransMultiplier<LhsEval>(intQuants, elementIdx, obtain);
1201 }
1202
1203 template <class LhsEval, class Callback>
1204 LhsEval rockCompTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1205 {
1206 const bool implicit = !this->explicitRockCompaction_;
1207 return implicit ? this->simulator().problem().template computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain)
1208 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1209 }
1210
1211 template <class LhsEval, class Callback>
1212 LhsEval wellTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1213 {
1214 OPM_TIMEBLOCK_LOCAL(wellTransMultiplier, Subsystem::Wells);
1215
1216 const bool implicit = !this->explicitRockCompaction_;
1217 LhsEval trans_mult = implicit ? this->simulator().problem().template computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain)
1218 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1219 trans_mult *= this->simulator().problem().template permFactTransMultiplier<LhsEval>(intQuants, elementIdx, obtain);
1220
1221 return trans_mult;
1222 }
1223
1224 std::pair<BCType, RateVector> boundaryCondition(const unsigned int globalSpaceIdx, const int directionId) const
1225 {
1226 OPM_TIMEBLOCK_LOCAL(boundaryCondition, Subsystem::Assembly);
1228 return { BCType::NONE, RateVector(0.0) };
1229 }
1230 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
1231 const auto& schedule = this->simulator().vanguard().schedule();
1232 if (bcindex_(dir)[globalSpaceIdx] == 0) {
1233 return { BCType::NONE, RateVector(0.0) };
1234 }
1235 if (schedule[this->episodeIndex()].bcprop.size() == 0) {
1236 return { BCType::NONE, RateVector(0.0) };
1237 }
1238 const auto& bc = schedule[this->episodeIndex()].bcprop[bcindex_(dir)[globalSpaceIdx]];
1239 if (bc.bctype!=BCType::RATE) {
1240 return { bc.bctype, RateVector(0.0) };
1241 }
1242
1243 RateVector rate = 0.0;
1244 switch (bc.component) {
1245 case BCComponent::OIL:
1246 rate[FluidSystem::canonicalToActiveCompIdx(oilCompIdx)] = bc.rate;
1247 break;
1248 case BCComponent::GAS:
1249 rate[FluidSystem::canonicalToActiveCompIdx(gasCompIdx)] = bc.rate;
1250 break;
1251 case BCComponent::WATER:
1252 rate[FluidSystem::canonicalToActiveCompIdx(waterCompIdx)] = bc.rate;
1253 break;
1254 case BCComponent::SOLVENT:
1255 this->handleSolventBC(bc, rate);
1256 break;
1257 case BCComponent::POLYMER:
1258 this->handlePolymerBC(bc, rate);
1259 break;
1260 case BCComponent::MICR:
1261 this->handleMicrBC(bc, rate);
1262 break;
1263 case BCComponent::OXYG:
1264 this->handleOxygBC(bc, rate);
1265 break;
1266 case BCComponent::UREA:
1267 this->handleUreaBC(bc, rate);
1268 break;
1269 case BCComponent::NONE:
1270 throw std::logic_error("you need to specify the component when RATE type is set in BC");
1271 break;
1272 }
1273 //TODO add support for enthalpy rate
1274 return {bc.bctype, rate};
1275 }
1276
1277
1278 template<class Serializer>
1279 void serializeOp(Serializer& serializer)
1280 {
1281 serializer(static_cast<BaseType&>(*this));
1282 serializer(drift_);
1283 serializer(wellModel_);
1284 serializer(aquiferModel_);
1285 serializer(tracerModel_);
1286 serializer(*materialLawManager_);
1287 }
1288
1289 const GlobalEqVector& drift() const
1290 {
1291 return drift_;
1292 }
1293
1294private:
1295 Implementation& asImp_()
1296 { return *static_cast<Implementation *>(this); }
1297
1298 const Implementation& asImp_() const
1299 { return *static_cast<const Implementation *>(this); }
1300
1301protected:
1302 template<class UpdateFunc>
1303 void updateProperty_(const std::string& failureMsg,
1304 UpdateFunc func)
1305 {
1306 OPM_TIMEBLOCK(updateProperty);
1307 const auto& model = this->simulator().model();
1308 const auto& primaryVars = model.solution(/*timeIdx*/0);
1309 const auto& vanguard = this->simulator().vanguard();
1310 std::size_t numGridDof = primaryVars.size();
1312#ifdef _OPENMP
1313#pragma omp parallel for
1314#endif
1315 for (unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
1316 const auto& iq = *model.cachedIntensiveQuantities(dofIdx, /*timeIdx=*/ 0);
1317 func(dofIdx, iq);
1318 }
1319 OPM_END_PARALLEL_TRY_CATCH(failureMsg, vanguard.grid().comm());
1320 }
1321
1323 {
1324 OPM_TIMEBLOCK(updateMaxOilSaturation);
1325 int episodeIdx = this->episodeIndex();
1326
1327 // we use VAPPARS
1328 if (this->vapparsActive(episodeIdx)) {
1329 this->updateProperty_("FlowProblem::updateMaxOilSaturation_() failed:",
1330 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1331 {
1332 this->updateMaxOilSaturation_(compressedDofIdx,iq);
1333 });
1334 return true;
1335 }
1336
1337 return false;
1338 }
1339
1340 bool updateMaxOilSaturation_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1341 {
1342 OPM_TIMEBLOCK_LOCAL(updateMaxOilSaturation, Subsystem::SatProps);
1343 const auto& fs = iq.fluidState();
1344 const Scalar So = decay<Scalar>(fs.saturation(refPressurePhaseIdx_()));
1345 auto& mos = this->maxOilSaturation_;
1346 if(mos[compressedDofIdx] < So){
1347 mos[compressedDofIdx] = So;
1348 return true;
1349 }else{
1350 return false;
1351 }
1352 }
1353
1355 {
1356 OPM_TIMEBLOCK(updateMaxWaterSaturation);
1357 // water compaction is activated in ROCKCOMP
1358 if (this->maxWaterSaturation_.empty())
1359 return false;
1360
1361 this->updateProperty_("FlowProblem::updateMaxWaterSaturation_() failed:",
1362 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1363 {
1364 this->updateMaxWaterSaturation_(compressedDofIdx,iq);
1365 });
1366 return true;
1367 }
1368
1369
1370 bool updateMaxWaterSaturation_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1371 {
1372 OPM_TIMEBLOCK_LOCAL(updateMaxWaterSaturation, Subsystem::SatProps);
1373 const auto& fs = iq.fluidState();
1374 const Scalar Sw = decay<Scalar>(fs.saturation(waterPhaseIdx));
1375 auto& mow = this->maxWaterSaturation_;
1376 if(mow[compressedDofIdx]< Sw){
1377 mow[compressedDofIdx] = Sw;
1378 return true;
1379 }else{
1380 return false;
1381 }
1382 }
1383
1385 {
1386 OPM_TIMEBLOCK(updateMinPressure);
1387 // IRREVERS option is used in ROCKCOMP
1388 if (this->minRefPressure_.empty())
1389 return false;
1390
1391 this->updateProperty_("FlowProblem::updateMinPressure_() failed:",
1392 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1393 {
1394 this->updateMinPressure_(compressedDofIdx,iq);
1395 });
1396 return true;
1397 }
1398
1399 bool updateMinPressure_(unsigned compressedDofIdx, const IntensiveQuantities& iq){
1400 OPM_TIMEBLOCK_LOCAL(updateMinPressure, Subsystem::PvtProps);
1401 const auto& fs = iq.fluidState();
1402 const Scalar min_pressure = getValue(fs.pressure(refPressurePhaseIdx_()));
1403 auto& min_pressures = this->minRefPressure_;
1404 if(min_pressures[compressedDofIdx]> min_pressure){
1405 min_pressures[compressedDofIdx] = min_pressure;
1406 return true;
1407 }else{
1408 return false;
1409 }
1410 }
1411
1412 // \brief Function to assign field properties of type double, on the leaf grid view.
1413 //
1414 // For CpGrid with local grid refinement, the field property of a cell on the leaf
1415 // is inherited from its parent or equivalent (when has no parent) cell on level zero.
1416 std::function<std::vector<double>(const FieldPropsManager&, const std::string&)>
1418 {
1419 const auto& lookup = this->lookUpData_;
1420 return [&lookup](const FieldPropsManager& fieldPropManager, const std::string& propString)
1421 {
1422 return lookup.assignFieldPropsDoubleOnLeaf(fieldPropManager, propString);
1423 };
1424 }
1425
1426 // \brief Function to assign field properties of type int, unsigned int, ..., on the leaf grid view.
1427 //
1428 // For CpGrid with local grid refinement, the field property of a cell on the leaf
1429 // is inherited from its parent or equivalent (when has no parent) cell on level zero.
1430 template<typename IntType>
1431 std::function<std::vector<IntType>(const FieldPropsManager&, const std::string&, bool)>
1433 {
1434 const auto& lookup = this->lookUpData_;
1435 return [&lookup](const FieldPropsManager& fieldPropManager, const std::string& propString, bool needsTranslation)
1436 {
1437 return lookup.template assignFieldPropsIntOnLeaf<IntType>(fieldPropManager, propString, needsTranslation);
1438 };
1439 }
1440
1442 {
1443 OPM_TIMEBLOCK(readMaterialParameters);
1444 const auto& simulator = this->simulator();
1445 const auto& vanguard = simulator.vanguard();
1446 const auto& eclState = vanguard.eclState();
1447
1448 // the PVT and saturation region numbers
1450 this->updatePvtnum_();
1451 this->updateSatnum_();
1452
1453 // the MISC region numbers (solvent model)
1454 this->updateMiscnum_();
1455 // the PLMIX region numbers (polymer model)
1456 this->updatePlmixnum_();
1457
1458 OPM_END_PARALLEL_TRY_CATCH("Invalid region numbers: ", vanguard.gridView().comm());
1460 // porosity
1462 this->referencePorosity_[1] = this->referencePorosity_[0];
1464
1466 // rock fraction
1468 this->rockFraction_[1] = this->rockFraction_[0];
1470
1472 // fluid-matrix interactions (saturation functions; relperm/capillary pressure)
1473 materialLawManager_ = std::make_shared<EclMaterialLawManager>();
1474 materialLawManager_->initFromState(eclState);
1475 materialLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1476 this-> template fieldPropIntTypeOnLeafAssigner_<int>(),
1479 }
1480
1482 {
1483 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal ||
1484 energyModuleType == EnergyModules::SequentialImplicitThermal )
1485 {
1486 const auto& simulator = this->simulator();
1487 const auto& vanguard = simulator.vanguard();
1488 const auto& eclState = vanguard.eclState();
1489
1490 // fluid-matrix interactions (saturation functions; relperm/capillary pressure)
1491 thermalLawManager_ = std::make_shared<EclThermalLawManager>();
1492 thermalLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1494 this-> template fieldPropIntTypeOnLeafAssigner_<unsigned int>());
1495 }
1496 }
1497
1499 {
1500 const auto& simulator = this->simulator();
1501 const auto& vanguard = simulator.vanguard();
1502 const auto& eclState = vanguard.eclState();
1503
1504 std::size_t numDof = this->model().numGridDof();
1505
1506 this->referencePorosity_[/*timeIdx=*/0].resize(numDof);
1507
1508 const auto& fp = eclState.fieldProps();
1509 const std::vector<double> porvData = this -> fieldPropDoubleOnLeafAssigner_()(fp, "PORV");
1510 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1511 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(dofIdx);
1512 Scalar poreVolume = porvData[dofIdx];
1513
1514 // we define the porosity as the accumulated pore volume divided by the
1515 // geometric volume of the element. Note that -- in pathetic cases -- it can
1516 // be larger than 1.0!
1517 Scalar dofVolume = simulator.model().dofTotalVolume(sfcdofIdx);
1518 assert(dofVolume > 0.0);
1519 this->referencePorosity_[/*timeIdx=*/0][sfcdofIdx] = poreVolume/dofVolume;
1520 }
1521 }
1522
1524
1525 const bool solveEnergyEquation = (energyModuleType == EnergyModules::FullyImplicitThermal ||
1526 energyModuleType == EnergyModules::SequentialImplicitThermal);
1527 if (!solveEnergyEquation)
1528 return;
1529
1530 const auto& simulator = this->simulator();
1531 const auto& vanguard = simulator.vanguard();
1532 const auto& eclState = vanguard.eclState();
1533
1534 std::size_t numDof = this->model().numGridDof();
1535 this->rockFraction_[/*timeIdx=*/0].resize(numDof);
1536 // For the energy equation, we need the volume of the rock.
1537 // The volume of the rock is computed by rockFraction * geometric volume of the element.
1538 // The reference porosity is defined as porosity * ntg * pore-volume-multiplier.
1539 // A common practice in reservoir simulation is to use large pore-volume-multipliers in boundary cells
1540 // to model boundary conditions other than no-flow. This may result in reference porosities that are larger than 1.
1541 // A simple (1-reference porosity) * geometric volume of the element may give unphysical results.
1542 // We therefore instead consider the pore-volume-multiplier as a volume multiplier. The rock fraction is thus given by
1543 // (1 - porosity * ntg) * pore-volume-multiplier = (1 - porosity * ntg) * reference porosity / (porosity * ntg)
1544 const auto& fp = eclState.fieldProps();
1545 const std::vector<double> poroData = this->fieldPropDoubleOnLeafAssigner_()(fp, "PORO");
1546 const std::vector<double> ntgData = this->fieldPropDoubleOnLeafAssigner_()(fp, "NTG");
1547
1548 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1549 const auto ntg = ntgData[dofIdx];
1550 const auto poro_eff = ntg * poroData[dofIdx];
1551 const int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(dofIdx);
1552 const auto rock_fraction = (1 - poro_eff) * this->referencePorosity_[/*timeIdx=*/0][sfcdofIdx] / poro_eff;
1553 this->rockFraction_[/*timeIdx=*/0][sfcdofIdx] = rock_fraction;
1554 }
1555 }
1556
1558 {
1559 // TODO: whether we should move this to FlowProblemBlackoil
1560 const auto& simulator = this->simulator();
1561 const auto& vanguard = simulator.vanguard();
1562 const auto& eclState = vanguard.eclState();
1563
1564 if (eclState.getInitConfig().hasEquil())
1566 else
1568
1569 //initialize min/max values
1570 std::size_t numElems = this->model().numGridDof();
1571 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1572 const auto& fs = asImp_().initialFluidStates()[elemIdx];
1573 if (!this->maxWaterSaturation_.empty() && waterPhaseIdx > -1)
1574 this->maxWaterSaturation_[elemIdx] = std::max(this->maxWaterSaturation_[elemIdx], fs.saturation(waterPhaseIdx));
1575 if (!this->maxOilSaturation_.empty() && oilPhaseIdx > -1)
1576 this->maxOilSaturation_[elemIdx] = std::max(this->maxOilSaturation_[elemIdx], fs.saturation(oilPhaseIdx));
1577 if (!this->minRefPressure_.empty() && refPressurePhaseIdx_() > -1)
1578 this->minRefPressure_[elemIdx] = std::min(this->minRefPressure_[elemIdx], fs.pressure(refPressurePhaseIdx_()));
1579 }
1580 }
1581
1582 virtual void readEquilInitialCondition_() = 0;
1584
1585 // update the hysteresis parameters of the material laws for the whole grid
1587 {
1588 if (!materialLawManager_->enableHysteresis())
1589 return false;
1590
1591 // we need to update the hysteresis data for _all_ elements (i.e., not just the
1592 // interior ones) to avoid desynchronization of the processes in the parallel case!
1593 this->updateProperty_("FlowProblem::updateHysteresis_() failed:",
1594 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1595 {
1596 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1597 });
1598 return true;
1599 }
1600
1601
1602 bool updateHysteresis_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1603 {
1604 OPM_TIMEBLOCK_LOCAL(updateHysteresis_, Subsystem::SatProps);
1605 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1606 //TODO change materials to give a bool
1607 return true;
1608 }
1609
1610 Scalar getRockCompTransMultVal(std::size_t dofIdx) const
1611 {
1612 if (this->rockCompTransMultVal_.empty())
1613 return 1.0;
1614
1615 return this->rockCompTransMultVal_[dofIdx];
1616 }
1617
1618protected:
1620 {
1621 ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransIn;
1622 ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransOut;
1623 ConditionalStorage<enableDiffusion, Scalar> diffusivity;
1624 ConditionalStorage<enableDispersion, Scalar> dispersivity;
1626 };
1627
1628 // update the prefetch friendly data object
1630 {
1631 const auto& distFn =
1632 [this](PffDofData_& dofData,
1633 const Stencil& stencil,
1634 unsigned localDofIdx)
1635 -> void
1636 {
1637 const auto& elementMapper = this->model().elementMapper();
1638
1639 unsigned globalElemIdx = elementMapper.index(stencil.entity(localDofIdx));
1640 if (localDofIdx != 0) {
1641 unsigned globalCenterElemIdx = elementMapper.index(stencil.entity(/*dofIdx=*/0));
1642 dofData.transmissibility = transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
1643
1644 if constexpr (enableFullyImplicitThermal) {
1645 *dofData.thermalHalfTransIn = transmissibilities_.thermalHalfTrans(globalCenterElemIdx, globalElemIdx);
1646 *dofData.thermalHalfTransOut = transmissibilities_.thermalHalfTrans(globalElemIdx, globalCenterElemIdx);
1647 }
1648 if constexpr (enableDiffusion)
1649 *dofData.diffusivity = transmissibilities_.diffusivity(globalCenterElemIdx, globalElemIdx);
1650 if (enableDispersion)
1651 dofData.dispersivity = transmissibilities_.dispersivity(globalCenterElemIdx, globalElemIdx);
1652 }
1653 };
1654
1655 pffDofData_.update(distFn);
1656 }
1657
1658 virtual void updateExplicitQuantities_(int episodeIdx, int timeStepSize, bool first_step_after_restart) = 0;
1659
1661 {
1662 const auto& simulator = this->simulator();
1663 const auto& vanguard = simulator.vanguard();
1664 const auto& bcconfig = vanguard.eclState().getSimulationConfig().bcconfig();
1665 if (bcconfig.size() > 0) {
1667
1668 std::size_t numCartDof = vanguard.cartesianSize();
1669 unsigned numElems = vanguard.gridView().size(/*codim=*/0);
1670 std::vector<int> cartesianToCompressedElemIdx(numCartDof, -1);
1671
1672 for (unsigned elemIdx = 0; elemIdx < numElems; ++elemIdx)
1673 cartesianToCompressedElemIdx[vanguard.cartesianIndex(elemIdx)] = elemIdx;
1674
1675 bcindex_.resize(numElems, 0);
1676 auto loopAndApply = [&cartesianToCompressedElemIdx,
1677 &vanguard](const auto& bcface,
1678 auto apply)
1679 {
1680 for (int i = bcface.i1; i <= bcface.i2; ++i) {
1681 for (int j = bcface.j1; j <= bcface.j2; ++j) {
1682 for (int k = bcface.k1; k <= bcface.k2; ++k) {
1683 std::array<int, 3> tmp = {i,j,k};
1684 auto elemIdx = cartesianToCompressedElemIdx[vanguard.cartesianIndex(tmp)];
1685 if (elemIdx >= 0)
1686 apply(elemIdx);
1687 }
1688 }
1689 }
1690 };
1691 for (const auto& bcface : bcconfig) {
1692 std::vector<int>& data = bcindex_(bcface.dir);
1693 const int index = bcface.index;
1694 loopAndApply(bcface,
1695 [&data,index](int elemIdx)
1696 { data[elemIdx] = index; });
1697 }
1698 }
1699 }
1700
1701 // this method applies the runtime constraints specified via the deck and/or command
1702 // line parameters for the size of the next time step.
1704 {
1705 if constexpr (enableExperiments) {
1706 const auto& simulator = this->simulator();
1707 const auto& schedule = simulator.vanguard().schedule();
1708 int episodeIdx = simulator.episodeIndex();
1709
1710 // first thing in the morning, limit the time step size to the maximum size
1711 Scalar maxTimeStepSize = Parameters::Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60;
1712 int reportStepIdx = std::max(episodeIdx, 0);
1713 if (this->enableTuning_) {
1714 const auto& tuning = schedule[reportStepIdx].tuning();
1715 maxTimeStepSize = tuning.TSMAXZ;
1716 }
1717
1718 dtNext = std::min(dtNext, maxTimeStepSize);
1719
1720 Scalar remainingEpisodeTime =
1721 simulator.episodeStartTime() + simulator.episodeLength()
1722 - (simulator.startTime() + simulator.time());
1723 assert(remainingEpisodeTime >= 0.0);
1724
1725 // if we would have a small amount of time left over in the current episode, make
1726 // two equal time steps instead of a big and a small one
1727 if (remainingEpisodeTime/2.0 < dtNext && dtNext < remainingEpisodeTime*(1.0 - 1e-5))
1728 // note: limiting to the maximum time step size here is probably not strictly
1729 // necessary, but it should not hurt and is more fool-proof
1730 dtNext = std::min(maxTimeStepSize, remainingEpisodeTime/2.0);
1731
1732 if (simulator.episodeStarts()) {
1733 // if a well event occurred, respect the limit for the maximum time step after
1734 // that, too
1735 const auto& events = simulator.vanguard().schedule()[reportStepIdx].events();
1736 bool wellEventOccured =
1737 events.hasEvent(ScheduleEvents::NEW_WELL)
1738 || events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE)
1739 || events.hasEvent(ScheduleEvents::INJECTION_UPDATE)
1740 || events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
1741 if (episodeIdx >= 0 && wellEventOccured && this->maxTimeStepAfterWellEvent_ > 0)
1742 dtNext = std::min(dtNext, this->maxTimeStepAfterWellEvent_);
1743 }
1744 }
1745
1746 return dtNext;
1747 }
1748
1750 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1751 return oilPhaseIdx;
1752 }
1753 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1754 return gasPhaseIdx;
1755 }
1756 else {
1757 return waterPhaseIdx;
1758 }
1759 }
1760
1762 {
1763 const auto& model = this->simulator().model();
1764 std::size_t numGridDof = this->model().numGridDof();
1765 this->rockCompTransMultVal_.resize(numGridDof, 1.0);
1766 for (std::size_t elementIdx = 0; elementIdx < numGridDof; ++elementIdx) {
1767 const auto& iq = *model.cachedIntensiveQuantities(elementIdx, /*timeIdx=*/ 0);
1768 Scalar trans_mult = computeRockCompTransMultiplier_<Scalar>(iq, elementIdx);
1769 this->rockCompTransMultVal_[elementIdx] = trans_mult;
1770 }
1771 }
1772
1778 template <class LhsEval>
1779 LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities& intQuants, unsigned elementIdx) const
1780 {
1781 auto obtain = [](const auto& value)
1782 {
1783 if constexpr (std::is_same_v<LhsEval, Scalar>) {
1784 return getValue(value);
1785 } else {
1786 return value;
1787 }
1788 };
1789
1790 return computeRockCompTransMultiplier_<LhsEval>(intQuants, elementIdx, obtain);
1791 }
1792
1793 template <class LhsEval, class Callback>
1794 LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
1795 {
1796 OPM_TIMEBLOCK_LOCAL(computeRockCompTransMultiplier, Subsystem::PvtProps);
1797 if (this->rockCompTransMult_.empty() && this->rockCompTransMultWc_.empty())
1798 return 1.0;
1799
1800 unsigned tableIdx = 0;
1801 if (!this->rockTableIdx_.empty())
1802 tableIdx = this->rockTableIdx_[elementIdx];
1803
1804 const auto& fs = intQuants.fluidState();
1805 LhsEval effectivePressure = obtain(fs.pressure(refPressurePhaseIdx_()));
1806 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1807 if (!this->minRefPressure_.empty())
1808 // The pore space change is irreversible
1809 effectivePressure =
1810 min(obtain(fs.pressure(refPressurePhaseIdx_())),
1811 this->minRefPressure_[elementIdx]);
1812
1813 if (!this->overburdenPressure_.empty())
1814 effectivePressure -= this->overburdenPressure_[elementIdx];
1815
1816 if (rock_config.store()) {
1817 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1818 }
1819
1820 if (!this->rockCompTransMult_.empty())
1821 return this->rockCompTransMult_[tableIdx].eval(effectivePressure, /*extrapolation=*/true);
1822
1823 // water compaction
1824 assert(!this->rockCompTransMultWc_.empty());
1825 LhsEval SwMax = max(obtain(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1826 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1827
1828 return this->rockCompTransMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax, /*extrapolation=*/true);
1829 }
1830
1831 typename Vanguard::TransmissibilityType transmissibilities_;
1832
1833 std::shared_ptr<EclMaterialLawManager> materialLawManager_;
1834 std::shared_ptr<EclThermalLawManager> thermalLawManager_;
1835
1837
1840
1844
1845 template<class T>
1846 struct BCData
1847 {
1848 std::array<std::vector<T>,6> data;
1849
1850 void resize(std::size_t size, T defVal)
1851 {
1852 for (auto& d : data)
1853 d.resize(size, defVal);
1854 }
1855
1856 const std::vector<T>& operator()(FaceDir::DirEnum dir) const
1857 {
1858 if (dir == FaceDir::DirEnum::Unknown)
1859 throw std::runtime_error("Tried to access BC data for the 'Unknown' direction");
1860 int idx = 0;
1861 int div = static_cast<int>(dir);
1862 while ((div /= 2) >= 1)
1863 ++idx;
1864 assert(idx >= 0 && idx <= 5);
1865 return data[idx];
1866 }
1867
1868 std::vector<T>& operator()(FaceDir::DirEnum dir)
1869 {
1870 return const_cast<std::vector<T>&>(std::as_const(*this)(dir));
1871 }
1872 };
1873
1874 virtual void handleSolventBC(const BCProp::BCFace&, RateVector&) const = 0;
1875
1876 virtual void handlePolymerBC(const BCProp::BCFace&, RateVector&) const = 0;
1877
1878 virtual void handleMicrBC(const BCProp::BCFace&, RateVector&) const = 0;
1879
1880 virtual void handleOxygBC(const BCProp::BCFace&, RateVector&) const = 0;
1881
1882 virtual void handleUreaBC(const BCProp::BCFace&, RateVector&) const = 0;
1883
1886 bool first_step_ = true;
1887
1890 virtual bool episodeWillBeOver() const
1891 {
1892 return this->simulator().episodeWillBeOver();
1893 }
1894};
1895
1896} // namespace Opm
1897
1898#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:197
#define OPM_BEGIN_PARALLEL_TRY_CATCH()
Macro to setup the try of a parallel try-catch.
Definition: DeferredLoggingErrorHelpers.hpp:160
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:1890
const WellModel & wellModel() const
Returns a reference to the ECL well manager used by the problem.
Definition: FlowProblem.hpp:1098
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:571
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:207
bool nonTrivialBoundaryConditions() const
Definition: FlowProblem.hpp:1110
const GlobalEqVector & drift() const
Definition: FlowProblem.hpp:1289
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:523
std::function< std::vector< IntType >(const FieldPropsManager &, const std::string &, bool)> fieldPropIntTypeOnLeafAssigner_()
Definition: FlowProblem.hpp:1432
const DimMatrix & intrinsicPermeability(unsigned globalElemIdx) const
This method returns the intrinsic permeability tensor given a global element index.
Definition: FlowProblem.hpp:553
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:906
LhsEval wellTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1212
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:706
void beginIteration()
Called by the simulator before each Newton-Raphson iteration.
Definition: FlowProblem.hpp:423
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:750
@ numComponents
Definition: FlowProblem.hpp:118
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:1602
GetPropType< TypeTag, Properties::BaseProblem > ParentType
Definition: FlowProblem.hpp:99
GetPropType< TypeTag, Properties::EqVector > EqVector
Definition: FlowProblem.hpp:107
unsigned satnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:914
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:661
bool first_step_
Definition: FlowProblem.hpp:1886
GetPropType< TypeTag, Properties::ElementContext > ElementContext
Definition: FlowProblem.hpp:152
const ThermalConductionLawParams & thermalConductionLawParams(unsigned globalSpaceIdx, unsigned) const
Definition: FlowProblem.hpp:981
AquiferModel aquiferModel_
Definition: FlowProblem.hpp:1839
GlobalEqVector drift_
Definition: FlowProblem.hpp:1836
bool updateMinPressure_()
Definition: FlowProblem.hpp:1384
std::function< std::vector< double >(const FieldPropsManager &, const std::string &)> fieldPropDoubleOnLeafAssigner_()
Definition: FlowProblem.hpp:1417
@ gasCompIdx
Definition: FlowProblem.hpp:144
Scalar transmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:618
GetPropType< TypeTag, Properties::RateVector > RateVector
Definition: FlowProblem.hpp:149
void updateReferencePorosity_()
Definition: FlowProblem.hpp:1498
Scalar thermalHalfTransmissibility(const unsigned globalSpaceIdxIn, const unsigned globalSpaceIdxOut) const
Definition: FlowProblem.hpp:638
LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1794
BCData< int > bcindex_
Definition: FlowProblem.hpp:1884
GetPropType< TypeTag, Properties::TracerModel > TracerModel
Definition: FlowProblem.hpp:169
Scalar rockCompressibility(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:740
bool updateMaxWaterSaturation_()
Definition: FlowProblem.hpp:1354
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: FlowProblem.hpp:166
@ waterPhaseIdx
Definition: FlowProblem.hpp:140
void advanceTimeLevel()
Called by the simulator to accept the current state as the new time level after a successful timestep...
Definition: FlowProblem.hpp:415
Scalar maxOilSaturation(unsigned globalDofIdx) const
Returns an element's historic maximum oil phase saturation that was observed during the simulation.
Definition: FlowProblem.hpp:996
bool updateMinPressure_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1399
std::string name() const
The problem name.
Definition: FlowProblem.hpp:945
int episodeIndex() const
Definition: FlowProblem.hpp:304
LhsEval rockCompTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1190
void endIteration()
Called by the simulator after each Newton-Raphson iteration.
Definition: FlowProblem.hpp:433
GetPropType< TypeTag, Properties::Indices > Indices
Definition: FlowProblem.hpp:109
FlowProblem(Simulator &simulator)
Definition: FlowProblem.hpp:226
virtual void handleSolventBC(const BCProp::BCFace &, RateVector &) const =0
@ enableFullyImplicitThermal
Definition: FlowProblem.hpp:132
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:684
void source(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:1066
@ enableExperiments
Definition: FlowProblem.hpp:133
virtual void readEquilInitialCondition_()=0
Scalar nextTimeStepSize() const
Propose the size of the next time step to the simulator.
Definition: FlowProblem.hpp:1119
LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1779
std::pair< BCType, RateVector > boundaryCondition(const unsigned int globalSpaceIdx, const int directionId) const
Definition: FlowProblem.hpp:1224
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:1841
@ dimWorld
Definition: FlowProblem.hpp:113
const ThermalConductionLawParams & thermalConductionLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:846
Scalar transmissibility(const Context &context, unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:560
TracerModel tracerModel_
Definition: FlowProblem.hpp:1842
@ enableThermalFluxBoundaries
Definition: FlowProblem.hpp:136
virtual void handlePolymerBC(const BCProp::BCFace &, RateVector &) const =0
const TracerModel & tracerModel() const
Definition: FlowProblem.hpp:688
WellModel wellModel_
Definition: FlowProblem.hpp:1838
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:312
const SolidEnergyLawParams & solidEnergyLawParams(unsigned globalSpaceIdx, unsigned) const
Definition: FlowProblem.hpp:975
static constexpr bool enablePolymerMolarWeight
Definition: FlowProblem.hpp:128
Scalar getRockCompTransMultVal(std::size_t dofIdx) const
Definition: FlowProblem.hpp:1610
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:371
@ gasPhaseIdx
Definition: FlowProblem.hpp:138
Scalar dofCenterDepth(unsigned globalSpaceIdx) const
Direct indexed acces to the depth of an degree of freedom [m].
Definition: FlowProblem.hpp:731
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:823
std::shared_ptr< const EclMaterialLawManager > materialLawManager() const
Returns the ECL material law manager.
Definition: FlowProblem.hpp:858
unsigned plmixnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:930
const MaterialLawParams & materialLawParams(unsigned globalDofIdx) const
Definition: FlowProblem.hpp:818
Scalar temperature(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:952
Scalar thermalHalfTransmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:674
unsigned miscnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:922
void updateRockCompTransMultVal_()
Definition: FlowProblem.hpp:1761
@ numPhases
Definition: FlowProblem.hpp:117
std::shared_ptr< EclThermalLawManager > thermalLawManager_
Definition: FlowProblem.hpp:1834
Scalar limitNextTimeStepSize_(Scalar dtNext) const
Definition: FlowProblem.hpp:1703
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
@ numEq
Definition: FlowProblem.hpp:116
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:539
void updateFailed()
Called by the simulator to restore the state captured at the beginning of the timestep after a failed...
Definition: FlowProblem.hpp:406
bool updateHysteresis_()
Definition: FlowProblem.hpp:1586
void readThermalParameters_()
Definition: FlowProblem.hpp:1481
void serializeOp(Serializer &serializer)
Definition: FlowProblem.hpp:1279
Scalar maxPolymerAdsorption(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the max polymer adsorption value.
Definition: FlowProblem.hpp:939
Scalar thermalHalfTransmissibilityIn(const Context &context, unsigned faceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:648
void setMaxOilSaturation(unsigned globalDofIdx, Scalar value)
Sets an element's maximum oil phase saturation observed during the simulation.
Definition: FlowProblem.hpp:1013
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:833
typename EclThermalLawManager::ThermalConductionLawParams ThermalConductionLawParams
Definition: FlowProblem.hpp:157
Scalar dispersivity(const unsigned globalCellIn, const unsigned globalCellOut) const
Definition: FlowProblem.hpp:598
AquiferModel & mutableAquiferModel()
Definition: FlowProblem.hpp:1107
@ dim
Definition: FlowProblem.hpp:112
GetPropType< TypeTag, Properties::IntensiveQuantities > IntensiveQuantities
Definition: FlowProblem.hpp:161
Scalar temperature(unsigned globalDofIdx, unsigned) const
Definition: FlowProblem.hpp:964
Scalar lame(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:760
@ enableSaltPrecipitation
Definition: FlowProblem.hpp:135
GetPropType< TypeTag, Properties::AquiferModel > AquiferModel
Definition: FlowProblem.hpp:163
TemperatureModel temperatureModel_
Definition: FlowProblem.hpp:1843
static constexpr bool enableExtbo
Definition: FlowProblem.hpp:125
std::shared_ptr< EclMaterialLawManager > materialLawManager_
Definition: FlowProblem.hpp:1833
WellModel & wellModel()
Definition: FlowProblem.hpp:1101
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:1303
LhsEval rockCompTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Definition: FlowProblem.hpp:1204
@ oilCompIdx
Definition: FlowProblem.hpp:145
bool updateMaxOilSaturation_()
Definition: FlowProblem.hpp:1322
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:191
void updatePffDofData_()
Definition: FlowProblem.hpp:1629
static constexpr bool enableDispersion
Definition: FlowProblem.hpp:124
virtual void endEpisode()
Called by the simulator after the end of an episode.
Definition: FlowProblem.hpp:500
@ oilPhaseIdx
Definition: FlowProblem.hpp:139
GetPropType< TypeTag, Properties::PrimaryVariables > PrimaryVariables
Definition: FlowProblem.hpp:148
bool nonTrivialBoundaryConditions_
Definition: FlowProblem.hpp:1885
GetPropType< TypeTag, Properties::Problem > Implementation
Definition: FlowProblem.hpp:100
void readBoundaryConditions_()
Definition: FlowProblem.hpp:1660
void updateRelperms(std::array< Evaluation, numPhases > &mobility, DirectionalMobilityPtr &dirMob, FluidState &fluidState, unsigned globalSpaceIdx) const
Definition: FlowProblem.hpp:865
Vanguard::TransmissibilityType transmissibilities_
Definition: FlowProblem.hpp:1831
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:1057
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:443
TemperatureModel & temperatureModel()
Definition: FlowProblem.hpp:694
Utility::CopyablePtr< DirectionalMobility< TypeTag > > DirectionalMobilityPtr
Definition: FlowProblem.hpp:170
virtual void readInitialCondition_()
Definition: FlowProblem.hpp:1557
virtual void initialSolutionApplied()
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblem.hpp:1024
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:811
Scalar thermalTransmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:605
static constexpr EnergyModules energyModuleType
Definition: FlowProblem.hpp:131
Scalar diffusivity(const Context &context, unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:580
Scalar rockReferencePressure(unsigned globalSpaceIdx) const
Definition: FlowProblem.hpp:789
std::string extraTrailerSummary() const
Definition: FlowProblem.hpp:176
void deserialize(Restarter &res)
This method restores the complete state of the problem and its sub-objects from disk.
Definition: FlowProblem.hpp:278
Scalar biotCoeff(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:770
std::shared_ptr< EclMaterialLawManager > materialLawManager()
Definition: FlowProblem.hpp:898
std::shared_ptr< const EclThermalLawManager > thermalLawManager() const
Definition: FlowProblem.hpp:861
bool updateMaxWaterSaturation_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1370
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:719
bool updateMaxOilSaturation_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblem.hpp:1340
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:1104
int refPressurePhaseIdx_() const
Definition: FlowProblem.hpp:1749
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:1146
Scalar transmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:628
TracerModel & tracerModel()
Definition: FlowProblem.hpp:691
void readMaterialParameters_()
Definition: FlowProblem.hpp:1441
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:297
MathToolbox< Evaluation > Toolbox
Definition: FlowProblem.hpp:165
@ waterCompIdx
Definition: FlowProblem.hpp:146
Scalar rockReferencePressure(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:780
Scalar diffusivity(const unsigned globalCellIn, const unsigned globalCellOut) const
Definition: FlowProblem.hpp:591
@ enableMICP
Definition: FlowProblem.hpp:134
void updateRockFraction_()
Definition: FlowProblem.hpp:1523
void prefetch(const Element &elem) const
Definition: FlowProblem.hpp:263
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:1847
const std::vector< T > & operator()(FaceDir::DirEnum dir) const
Definition: FlowProblem.hpp:1856
void resize(std::size_t size, T defVal)
Definition: FlowProblem.hpp:1850
std::vector< T > & operator()(FaceDir::DirEnum dir)
Definition: FlowProblem.hpp:1868
std::array< std::vector< T >, 6 > data
Definition: FlowProblem.hpp:1848
Definition: FlowProblem.hpp:1620
ConditionalStorage< enableFullyImplicitThermal, Scalar > thermalHalfTransOut
Definition: FlowProblem.hpp:1622
ConditionalStorage< enableFullyImplicitThermal, Scalar > thermalHalfTransIn
Definition: FlowProblem.hpp:1621
ConditionalStorage< enableDiffusion, Scalar > diffusivity
Definition: FlowProblem.hpp:1623
ConditionalStorage< enableDispersion, Scalar > dispersivity
Definition: FlowProblem.hpp:1624
Scalar transmissibility
Definition: FlowProblem.hpp:1625