opm-simulators
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
62 #include <opm/simulators/flow/FlowUtils.hpp>
66 #include <opm/simulators/timestepping/AdaptiveTimeStepping.hpp>
67 #include <opm/simulators/timestepping/SimulatorReport.hpp>
68 
69 #include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
70 #include <opm/simulators/utils/ParallelSerialization.hpp>
71 #include <opm/simulators/utils/satfunc/RelpermDiagnostics.hpp>
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 
83 namespace Opm {
84 
91 template <class TypeTag>
92 class FlowProblem : public GetPropType<TypeTag, Properties::BaseProblem>
93  , public FlowGenericProblem<GetPropType<TypeTag, Properties::GridView>,
94  GetPropType<TypeTag, Properties::FluidSystem>>
95 {
96 protected:
100  using Implementation = GetPropType<TypeTag, Properties::Problem>;
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;
153  using EclMaterialLawManager = typename GetProp<TypeTag, Properties::MaterialLaw>::EclMaterialLawManager;
154  using EclThermalLawManager = typename GetProp<TypeTag, Properties::SolidEnergyLaw>::EclThermalLawManager;
155  using MaterialLawParams = typename EclMaterialLawManager::MaterialLawParams;
156  using SolidEnergyLawParams = typename EclThermalLawManager::SolidEnergyLawParams;
157  using ThermalConductionLawParams = typename EclThermalLawManager::ThermalConductionLawParams;
161  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
164 
165  using Toolbox = MathToolbox<Evaluation>;
166  using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
167 
170  using DirectionalMobilityPtr = Utility::CopyablePtr<DirectionalMobility<TypeTag>>;
171 
172 public:
178  using BaseType::lame;
179  using BaseType::biotCoeff;
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),
233  enableDiffusion,
234  enableDispersion)
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];
338  updateReferencePorosity_();
339  this->rockFraction_[1] = this->rockFraction_[0];
340  updateRockFraction_();
341  updatePffDofData_();
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 
372  this->beginTimeStep_(enableExperiments,
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 
386  if (nonTrivialBoundaryConditions()) {
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 
471  if (this->enableDriftCompensation_ || this->enableDriftCompensationTemp_) {
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>
656  Scalar thermalHalfTransmissibilityOut(const Context& 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>
669  Scalar thermalHalfTransmissibilityBoundary(const Context& elemCtx,
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 
683  const TracerModel& tracerModel() const
684  { return tracerModel_; }
685 
686  TracerModel& tracerModel()
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>
827  const SolidEnergyLawParams&
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>
840  const ThermalConductionLawParams &
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>
860  void updateRelperms(
861  std::array<Evaluation,numPhases> &mobility,
862  DirectionalMobilityPtr &dirMob,
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 
969  const SolidEnergyLawParams&
970  solidEnergyLawParams(unsigned globalSpaceIdx,
971  unsigned /*timeIdx*/) const
972  {
973  return this->thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
974  }
975  const ThermalConductionLawParams &
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 
1019  virtual void initialSolutionApplied()
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 
1096  WellModel& wellModel()
1097  { return wellModel_; }
1098 
1099  const AquiferModel& aquiferModel() const
1100  { return aquiferModel_; }
1101 
1102  AquiferModel& mutableAquiferModel()
1103  { return aquiferModel_; }
1104 
1105  bool nonTrivialBoundaryConditions() const
1106  { return nonTrivialBoundaryConditions_; }
1107 
1114  Scalar nextTimeStepSize() const
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);
1222  if (!nonTrivialBoundaryConditions_) {
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 
1289 private:
1290  Implementation& asImp_()
1291  { return *static_cast<Implementation *>(this); }
1292 
1293  const Implementation& asImp_() const
1294  { return *static_cast<const Implementation *>(this); }
1295 
1296 protected:
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();
1306  OPM_BEGIN_PARALLEL_TRY_CATCH();
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 
1317  bool updateMaxOilSaturation_()
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 
1349  bool updateMaxWaterSaturation_()
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 
1380  bool updateMinPressure_()
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&)>
1413  fieldPropDoubleOnLeafAssigner_()
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)>
1428  fieldPropIntTypeOnLeafAssigner_()
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 
1437  void readMaterialParameters_()
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
1445  OPM_BEGIN_PARALLEL_TRY_CATCH();
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
1457  updateReferencePorosity_();
1458  this->referencePorosity_[1] = this->referencePorosity_[0];
1460 
1462  // rock fraction
1463  updateRockFraction_();
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>(),
1473  this-> lookupIdxOnLevelZeroAssigner_());
1475  }
1476 
1477  void readThermalParameters_()
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(),
1489  this-> fieldPropDoubleOnLeafAssigner_(),
1490  this-> template fieldPropIntTypeOnLeafAssigner_<unsigned int>());
1491  }
1492  }
1493 
1494  void updateReferencePorosity_()
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 
1519  void updateRockFraction_() {
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 
1553  virtual void readInitialCondition_()
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())
1561  readEquilInitialCondition_();
1562  else
1563  readExplicitInitialCondition_();
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;
1579  virtual void readExplicitInitialCondition_() = 0;
1580 
1581  // update the hysteresis parameters of the material laws for the whole grid
1582  bool updateHysteresis_()
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 
1614 protected:
1616  {
1617  ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransIn;
1618  ConditionalStorage<enableFullyImplicitThermal, Scalar> thermalHalfTransOut;
1619  ConditionalStorage<enableDiffusion, Scalar> diffusivity;
1620  ConditionalStorage<enableDispersion, Scalar> dispersivity;
1621  Scalar transmissibility;
1622  };
1623 
1624  // update the prefetch friendly data object
1625  void updatePffDofData_()
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 
1656  void readBoundaryConditions_()
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) {
1662  nonTrivialBoundaryConditions_ = true;
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.
1699  Scalar limitNextTimeStepSize_(Scalar dtNext) const
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 
1745  int refPressurePhaseIdx_() const {
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 
1757  void updateRockCompTransMultVal_()
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 
1832  GlobalEqVector drift_;
1833 
1834  WellModel wellModel_;
1835  AquiferModel aquiferModel_;
1836 
1837  PffGridVector<GridView, Stencil, PffDofData_, DofMapper> pffDofData_;
1838  TracerModel tracerModel_;
1839  TemperatureModel temperatureModel_;
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 
1880  BCData<int> bcindex_;
1881  bool nonTrivialBoundaryConditions_ = false;
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
void deserialize(Restarter &res)
This method restores the complete state of the problem and its sub-objects from disk.
Definition: FlowProblem.hpp:273
Scalar rockCompressibility(unsigned globalSpaceIdx) const
Direct access to rock compressibility.
Definition: FlowGenericProblem_impl.hpp:323
LhsEval rockCompPoroMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the porosity multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1141
void diagnosis(const EclipseState &eclState, const LevelCartesianIndexMapper &levelCartesianIndexMapper)
This function is used to diagnosis relperm in eclipse data file.
Definition: RelpermDiagnostics.cpp:907
std::shared_ptr< const EclMaterialLawManager > materialLawManager() const
Returns the ECL material law manager.
Definition: FlowProblem.hpp:853
std::shared_ptr< EclMaterialLawManager > materialLawManager()
Definition: FlowProblem.hpp:893
A class which handles tracers as specified in by ECL.
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
const DimMatrix & intrinsicPermeability(unsigned globalElemIdx) const
This method returns the intrinsic permeability tensor given a global element index.
Definition: FlowProblem.hpp:548
Scalar maxPolymerAdsorption(unsigned elemIdx) const
Returns the max polymer adsorption value.
Definition: FlowGenericProblem_impl.hpp:797
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property (equivalent to old macro GET_PROP(...))
Definition: propertysystem.hh:224
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:92
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:901
Collects necessary output values and pass it to opm-common&#39;s ECL output.
static std::string helpPreamble(int, const char **argv)
Definition: FlowGenericProblem_impl.hpp:115
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:806
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
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:366
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
virtual bool episodeWillBeOver() const
Whether or not the current episode will end at the end of the current time step.
Definition: FlowProblem.hpp:1886
unsigned pvtRegionIndex(unsigned elemIdx) const
Returns the index the relevant PVT region given a cell index.
Definition: FlowGenericProblem_impl.hpp:756
Scalar temperature(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:947
unsigned plmixnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:925
Scalar lame(unsigned elementIdx) const
Direct access to Lame&#39;s second parameter in an element.
Definition: FlowGenericProblem_impl.hpp:357
std::string name() const
The problem name.
Definition: FlowProblem.hpp:940
The base class for the element-centered finite-volume discretization scheme.
unsigned miscnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant MISC region given a cell index.
Definition: FlowGenericProblem_impl.hpp:776
Scalar transmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:623
This is a "dummy" gradient calculator which does not do anything.
Scalar nextTimeStepSize() const
Propose the size of the next time step to the simulator.
Definition: FlowProblem.hpp:1114
Scalar thermalHalfTransmissibility(const unsigned globalSpaceIdxIn, const unsigned globalSpaceIdxOut) const
Definition: FlowProblem.hpp:633
Scalar thermalHalfTransmissibilityOut(const Context &context, unsigned faceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:656
Scalar thermalHalfTransmissibilityIn(const Context &context, unsigned faceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:643
A class which handles tracers as specified in by ECL.
Definition: TracerModel.hpp:70
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Scalar maxOilSaturation(unsigned globalDofIdx) const
Returns an element&#39;s historic maximum oil phase saturation that was observed during the simulation...
Definition: FlowProblem.hpp:991
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:701
const WellModel & wellModel() const
Returns a reference to the ECL well manager used by the problem.
Definition: FlowProblem.hpp:1093
Scalar thermalHalfTransmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:669
Scalar transmissibilityBoundary(const Context &elemCtx, unsigned boundaryFaceIdx) const
Definition: FlowProblem.hpp:613
Scalar thermalTransmissibilityBoundary(const unsigned globalSpaceIdx, const unsigned boundaryFaceIdx) const
Direct access to a boundary transmissibility.
Definition: FlowProblem.hpp:600
LhsEval rockCompTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1185
Scalar dofCenterDepth(unsigned globalSpaceIdx) const
Direct indexed acces to the depth of an degree of freedom [m].
Definition: FlowProblem.hpp:726
Definition: FlowProblem.hpp:1615
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:534
Scalar biotCoeff(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:765
Helper class for grid instantiation of ECL file-format using problems.
Scalar rockBiotComp(unsigned elementIdx) const
Returns the rock compressibility of an element due to poroelasticity.
Definition: FlowGenericProblem_impl.hpp:346
Scalar maxPolymerAdsorption(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the max polymer adsorption value.
Definition: FlowProblem.hpp:934
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:307
Scalar transmissibility(unsigned globalCenterElemIdx, unsigned globalElemIdx) const
Direct access to the transmissibility between two elements.
Definition: FlowProblem.hpp:566
Scalar biotCoeff(unsigned elementIdx) const
Direct access to Biot coefficient in an element.
Definition: FlowGenericProblem_impl.hpp:388
unsigned satnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:909
Scalar rockBiotComp(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:745
virtual void endTimeStep()
Called by the simulator after each time integration.
Definition: FlowProblem.hpp:438
const Vanguard::TransmissibilityType & eclTransmissibilities() const
Return a reference to the object that handles the "raw" transmissibilities.
Definition: FlowProblem.hpp:679
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
const ThermalConductionLawParams & thermalConductionLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:841
void advanceTimeLevel()
Called by the simulator to accept the current state as the new time level after a successful timestep...
Definition: FlowProblem.hpp:410
void beginIteration()
Called by the simulator before each Newton-Raphson iteration.
Definition: FlowProblem.hpp:418
virtual void endEpisode()
Called by the simulator after the end of an episode.
Definition: FlowProblem.hpp:495
unsigned satnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant saturation function region given a cell index.
Definition: FlowGenericProblem_impl.hpp:766
Scalar rockReferencePressure(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:775
void serialize(Restarter &res)
This method writes the complete state of the problem and its subobjects to disk.
Definition: FlowProblem.hpp:292
FlowProblem(Simulator &simulator)
Definition: FlowProblem.hpp:221
Definition: FlowProblem.hpp:1842
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:186
Scalar dofCenterDepth(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the depth of an degree of freedom [m].
Definition: FlowProblem.hpp:714
Scalar porosity(unsigned globalSpaceIdx, unsigned timeIdx) const
Direct indexed access to the porosity.
Definition: FlowGenericProblem_impl.hpp:338
void setMaxOilSaturation(unsigned globalDofIdx, Scalar value)
Sets an element&#39;s maximum oil phase saturation observed during the simulation.
Definition: FlowProblem.hpp:1008
Scalar transmissibility(const Context &context, [[maybe_unused]] unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:555
virtual void initialSolutionApplied()
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblem.hpp:1019
Scalar lame(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:755
This file contains definitions related to directional mobilities.
unsigned plmixnumRegionIndex(unsigned elemIdx) const
Returns the index the relevant PLMIXNUM (for polymer module) region given a cell index.
Definition: FlowGenericProblem_impl.hpp:786
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:518
A class which handles sequential implicit solution of the energy equation as specified in by TEMP...
void updateFailed()
Called by the simulator to restore the state captured at the beginning of the timestep after a failed...
Definition: FlowProblem.hpp:401
LhsEval computeRockCompTransMultiplier_(const IntensiveQuantities &intQuants, unsigned elementIdx) const
Calculate the transmissibility multiplier due to water induced rock compaction.
Definition: FlowProblem.hpp:1775
This class is intend to be a relperm diagnostics, to detect wrong input of relperm table and endpoint...
Definition: RelpermDiagnostics.hpp:50
Scalar rockCompressibility(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:735
Scalar diffusivity(const unsigned globalCellIn, const unsigned globalCellOut) const
give the transmissibility for a face i.e.
Definition: FlowProblem.hpp:586
unsigned miscnumRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:917
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowGenericProblem.hpp:60
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
void endIteration()
Called by the simulator after each Newton-Raphson iteration.
Definition: FlowProblem.hpp:428
bool shouldWriteRestartFile() const
Returns true if an eWoms restart file should be written to disk.
Definition: FlowGenericProblem.hpp:303
Computes the initial condition based on the EQUIL keyword from ECL.
Scalar rockReferencePressure(unsigned globalSpaceIdx) const
Definition: FlowProblem.hpp:784
Scalar dispersivity(const unsigned globalCellIn, const unsigned globalCellOut) const
give the dispersivity for a face i.e.
Definition: FlowProblem.hpp:593
Scalar diffusivity(const Context &context, [[maybe_unused]] unsigned fromDofLocalIdx, unsigned toDofLocalIdx) const
Definition: FlowProblem.hpp:575