92 ,
public FlowGenericProblem<GetPropType<TypeTag, Properties::GridView>,
93 GetPropType<TypeTag, Properties::FluidSystem>>
96 using BaseType = FlowGenericProblem<GetPropType<TypeTag, Properties::GridView>,
111 enum { dim = GridView::dimension };
112 enum { dimWorld = GridView::dimensionworld };
116 enum { numPhases = FluidSystem::numPhases };
117 enum { numComponents = FluidSystem::numComponents };
128 enum { enableMICP = Indices::enableMICP };
136 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
137 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
138 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
142 enum { gasCompIdx = FluidSystem::gasCompIdx };
143 enum { oilCompIdx = FluidSystem::oilCompIdx };
144 enum { waterCompIdx = FluidSystem::waterCompIdx };
149 using Element =
typename GridView::template Codim<0>::Entity;
153 using MaterialLawParams =
typename EclMaterialLawManager::MaterialLawParams;
154 using SolidEnergyLawParams =
typename EclThermalLawManager::SolidEnergyLawParams;
155 using ThermalConductionLawParams =
typename EclThermalLawManager::ThermalConductionLawParams;
163 using Toolbox = MathToolbox<Evaluation>;
164 using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
168 using DirectionalMobilityPtr = Utility::CopyablePtr<DirectionalMobility<TypeTag>>;
183 ParentType::registerParameters();
185 registerFlowProblemParameters<Scalar>();
198 const std::string&)> addKey,
199 std::set<std::string>& seenParams,
200 std::string& errorMsg,
206 return detail::eclPositionalParameter(addKey,
217 : ParentType(simulator)
218 , BaseType(simulator.vanguard().eclState(),
219 simulator.vanguard().schedule(),
220 simulator.vanguard().gridView())
221 , transmissibilities_(simulator.vanguard().eclState(),
222 simulator.vanguard().gridView(),
223 simulator.vanguard().cartesianIndexMapper(),
224 simulator.vanguard().grid(),
225 simulator.vanguard().cellCentroids(),
229 , wellModel_(simulator)
230 , aquiferModel_(simulator)
231 , pffDofData_(simulator.gridView(), this->elementMapper())
232 , tracerModel_(simulator)
239 relpermDiagnostics.
diagnosis(simulator.vanguard().eclState(),
240 simulator.vanguard().levelCartesianIndexMapper());
246 void prefetch(
const Element& elem)
const
247 { this->pffDofData_.prefetch(elem); }
260 template <
class Restarter>
267 wellModel_.deserialize(res);
270 aquiferModel_.deserialize(res);
279 template <
class Restarter>
282 wellModel_.serialize(res);
284 aquiferModel_.serialize(res);
287 int episodeIndex()
const
289 return std::max(this->simulator().episodeIndex(), 0);
299 auto& simulator = this->simulator();
300 int episodeIdx = simulator.episodeIndex();
301 auto& eclState = simulator.vanguard().eclState();
302 const auto& schedule = simulator.vanguard().schedule();
303 const auto& events = schedule[episodeIdx].events();
305 if (episodeIdx >= 0 && events.hasEvent(ScheduleEvents::GEO_MODIFIER)) {
312 const auto& miniDeck = schedule[episodeIdx].geo_keywords();
313 const auto& cc = simulator.vanguard().grid().comm();
314 eclState.apply_schedule_keywords( miniDeck );
315 eclBroadcast(cc, eclState.getTransMult() );
318 std::function<
unsigned int(
unsigned int)> equilGridToGrid = [&simulator](
unsigned int i) {
319 return simulator.vanguard().gridEquilIdxToGridIdx(i);
323 using TransUpdateQuantities =
typename Vanguard::TransmissibilityType::TransUpdateQuantities;
324 transmissibilities_.update(
true, TransUpdateQuantities::All, equilGridToGrid);
325 this->referencePorosity_[1] = this->referencePorosity_[0];
326 updateReferencePorosity_();
328 this->model().linearizer().updateDiscretizationParameters();
331 bool tuningEvent = this->beginEpisode_(enableExperiments, this->episodeIndex());
334 wellModel_.beginEpisode();
337 aquiferModel_.beginEpisode();
340 Scalar dt = limitNextTimeStepSize_(simulator.episodeLength());
342 if ( (episodeIdx == 0 || tuningEvent) && this->initialTimeStepSize_ > 0)
345 dt = std::min(dt, this->initialTimeStepSize_);
346 simulator.setTimeStepSize(dt);
355 const int episodeIdx = this->episodeIndex();
356 const int timeStepSize = this->simulator().timeStepSize();
358 this->beginTimeStep_(enableExperiments,
360 this->simulator().timeStepIndex(),
361 this->simulator().startTime(),
362 this->simulator().time(),
364 this->simulator().endTime());
369 this->updateExplicitQuantities_(episodeIdx, timeStepSize, first_step_ && (episodeIdx > 0));
372 if (nonTrivialBoundaryConditions()) {
373 this->model().linearizer().updateBoundaryConditionData();
376 wellModel_.beginTimeStep();
377 aquiferModel_.beginTimeStep();
378 tracerModel_.beginTimeStep();
387 wellModel_.beginIteration();
388 aquiferModel_.beginIteration();
397 wellModel_.endIteration();
398 aquiferModel_.endIteration();
415 const int rank = this->simulator().gridView().comm().rank();
417 std::cout <<
"checking conservativeness of solution\n";
420 this->model().checkConservativeness(-1,
true);
422 std::cout <<
"solution is sufficiently conservative\n";
427 auto& simulator = this->simulator();
428 simulator.setTimeStepIndex(simulator.timeStepIndex()+1);
430 this->wellModel_.endTimeStep();
431 this->aquiferModel_.endTimeStep();
432 this->tracerModel_.endTimeStep();
435 this->model().linearizer().updateFlowsInfo();
437 if (this->enableDriftCompensation_) {
438 OPM_TIMEBLOCK(driftCompansation);
440 const auto& residual = this->model().linearizer().residual();
442 for (
unsigned globalDofIdx = 0; globalDofIdx < residual.size(); globalDofIdx ++) {
443 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(globalDofIdx);
444 this->drift_[sfcdofIdx] = residual[sfcdofIdx] * simulator.timeStepSize();
447 this->drift_[sfcdofIdx] *= this->model().dofTotalVolume(sfcdofIdx);
458 const int episodeIdx = this->episodeIndex();
460 this->wellModel_.endEpisode();
461 this->aquiferModel_.endEpisode();
463 const auto& schedule = this->simulator().vanguard().schedule();
466 if (episodeIdx + 1 >=
static_cast<int>(schedule.size()) - 1) {
467 this->simulator().setFinished(
true);
472 this->simulator().startNextEpisode(schedule.stepLength(episodeIdx + 1));
481 OPM_TIMEBLOCK(problemWriteOutput);
487 ParentType::writeOutput(verbose);
494 template <
class Context>
497 unsigned timeIdx)
const
499 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
500 return transmissibilities_.permeability(globalSpaceIdx);
510 {
return transmissibilities_.permeability(globalElemIdx); }
515 template <
class Context>
517 [[maybe_unused]]
unsigned fromDofLocalIdx,
518 unsigned toDofLocalIdx)
const
520 assert(fromDofLocalIdx == 0);
521 return pffDofData_.get(context.element(), toDofLocalIdx).transmissibility;
529 return transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
535 template <
class Context>
537 [[maybe_unused]]
unsigned fromDofLocalIdx,
538 unsigned toDofLocalIdx)
const
540 assert(fromDofLocalIdx == 0);
541 return *pffDofData_.get(context.element(), toDofLocalIdx).diffusivity;
547 Scalar
diffusivity(
const unsigned globalCellIn,
const unsigned globalCellOut)
const{
548 return transmissibilities_.diffusivity(globalCellIn, globalCellOut);
554 Scalar
dispersivity(
const unsigned globalCellIn,
const unsigned globalCellOut)
const{
555 return transmissibilities_.dispersivity(globalCellIn, globalCellOut);
562 const unsigned boundaryFaceIdx)
const
564 return transmissibilities_.thermalTransmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
573 template <
class Context>
575 unsigned boundaryFaceIdx)
const
577 unsigned elemIdx = elemCtx.globalSpaceIndex(0, 0);
578 return transmissibilities_.transmissibilityBoundary(elemIdx, boundaryFaceIdx);
585 const unsigned boundaryFaceIdx)
const
587 return transmissibilities_.transmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
595 const unsigned globalSpaceIdxOut)
const
597 return transmissibilities_.thermalHalfTrans(globalSpaceIdxIn,globalSpaceIdxOut);
603 template <
class Context>
606 unsigned timeIdx)
const
608 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
609 unsigned toDofLocalIdx = face.exteriorIndex();
610 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransIn;
616 template <
class Context>
619 unsigned timeIdx)
const
621 const auto& face = context.stencil(timeIdx).interiorFace(faceIdx);
622 unsigned toDofLocalIdx = face.exteriorIndex();
623 return *pffDofData_.get(context.element(), toDofLocalIdx).thermalHalfTransOut;
629 template <
class Context>
631 unsigned boundaryFaceIdx)
const
633 unsigned elemIdx = elemCtx.globalSpaceIndex(0, 0);
634 return transmissibilities_.thermalHalfTransBoundary(elemIdx, boundaryFaceIdx);
641 {
return transmissibilities_; }
645 {
return tracerModel_; }
647 TracerModel& tracerModel()
648 {
return tracerModel_; }
658 template <
class Context>
659 Scalar
porosity(
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const
661 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
662 return this->
porosity(globalSpaceIdx, timeIdx);
671 template <
class Context>
672 Scalar
dofCenterDepth(
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const
674 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
686 return this->simulator().vanguard().cellCenterDepth(globalSpaceIdx);
692 template <
class Context>
695 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
702 template <
class Context>
705 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
714 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
715 if (rock_config.store()) {
716 return asImp_().initialFluidState(globalSpaceIdx).pressure(refPressurePhaseIdx_());
719 if (this->rockParams_.empty())
722 unsigned tableIdx = 0;
723 if (!this->rockTableIdx_.empty()) {
724 tableIdx = this->rockTableIdx_[globalSpaceIdx];
726 return this->rockParams_[tableIdx].referencePressure;
733 template <
class Context>
735 unsigned spaceIdx,
unsigned timeIdx)
const
737 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
743 return materialLawManager_->materialLawParams(globalDofIdx);
746 const MaterialLawParams&
materialLawParams(
unsigned globalDofIdx, FaceDir::DirEnum facedir)
const
748 return materialLawManager_->materialLawParams(globalDofIdx, facedir);
754 template <
class Context>
755 const SolidEnergyLawParams&
758 unsigned timeIdx)
const
760 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
761 return thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
767 template <
class Context>
768 const ThermalConductionLawParams &
771 unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
772 return thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
782 {
return materialLawManager_; }
784 template <
class FluidState,
class ...Args>
786 std::array<Evaluation,numPhases> &mobility,
787 DirectionalMobilityPtr &dirMob,
788 FluidState &fluidState,
789 unsigned globalSpaceIdx)
const
791 using ContainerT = std::array<Evaluation, numPhases>;
792 OPM_TIMEBLOCK_LOCAL(updateRelperms, Subsystem::SatProps);
797 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mobility, materialParams, fluidState);
798 Valgrind::CheckDefined(mobility);
800 if (materialLawManager_->hasDirectionalRelperms()
801 || materialLawManager_->hasDirectionalImbnum())
803 using Dir = FaceDir::DirEnum;
804 constexpr int ndim = 3;
805 dirMob = std::make_unique<DirectionalMobility<TypeTag>>();
806 Dir facedirs[ndim] = {Dir::XPlus, Dir::YPlus, Dir::ZPlus};
807 for (
int i = 0; i<ndim; i++) {
809 auto& mob_array = dirMob->getArray(i);
810 MaterialLaw::template relativePermeabilities<ContainerT, FluidState, Args...>(mob_array, materialParams, fluidState);
819 {
return materialLawManager_; }
825 template <
class Context>
826 unsigned pvtRegionIndex(
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const
827 {
return pvtRegionIndex(context.globalSpaceIndex(spaceIdx, timeIdx)); }
833 template <
class Context>
841 template <
class Context>
849 template <
class Context>
858 template <
class Context>
866 {
return this->simulator().vanguard().caseName(); }
871 template <
class Context>
872 Scalar
temperature(
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const
876 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
877 return asImp_().initialFluidState(globalDofIdx).temperature(0);
881 Scalar
temperature(
unsigned globalDofIdx,
unsigned )
const
885 return asImp_().initialFluidState(globalDofIdx).temperature(0);
888 const SolidEnergyLawParams&
892 return this->thermalLawManager_->solidEnergyLawParams(globalSpaceIdx);
894 const ThermalConductionLawParams &
898 return this->thermalLawManager_->thermalConductionLawParams(globalSpaceIdx);
912 if (!this->vapparsActive(this->episodeIndex()))
915 return this->maxOilSaturation_[globalDofIdx];
929 if (!this->vapparsActive(this->episodeIndex()))
932 this->maxOilSaturation_[globalDofIdx] = value;
941 this->model().invalidateAndUpdateIntensiveQuantities(0);
947 if (!this->model().enableStorageCache() || !this->recycleFirstIterationStorage()) {
948 this->model().invalidateAndUpdateIntensiveQuantities(1);
956 aquiferModel_.initialSolutionApplied();
958 const bool invalidateFromHyst = updateHysteresis_();
959 if (invalidateFromHyst) {
960 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
961 this->model().invalidateAndUpdateIntensiveQuantities(0);
970 template <
class Context>
972 const Context& context,
974 unsigned timeIdx)
const
976 const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
977 source(rate, globalDofIdx, timeIdx);
980 void source(RateVector& rate,
981 unsigned globalDofIdx,
982 unsigned timeIdx)
const
984 OPM_TIMEBLOCK_LOCAL(eclProblemSource, Subsystem::Assembly);
988 wellModel_.computeTotalRatesForDof(rate, globalDofIdx);
992 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
993 rate[eqIdx] /= this->model().dofTotalVolume(globalDofIdx);
995 Valgrind::CheckDefined(rate[eqIdx]);
996 assert(isfinite(rate[eqIdx]));
1000 addToSourceDense(rate, globalDofIdx, timeIdx);
1003 virtual void addToSourceDense(RateVector& rate,
1004 unsigned globalDofIdx,
1005 unsigned timeIdx)
const = 0;
1013 {
return wellModel_; }
1016 {
return wellModel_; }
1018 const AquiferModel& aquiferModel()
const
1019 {
return aquiferModel_; }
1021 AquiferModel& mutableAquiferModel()
1022 {
return aquiferModel_; }
1024 bool nonTrivialBoundaryConditions()
const
1025 {
return nonTrivialBoundaryConditions_; }
1035 OPM_TIMEBLOCK(nexTimeStepSize);
1037 if (this->nextTimeStepSize_ > 0.0)
1038 return this->nextTimeStepSize_;
1040 const auto& simulator = this->simulator();
1041 int episodeIdx = simulator.episodeIndex();
1045 return this->initialTimeStepSize_;
1050 const auto& newtonMethod = this->model().newtonMethod();
1051 return limitNextTimeStepSize_(newtonMethod.suggestTimeStepSize(simulator.timeStepSize()));
1059 template <
class LhsEval>
1063 if (this->rockCompPoroMult_.empty() && this->rockCompPoroMultWc_.empty())
1066 unsigned tableIdx = 0;
1067 if (!this->rockTableIdx_.empty())
1068 tableIdx = this->rockTableIdx_[elementIdx];
1070 const auto& fs = intQuants.fluidState();
1071 LhsEval effectivePressure = decay<LhsEval>(fs.pressure(refPressurePhaseIdx_()));
1072 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1073 if (!this->minRefPressure_.empty())
1076 min(decay<LhsEval>(fs.pressure(refPressurePhaseIdx_())),
1077 this->minRefPressure_[elementIdx]);
1079 if (!this->overburdenPressure_.empty())
1080 effectivePressure -= this->overburdenPressure_[elementIdx];
1082 if (rock_config.store()) {
1083 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1086 if (!this->rockCompPoroMult_.empty()) {
1087 return this->rockCompPoroMult_[tableIdx].eval(effectivePressure,
true);
1091 assert(!this->rockCompPoroMultWc_.empty());
1092 LhsEval SwMax = max(decay<LhsEval>(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1093 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1095 return this->rockCompPoroMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax,
true);
1103 template <
class LhsEval>
1106 const bool implicit = !this->explicitRockCompaction_;
1108 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1115 template <
class LhsEval>
1120 const bool implicit = !this->explicitRockCompaction_;
1122 : this->simulator().problem().getRockCompTransMultVal(elementIdx);
1123 trans_mult *= this->simulator().problem().template permFactTransMultiplier<double>(intQuants, elementIdx);
1128 std::pair<BCType, RateVector> boundaryCondition(
const unsigned int globalSpaceIdx,
const int directionId)
const
1130 OPM_TIMEBLOCK_LOCAL(boundaryCondition, Subsystem::Assembly);
1131 if (!nonTrivialBoundaryConditions_) {
1132 return { BCType::NONE, RateVector(0.0) };
1134 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
1135 const auto& schedule = this->simulator().vanguard().schedule();
1136 if (bcindex_(dir)[globalSpaceIdx] == 0) {
1137 return { BCType::NONE, RateVector(0.0) };
1139 if (schedule[this->episodeIndex()].bcprop.size() == 0) {
1140 return { BCType::NONE, RateVector(0.0) };
1142 const auto& bc = schedule[this->episodeIndex()].bcprop[bcindex_(dir)[globalSpaceIdx]];
1143 if (bc.bctype!=BCType::RATE) {
1144 return { bc.bctype, RateVector(0.0) };
1147 RateVector rate = 0.0;
1148 switch (bc.component) {
1149 case BCComponent::OIL:
1150 rate[FluidSystem::canonicalToActiveCompIdx(oilCompIdx)] = bc.rate;
1152 case BCComponent::GAS:
1153 rate[FluidSystem::canonicalToActiveCompIdx(gasCompIdx)] = bc.rate;
1155 case BCComponent::WATER:
1156 rate[FluidSystem::canonicalToActiveCompIdx(waterCompIdx)] = bc.rate;
1158 case BCComponent::SOLVENT:
1159 this->handleSolventBC(bc, rate);
1161 case BCComponent::POLYMER:
1162 this->handlePolymerBC(bc, rate);
1164 case BCComponent::MICR:
1165 this->handleMicrBC(bc, rate);
1167 case BCComponent::OXYG:
1168 this->handleOxygBC(bc, rate);
1170 case BCComponent::UREA:
1171 this->handleUreaBC(bc, rate);
1173 case BCComponent::NONE:
1174 throw std::logic_error(
"you need to specify the component when RATE type is set in BC");
1178 return {bc.bctype, rate};
1182 template<
class Serializer>
1183 void serializeOp(Serializer& serializer)
1185 serializer(
static_cast<BaseType&
>(*
this));
1187 serializer(wellModel_);
1188 serializer(aquiferModel_);
1189 serializer(tracerModel_);
1190 serializer(*materialLawManager_);
1194 Implementation& asImp_()
1195 {
return *
static_cast<Implementation *
>(
this); }
1197 const Implementation& asImp_()
const
1198 {
return *
static_cast<const Implementation *
>(
this); }
1201 template<
class UpdateFunc>
1202 void updateProperty_(
const std::string& failureMsg,
1205 OPM_TIMEBLOCK(updateProperty);
1206 const auto& model = this->simulator().model();
1207 const auto& primaryVars = model.solution(0);
1208 const auto& vanguard = this->simulator().vanguard();
1209 std::size_t numGridDof = primaryVars.size();
1210 OPM_BEGIN_PARALLEL_TRY_CATCH();
1212#pragma omp parallel for
1214 for (
unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
1215 const auto& iq = *model.cachedIntensiveQuantities(dofIdx, 0);
1218 OPM_END_PARALLEL_TRY_CATCH(failureMsg, vanguard.grid().comm());
1221 bool updateMaxOilSaturation_()
1223 OPM_TIMEBLOCK(updateMaxOilSaturation);
1224 int episodeIdx = this->episodeIndex();
1227 if (this->vapparsActive(episodeIdx)) {
1228 this->updateProperty_(
"FlowProblem::updateMaxOilSaturation_() failed:",
1229 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1231 this->updateMaxOilSaturation_(compressedDofIdx,iq);
1239 bool updateMaxOilSaturation_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1241 OPM_TIMEBLOCK_LOCAL(updateMaxOilSaturation, Subsystem::SatProps);
1242 const auto& fs = iq.fluidState();
1243 const Scalar So = decay<Scalar>(fs.saturation(refPressurePhaseIdx_()));
1244 auto& mos = this->maxOilSaturation_;
1245 if(mos[compressedDofIdx] < So){
1246 mos[compressedDofIdx] = So;
1253 bool updateMaxWaterSaturation_()
1255 OPM_TIMEBLOCK(updateMaxWaterSaturation);
1257 if (this->maxWaterSaturation_.empty())
1260 this->maxWaterSaturation_[1] = this->maxWaterSaturation_[0];
1261 this->updateProperty_(
"FlowProblem::updateMaxWaterSaturation_() failed:",
1262 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1264 this->updateMaxWaterSaturation_(compressedDofIdx,iq);
1270 bool updateMaxWaterSaturation_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1272 OPM_TIMEBLOCK_LOCAL(updateMaxWaterSaturation, Subsystem::SatProps);
1273 const auto& fs = iq.fluidState();
1274 const Scalar Sw = decay<Scalar>(fs.saturation(waterPhaseIdx));
1275 auto& mow = this->maxWaterSaturation_;
1276 if(mow[compressedDofIdx]< Sw){
1277 mow[compressedDofIdx] = Sw;
1284 bool updateMinPressure_()
1286 OPM_TIMEBLOCK(updateMinPressure);
1288 if (this->minRefPressure_.empty())
1291 this->updateProperty_(
"FlowProblem::updateMinPressure_() failed:",
1292 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1294 this->updateMinPressure_(compressedDofIdx,iq);
1299 bool updateMinPressure_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq){
1300 OPM_TIMEBLOCK_LOCAL(updateMinPressure, Subsystem::PvtProps);
1301 const auto& fs = iq.fluidState();
1302 const Scalar min_pressure = getValue(fs.pressure(refPressurePhaseIdx_()));
1303 auto& min_pressures = this->minRefPressure_;
1304 if(min_pressures[compressedDofIdx]> min_pressure){
1305 min_pressures[compressedDofIdx] = min_pressure;
1316 std::function<std::vector<double>(
const FieldPropsManager&,
const std::string&)>
1317 fieldPropDoubleOnLeafAssigner_()
1319 const auto& lookup = this->lookUpData_;
1320 return [&lookup](
const FieldPropsManager& fieldPropManager,
const std::string& propString)
1322 return lookup.assignFieldPropsDoubleOnLeaf(fieldPropManager, propString);
1330 template<
typename IntType>
1331 std::function<std::vector<IntType>(
const FieldPropsManager&,
const std::string&,
bool)>
1332 fieldPropIntTypeOnLeafAssigner_()
1334 const auto& lookup = this->lookUpData_;
1335 return [&lookup](
const FieldPropsManager& fieldPropManager,
const std::string& propString,
bool needsTranslation)
1337 return lookup.template assignFieldPropsIntOnLeaf<IntType>(fieldPropManager, propString, needsTranslation);
1341 void readMaterialParameters_()
1343 OPM_TIMEBLOCK(readMaterialParameters);
1344 const auto& simulator = this->simulator();
1345 const auto& vanguard = simulator.vanguard();
1346 const auto& eclState = vanguard.eclState();
1349 OPM_BEGIN_PARALLEL_TRY_CATCH();
1350 this->updatePvtnum_();
1351 this->updateSatnum_();
1354 this->updateMiscnum_();
1356 this->updatePlmixnum_();
1358 OPM_END_PARALLEL_TRY_CATCH(
"Invalid region numbers: ", vanguard.gridView().comm());
1361 updateReferencePorosity_();
1362 this->referencePorosity_[1] = this->referencePorosity_[0];
1367 materialLawManager_ = std::make_shared<EclMaterialLawManager>();
1368 materialLawManager_->initFromState(eclState);
1369 materialLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1370 this->
template fieldPropIntTypeOnLeafAssigner_<int>(),
1371 this-> lookupIdxOnLevelZeroAssigner_());
1375 void readThermalParameters_()
1377 if constexpr (enableEnergy)
1379 const auto& simulator = this->simulator();
1380 const auto& vanguard = simulator.vanguard();
1381 const auto& eclState = vanguard.eclState();
1384 thermalLawManager_ = std::make_shared<EclThermalLawManager>();
1385 thermalLawManager_->initParamsForElements(eclState, this->model().numGridDof(),
1386 this-> fieldPropDoubleOnLeafAssigner_(),
1387 this->
template fieldPropIntTypeOnLeafAssigner_<unsigned int>());
1391 void updateReferencePorosity_()
1393 const auto& simulator = this->simulator();
1394 const auto& vanguard = simulator.vanguard();
1395 const auto& eclState = vanguard.eclState();
1397 std::size_t numDof = this->model().numGridDof();
1399 this->referencePorosity_[0].resize(numDof);
1401 const auto& fp = eclState.fieldProps();
1402 const std::vector<double> porvData =
this -> fieldPropDoubleOnLeafAssigner_()(fp,
"PORV");
1403 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1404 int sfcdofIdx = simulator.vanguard().gridEquilIdxToGridIdx(dofIdx);
1405 Scalar poreVolume = porvData[dofIdx];
1410 Scalar dofVolume = simulator.model().dofTotalVolume(sfcdofIdx);
1411 assert(dofVolume > 0.0);
1412 this->referencePorosity_[0][sfcdofIdx] = poreVolume/dofVolume;
1416 virtual void readInitialCondition_()
1419 const auto& simulator = this->simulator();
1420 const auto& vanguard = simulator.vanguard();
1421 const auto& eclState = vanguard.eclState();
1423 if (eclState.getInitConfig().hasEquil())
1424 readEquilInitialCondition_();
1426 readExplicitInitialCondition_();
1429 std::size_t numElems = this->model().numGridDof();
1430 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1431 const auto& fs = asImp_().initialFluidStates()[elemIdx];
1432 if (!this->maxWaterSaturation_.empty() && waterPhaseIdx > -1)
1433 this->maxWaterSaturation_[elemIdx] = std::max(this->maxWaterSaturation_[elemIdx], fs.saturation(waterPhaseIdx));
1434 if (!this->maxOilSaturation_.empty() && oilPhaseIdx > -1)
1435 this->maxOilSaturation_[elemIdx] = std::max(this->maxOilSaturation_[elemIdx], fs.saturation(oilPhaseIdx));
1436 if (!this->minRefPressure_.empty() && refPressurePhaseIdx_() > -1)
1437 this->minRefPressure_[elemIdx] = std::min(this->minRefPressure_[elemIdx], fs.pressure(refPressurePhaseIdx_()));
1441 virtual void readEquilInitialCondition_() = 0;
1442 virtual void readExplicitInitialCondition_() = 0;
1445 bool updateHysteresis_()
1447 if (!materialLawManager_->enableHysteresis())
1452 this->updateProperty_(
"FlowProblem::updateHysteresis_() failed:",
1453 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1455 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1461 bool updateHysteresis_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1463 OPM_TIMEBLOCK_LOCAL(updateHysteresis_, Subsystem::SatProps);
1464 materialLawManager_->updateHysteresis(iq.fluidState(), compressedDofIdx);
1469 Scalar getRockCompTransMultVal(std::size_t dofIdx)
const
1471 if (this->rockCompTransMultVal_.empty())
1474 return this->rockCompTransMultVal_[dofIdx];
1480 ConditionalStorage<enableEnergy, Scalar> thermalHalfTransIn;
1481 ConditionalStorage<enableEnergy, Scalar> thermalHalfTransOut;
1482 ConditionalStorage<enableDiffusion, Scalar> diffusivity;
1483 ConditionalStorage<enableDispersion, Scalar> dispersivity;
1484 Scalar transmissibility;
1488 void updatePffDofData_()
1490 const auto& distFn =
1492 const Stencil& stencil,
1493 unsigned localDofIdx)
1496 const auto& elementMapper = this->model().elementMapper();
1498 unsigned globalElemIdx = elementMapper.index(stencil.entity(localDofIdx));
1499 if (localDofIdx != 0) {
1500 unsigned globalCenterElemIdx = elementMapper.index(stencil.entity(0));
1501 dofData.transmissibility = transmissibilities_.transmissibility(globalCenterElemIdx, globalElemIdx);
1503 if constexpr (enableEnergy) {
1504 *dofData.thermalHalfTransIn = transmissibilities_.thermalHalfTrans(globalCenterElemIdx, globalElemIdx);
1505 *dofData.thermalHalfTransOut = transmissibilities_.thermalHalfTrans(globalElemIdx, globalCenterElemIdx);
1507 if constexpr (enableDiffusion)
1508 *dofData.diffusivity = transmissibilities_.diffusivity(globalCenterElemIdx, globalElemIdx);
1509 if (enableDispersion)
1510 dofData.dispersivity = transmissibilities_.dispersivity(globalCenterElemIdx, globalElemIdx);
1514 pffDofData_.update(distFn);
1517 virtual void updateExplicitQuantities_(
int episodeIdx,
int timeStepSize,
bool first_step_after_restart) = 0;
1519 void readBoundaryConditions_()
1521 const auto& simulator = this->simulator();
1522 const auto& vanguard = simulator.vanguard();
1523 const auto& bcconfig = vanguard.eclState().getSimulationConfig().bcconfig();
1524 if (bcconfig.size() > 0) {
1525 nonTrivialBoundaryConditions_ =
true;
1527 std::size_t numCartDof = vanguard.cartesianSize();
1528 unsigned numElems = vanguard.gridView().size(0);
1529 std::vector<int> cartesianToCompressedElemIdx(numCartDof, -1);
1531 for (
unsigned elemIdx = 0; elemIdx < numElems; ++elemIdx)
1532 cartesianToCompressedElemIdx[vanguard.cartesianIndex(elemIdx)] = elemIdx;
1534 bcindex_.resize(numElems, 0);
1535 auto loopAndApply = [&cartesianToCompressedElemIdx,
1536 &vanguard](
const auto& bcface,
1539 for (
int i = bcface.i1; i <= bcface.i2; ++i) {
1540 for (
int j = bcface.j1; j <= bcface.j2; ++j) {
1541 for (
int k = bcface.k1; k <= bcface.k2; ++k) {
1542 std::array<int, 3> tmp = {i,j,k};
1543 auto elemIdx = cartesianToCompressedElemIdx[vanguard.cartesianIndex(tmp)];
1550 for (
const auto& bcface : bcconfig) {
1551 std::vector<int>& data = bcindex_(bcface.dir);
1552 const int index = bcface.index;
1553 loopAndApply(bcface,
1554 [&data,index](
int elemIdx)
1555 { data[elemIdx] = index; });
1562 Scalar limitNextTimeStepSize_(Scalar dtNext)
const
1564 if constexpr (enableExperiments) {
1565 const auto& simulator = this->simulator();
1566 const auto& schedule = simulator.vanguard().schedule();
1567 int episodeIdx = simulator.episodeIndex();
1570 Scalar maxTimeStepSize = Parameters::Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60;
1571 int reportStepIdx = std::max(episodeIdx, 0);
1572 if (this->enableTuning_) {
1573 const auto& tuning = schedule[reportStepIdx].tuning();
1574 maxTimeStepSize = tuning.TSMAXZ;
1577 dtNext = std::min(dtNext, maxTimeStepSize);
1579 Scalar remainingEpisodeTime =
1580 simulator.episodeStartTime() + simulator.episodeLength()
1581 - (simulator.startTime() + simulator.time());
1582 assert(remainingEpisodeTime >= 0.0);
1586 if (remainingEpisodeTime/2.0 < dtNext && dtNext < remainingEpisodeTime*(1.0 - 1e-5))
1589 dtNext = std::min(maxTimeStepSize, remainingEpisodeTime/2.0);
1591 if (simulator.episodeStarts()) {
1594 const auto& events = simulator.vanguard().schedule()[reportStepIdx].events();
1595 bool wellEventOccured =
1596 events.hasEvent(ScheduleEvents::NEW_WELL)
1597 || events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE)
1598 || events.hasEvent(ScheduleEvents::INJECTION_UPDATE)
1599 || events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
1600 if (episodeIdx >= 0 && wellEventOccured && this->maxTimeStepAfterWellEvent_ > 0)
1601 dtNext = std::min(dtNext, this->maxTimeStepAfterWellEvent_);
1608 int refPressurePhaseIdx_()
const {
1609 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1612 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1616 return waterPhaseIdx;
1620 void updateRockCompTransMultVal_()
1622 const auto& model = this->simulator().model();
1623 std::size_t numGridDof = this->model().numGridDof();
1624 this->rockCompTransMultVal_.resize(numGridDof, 1.0);
1625 for (std::size_t elementIdx = 0; elementIdx < numGridDof; ++elementIdx) {
1626 const auto& iq = *model.cachedIntensiveQuantities(elementIdx, 0);
1628 this->rockCompTransMultVal_[elementIdx] = trans_mult;
1637 template <
class LhsEval>
1640 OPM_TIMEBLOCK_LOCAL(computeRockCompTransMultiplier, Subsystem::PvtProps);
1641 if (this->rockCompTransMult_.empty() && this->rockCompTransMultWc_.empty())
1644 unsigned tableIdx = 0;
1645 if (!this->rockTableIdx_.empty())
1646 tableIdx = this->rockTableIdx_[elementIdx];
1648 const auto& fs = intQuants.fluidState();
1649 LhsEval effectivePressure = decay<LhsEval>(fs.pressure(refPressurePhaseIdx_()));
1650 const auto& rock_config = this->simulator().vanguard().eclState().getSimulationConfig().rock_config();
1651 if (!this->minRefPressure_.empty())
1654 min(decay<LhsEval>(fs.pressure(refPressurePhaseIdx_())),
1655 this->minRefPressure_[elementIdx]);
1657 if (!this->overburdenPressure_.empty())
1658 effectivePressure -= this->overburdenPressure_[elementIdx];
1660 if (rock_config.store()) {
1661 effectivePressure -= asImp_().initialFluidState(elementIdx).pressure(refPressurePhaseIdx_());
1664 if (!this->rockCompTransMult_.empty())
1665 return this->rockCompTransMult_[tableIdx].eval(effectivePressure,
true);
1668 assert(!this->rockCompTransMultWc_.empty());
1669 LhsEval SwMax = max(decay<LhsEval>(fs.saturation(waterPhaseIdx)), this->maxWaterSaturation_[elementIdx]);
1670 LhsEval SwDeltaMax = SwMax - asImp_().initialFluidStates()[elementIdx].saturation(waterPhaseIdx);
1672 return this->rockCompTransMultWc_[tableIdx].eval(effectivePressure, SwDeltaMax,
true);
1675 typename Vanguard::TransmissibilityType transmissibilities_;
1677 std::shared_ptr<EclMaterialLawManager> materialLawManager_;
1678 std::shared_ptr<EclThermalLawManager> thermalLawManager_;
1680 GlobalEqVector drift_;
1682 WellModel wellModel_;
1683 AquiferModel aquiferModel_;
1691 std::array<std::vector<T>,6> data;
1693 void resize(std::size_t size, T defVal)
1695 for (
auto& d : data)
1696 d.resize(size, defVal);
1699 const std::vector<T>& operator()(FaceDir::DirEnum dir)
const
1701 if (dir == FaceDir::DirEnum::Unknown)
1702 throw std::runtime_error(
"Tried to access BC data for the 'Unknown' direction");
1704 int div =
static_cast<int>(dir);
1705 while ((div /= 2) >= 1)
1707 assert(idx >= 0 && idx <= 5);
1711 std::vector<T>& operator()(FaceDir::DirEnum dir)
1713 return const_cast<std::vector<T>&
>(std::as_const(*
this)(dir));
1717 virtual void handleSolventBC(
const BCProp::BCFace&, RateVector&)
const = 0;
1719 virtual void handlePolymerBC(
const BCProp::BCFace&, RateVector&)
const = 0;
1721 virtual void handleMicrBC(
const BCProp::BCFace&, RateVector&)
const = 0;
1723 virtual void handleOxygBC(
const BCProp::BCFace&, RateVector&)
const = 0;
1725 virtual void handleUreaBC(
const BCProp::BCFace&, RateVector&)
const = 0;
1728 bool nonTrivialBoundaryConditions_ =
false;
1729 bool first_step_ =
true;
1735 return this->simulator().episodeWillBeOver();