OutputBlackoilModule.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 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
27#ifndef OPM_OUTPUT_BLACK_OIL_MODULE_HPP
28#define OPM_OUTPUT_BLACK_OIL_MODULE_HPP
29
30#include <dune/common/fvector.hh>
31
33
34#include <opm/common/Exceptions.hpp>
35#include <opm/common/TimingMacros.hpp>
36#include <opm/common/OpmLog/OpmLog.hpp>
37#include <opm/common/utility/Visitor.hpp>
38
39#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
40
41#include <opm/material/common/Valgrind.hpp>
42#include <opm/material/fluidmatrixinteractions/EclEpsScalingPoints.hpp>
43#include <opm/material/fluidstates/BlackOilFluidState.hpp>
44#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
45
51
52#include <opm/output/data/Cells.hpp>
53#include <opm/output/eclipse/EclipseIO.hpp>
54#include <opm/output/eclipse/Inplace.hpp>
55
60
61#include <algorithm>
62#include <array>
63#include <cassert>
64#include <cstddef>
65#include <functional>
66#include <stdexcept>
67#include <string>
68#include <type_traits>
69#include <utility>
70#include <vector>
71
72namespace Opm {
73
74// forward declaration
75template <class TypeTag>
76class EcfvDiscretization;
77
84template <class TypeTag>
85class OutputBlackOilModule : public GenericOutputBlackoilModule<GetPropType<TypeTag, Properties::FluidSystem>>
86{
96 using FluidState = typename IntensiveQuantities::FluidState;
98 using Element = typename GridView::template Codim<0>::Entity;
99 using ElementIterator = typename GridView::template Codim<0>::Iterator;
102 using Dir = FaceDir::DirEnum;
108
109 static constexpr int conti0EqIdx = Indices::conti0EqIdx;
110 static constexpr int numPhases = FluidSystem::numPhases;
111 static constexpr int oilPhaseIdx = FluidSystem::oilPhaseIdx;
112 static constexpr int gasPhaseIdx = FluidSystem::gasPhaseIdx;
113 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
114 static constexpr int gasCompIdx = FluidSystem::gasCompIdx;
115 static constexpr int oilCompIdx = FluidSystem::oilCompIdx;
116 static constexpr int waterCompIdx = FluidSystem::waterCompIdx;
117 static constexpr EnergyModules energyModuleType = getPropValue<TypeTag, Properties::EnergyModuleType>();
118 enum { enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>() };
119 enum { enableMICP = Indices::enableMICP };
120 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
121 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
122 enum { enableDissolvedGas = Indices::compositionSwitchIdx >= 0 };
123
124 template<class VectorType>
125 static Scalar value_or_zero(int idx, const VectorType& v)
126 {
127 if (idx == -1) {
128 return 0.0;
129 }
130 return v.empty() ? 0.0 : v[idx];
131 }
132
133public:
134 OutputBlackOilModule(const Simulator& simulator,
135 const SummaryConfig& smryCfg,
136 const CollectDataOnIORankType& collectOnIORank)
137 : BaseType(simulator.vanguard().eclState(),
138 simulator.vanguard().schedule(),
139 smryCfg,
140 simulator.vanguard().summaryState(),
142 [this](const int idx)
143 { return simulator_.problem().eclWriter().collectOnIORank().localIdxToGlobalIdx(idx); },
144 [&collectOnIORank](const int idx)
145 { return collectOnIORank.isCartIdxOnThisRank(idx); },
146 simulator.vanguard().grid().comm(),
147 energyModuleType == EnergyModules::FullyImplicitThermal ||
148 energyModuleType == EnergyModules::SequentialImplicitThermal,
149 energyModuleType == EnergyModules::ConstantTemperature,
150 getPropValue<TypeTag, Properties::EnableMech>(),
151 getPropValue<TypeTag, Properties::EnableSolvent>(),
152 getPropValue<TypeTag, Properties::EnablePolymer>(),
153 getPropValue<TypeTag, Properties::EnableFoam>(),
154 getPropValue<TypeTag, Properties::EnableBrine>(),
155 getPropValue<TypeTag, Properties::EnableSaltPrecipitation>(),
156 getPropValue<TypeTag, Properties::EnableExtbo>(),
157 getPropValue<TypeTag, Properties::EnableBioeffects>(),
158 getPropValue<TypeTag, Properties::EnableGeochemistry>())
159 , simulator_(simulator)
160 , collectOnIORank_(collectOnIORank)
161 {
162 for (auto& region_pair : this->regions_) {
163 this->createLocalRegion_(region_pair.second);
164 }
165
166 auto isCartIdxOnThisRank = [&collectOnIORank](const int idx) {
167 return collectOnIORank.isCartIdxOnThisRank(idx);
168 };
169
170 this->setupBlockData(isCartIdxOnThisRank);
171
172 if (! Parameters::Get<Parameters::OwnerCellsFirst>()) {
173 const std::string msg = "The output code does not support --owner-cells-first=false.";
174 if (collectOnIORank.isIORank()) {
175 OpmLog::error(msg);
176 }
177 OPM_THROW_NOLOG(std::runtime_error, msg);
178 }
179
180 if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) {
181 auto rset = this->eclState_.fieldProps().fip_regions();
182 rset.push_back("PVTNUM");
183
184 // Note: We explicitly use decltype(auto) here because the
185 // default scheme (-> auto) will deduce an undesirable type. We
186 // need the "reference to vector" semantics in this instance.
188 .emplace(this->simulator_.gridView().comm(),
189 FluidSystem::numPhases, rset,
190 [fp = std::cref(this->eclState_.fieldProps())]
191 (const std::string& rsetName) -> decltype(auto)
192 { return fp.get().get_int(rsetName); });
193 }
194 }
195
200 void
201 allocBuffers(const unsigned bufferSize,
202 const unsigned reportStepNum,
203 const bool substep,
204 const bool log,
205 const bool isRestart)
206 {
207 if (! std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
208 return;
209 }
210
211 const auto& problem = this->simulator_.problem();
212
213 this->doAllocBuffers(bufferSize,
214 reportStepNum,
215 substep,
216 log,
217 isRestart,
218 &problem.materialLawManager()->hysteresisConfig(),
219 problem.eclWriter().getOutputNnc().front().size());
220 }
221
223 void setupExtractors(const bool isSubStep,
224 const int reportStepNum)
225 {
226 this->setupElementExtractors_();
227 this->setupBlockExtractors_(isSubStep, reportStepNum);
228 }
229
232 {
233 this->extractors_.clear();
234 this->blockExtractors_.clear();
235 this->extraBlockExtractors_.clear();
236 }
237
242 void processElement(const ElementContext& elemCtx)
243 {
244 OPM_TIMEBLOCK_LOCAL(processElement, Subsystem::Output);
245 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
246 return;
247 }
248
249 if (this->extractors_.empty()) {
250 assert(0);
251 }
252
253 const auto& matLawManager = simulator_.problem().materialLawManager();
254
255 typename Extractor::HysteresisParams hysterParams;
256 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
257 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
258 const auto& fs = intQuants.fluidState();
259
260 const typename Extractor::Context ectx{
261 elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0),
262 elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(),
263 elemCtx.simulator().episodeIndex(),
264 fs,
265 intQuants,
266 hysterParams
267 };
268
269 if (matLawManager->enableHysteresis()) {
270 if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx)) {
271 matLawManager->oilWaterHysteresisParams(hysterParams.somax,
272 hysterParams.swmax,
273 hysterParams.swmin,
274 ectx.globalDofIdx);
275 }
276 if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(gasPhaseIdx)) {
277 matLawManager->gasOilHysteresisParams(hysterParams.sgmax,
278 hysterParams.shmax,
279 hysterParams.somin,
280 ectx.globalDofIdx);
281 }
282 }
283
284 Extractor::process(ectx, extractors_);
285 }
286 }
287
288 void processElementBlockData(const ElementContext& elemCtx)
289 {
290 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
291 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
292 return;
293 }
294
295 if (this->blockExtractors_.empty() && this->extraBlockExtractors_.empty()) {
296 return;
297 }
298
299 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
300 // Adding block data
301 const auto globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
302 const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx);
303
304 const auto be_it = this->blockExtractors_.find(cartesianIdx);
305 const auto bee_it = this->extraBlockExtractors_.find(cartesianIdx);
306 if (be_it == this->blockExtractors_.end() &&
307 bee_it == this->extraBlockExtractors_.end())
308 {
309 continue;
310 }
311
312 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
313 const auto& fs = intQuants.fluidState();
314
315 const typename BlockExtractor::Context ectx{
316 globalDofIdx,
317 dofIdx,
318 fs,
319 intQuants,
320 elemCtx,
321 };
322
323 if (be_it != this->blockExtractors_.end()) {
324 BlockExtractor::process(be_it->second, ectx);
325 }
326 if (bee_it != this->extraBlockExtractors_.end()) {
327 BlockExtractor::process(bee_it->second, ectx);
328 }
329 }
330 }
331
332 void outputFipAndResvLog(const Inplace& inplace,
333 const std::size_t reportStepNum,
334 double elapsed,
335 boost::posix_time::ptime currentDate,
336 const bool substep,
337 const Parallel::Communication& comm)
338 {
339
340 if (comm.rank() != 0) {
341 return;
342 }
343
344 // For report step 0 we use the RPTSOL config, else derive from RPTSCHED
345 std::unique_ptr<FIPConfig> fipSched;
346 if (reportStepNum > 0) {
347 const auto& rpt = this->schedule_[reportStepNum-1].rpt_config.get();
348 fipSched = std::make_unique<FIPConfig>(rpt);
349 }
350 const FIPConfig& fipc = reportStepNum == 0 ? this->eclState_.getEclipseConfig().fip()
351 : *fipSched;
352
353 if (!substep && !this->forceDisableFipOutput_ && fipc.output(FIPConfig::OutputField::FIELD)) {
354
355 this->logOutput_.timeStamp("BALANCE", elapsed, reportStepNum, currentDate);
356
357 const auto& initial_inplace = *this->initialInplace();
358 this->logOutput_.fip(inplace, initial_inplace, "");
359
360 if (fipc.output(FIPConfig::OutputField::FIPNUM)) {
361 this->logOutput_.fip(inplace, initial_inplace, "FIPNUM");
362
363 if (fipc.output(FIPConfig::OutputField::RESV))
364 this->logOutput_.fipResv(inplace, "FIPNUM");
365 }
366
367 if (fipc.output(FIPConfig::OutputField::FIP)) {
368 for (const auto& reg : this->regions_) {
369 if (reg.first != "FIPNUM") {
370 std::ostringstream ss;
371 ss << "BAL" << reg.first.substr(3);
372 this->logOutput_.timeStamp(ss.str(), elapsed, reportStepNum, currentDate);
373 this->logOutput_.fip(inplace, initial_inplace, reg.first);
374
375 if (fipc.output(FIPConfig::OutputField::RESV))
376 this->logOutput_.fipResv(inplace, reg.first);
377 }
378 }
379 }
380 }
381 }
382
383 void outputFipAndResvLogToCSV(const std::size_t reportStepNum,
384 const bool substep,
385 const Parallel::Communication& comm)
386 {
387 if (comm.rank() != 0) {
388 return;
389 }
390
391 if ((reportStepNum == 0) && (!substep) &&
392 (this->schedule_.initialReportConfiguration().has_value()) &&
393 (this->schedule_.initialReportConfiguration()->contains("CSVFIP"))) {
394
395 std::ostringstream csv_stream;
396
397 this->logOutput_.csv_header(csv_stream);
398
399 const auto& initial_inplace = *this->initialInplace();
400
401 this->logOutput_.fip_csv(csv_stream, initial_inplace, "FIPNUM");
402
403 for (const auto& reg : this->regions_) {
404 if (reg.first != "FIPNUM") {
405 this->logOutput_.fip_csv(csv_stream, initial_inplace, reg.first);
406 }
407 }
408
409 const IOConfig& io = this->eclState_.getIOConfig();
410 auto csv_fname = io.getOutputDir() + "/" + io.getBaseName() + ".CSV";
411
412 std::ofstream outputFile(csv_fname);
413
414 outputFile << csv_stream.str();
415
416 outputFile.close();
417 }
418 }
419
448 template <class ActiveIndex, class CartesianIndex>
449 void processFluxes(const ElementContext& elemCtx,
450 ActiveIndex&& activeIndex,
451 CartesianIndex&& cartesianIndex)
452 {
453 OPM_TIMEBLOCK_LOCAL(processFluxes, Subsystem::Output);
454 const auto identifyCell = [&activeIndex, &cartesianIndex](const Element& elem)
456 {
457 const auto cellIndex = activeIndex(elem);
458
459 return {
460 static_cast<int>(cellIndex),
461 cartesianIndex(cellIndex),
462 elem.partitionType() == Dune::InteriorEntity
463 };
464 };
465
466 const auto timeIdx = 0u;
467 const auto& stencil = elemCtx.stencil(timeIdx);
468 const auto numInteriorFaces = elemCtx.numInteriorFaces(timeIdx);
469
470 for (auto scvfIdx = 0 * numInteriorFaces; scvfIdx < numInteriorFaces; ++scvfIdx) {
471 const auto& face = stencil.interiorFace(scvfIdx);
472 const auto left = identifyCell(stencil.element(face.interiorIndex()));
473 const auto right = identifyCell(stencil.element(face.exteriorIndex()));
474
475 const auto rates = this->
476 getComponentSurfaceRates(elemCtx, face.area(), scvfIdx, timeIdx);
477
478 this->interRegionFlows_.addConnection(left, right, rates);
479 }
480 }
481
487 {
488 // Inter-region flow rates. Note: ".clear()" prepares to accumulate
489 // contributions per bulk connection between FIP regions.
490 this->interRegionFlows_.clear();
491 }
492
497 {
499 }
500
505 {
506 return this->interRegionFlows_;
507 }
508
509 template <class FluidState>
510 void assignToFluidState(FluidState& fs, unsigned elemIdx) const
511 {
512 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
513 if (this->saturation_[phaseIdx].empty())
514 continue;
515
516 fs.setSaturation(phaseIdx, this->saturation_[phaseIdx][elemIdx]);
517 }
518
519 if (!this->fluidPressure_.empty()) {
520 // this assumes that capillary pressures only depend on the phase saturations
521 // and possibly on temperature. (this is always the case for ECL problems.)
522 std::array<Scalar, numPhases> pc = {0};
523 const MaterialLawParams& matParams = simulator_.problem().materialLawParams(elemIdx);
524 MaterialLaw::capillaryPressures(pc, matParams, fs);
525 Valgrind::CheckDefined(this->fluidPressure_[elemIdx]);
526 Valgrind::CheckDefined(pc);
527 const auto& pressure = this->fluidPressure_[elemIdx];
528 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
529 if (!FluidSystem::phaseIsActive(phaseIdx))
530 continue;
531
532 if (Indices::oilEnabled)
533 fs.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
534 else if (Indices::gasEnabled)
535 fs.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
536 else if (Indices::waterEnabled)
537 //single (water) phase
538 fs.setPressure(phaseIdx, pressure);
539 }
540 }
541
542 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
543 if (!this->temperature_.empty())
544 fs.setTemperature(this->temperature_[elemIdx]);
545 }
546 if constexpr (enableDissolvedGas) {
547 if (!this->rs_.empty())
548 fs.setRs(this->rs_[elemIdx]);
549 if (!this->rv_.empty())
550 fs.setRv(this->rv_[elemIdx]);
551 }
552 if constexpr (enableDisgasInWater) {
553 if (!this->rsw_.empty())
554 fs.setRsw(this->rsw_[elemIdx]);
555 }
556 if constexpr (enableVapwat) {
557 if (!this->rvw_.empty())
558 fs.setRvw(this->rvw_[elemIdx]);
559 }
560 }
561
562 void initHysteresisParams(Simulator& simulator, unsigned elemIdx) const
563 {
564 if (!this->soMax_.empty())
565 simulator.problem().setMaxOilSaturation(elemIdx, this->soMax_[elemIdx]);
566
567 if (simulator.problem().materialLawManager()->enableHysteresis()) {
568 auto matLawManager = simulator.problem().materialLawManager();
569
570 if (FluidSystem::phaseIsActive(oilPhaseIdx)
571 && FluidSystem::phaseIsActive(waterPhaseIdx)) {
572 Scalar somax = 2.0;
573 Scalar swmax = -2.0;
574 Scalar swmin = 2.0;
575
576 if (matLawManager->enableNonWettingHysteresis()) {
577 if (!this->soMax_.empty()) {
578 somax = this->soMax_[elemIdx];
579 }
580 }
581 if (matLawManager->enableWettingHysteresis()) {
582 if (!this->swMax_.empty()) {
583 swmax = this->swMax_[elemIdx];
584 }
585 }
586 if (matLawManager->enablePCHysteresis()) {
587 if (!this->swmin_.empty()) {
588 swmin = this->swmin_[elemIdx];
589 }
590 }
591 matLawManager->setOilWaterHysteresisParams(
592 somax, swmax, swmin, elemIdx);
593 }
594 if (FluidSystem::phaseIsActive(oilPhaseIdx)
595 && FluidSystem::phaseIsActive(gasPhaseIdx)) {
596 Scalar sgmax = 2.0;
597 Scalar shmax = -2.0;
598 Scalar somin = 2.0;
599
600 if (matLawManager->enableNonWettingHysteresis()) {
601 if (!this->sgmax_.empty()) {
602 sgmax = this->sgmax_[elemIdx];
603 }
604 }
605 if (matLawManager->enableWettingHysteresis()) {
606 if (!this->shmax_.empty()) {
607 shmax = this->shmax_[elemIdx];
608 }
609 }
610 if (matLawManager->enablePCHysteresis()) {
611 if (!this->somin_.empty()) {
612 somin = this->somin_[elemIdx];
613 }
614 }
615 matLawManager->setGasOilHysteresisParams(
616 sgmax, shmax, somin, elemIdx);
617 }
618
619 }
620
621 if (simulator_.vanguard().eclState().fieldProps().has_double("SWATINIT")) {
622 simulator.problem().materialLawManager()
623 ->applyRestartSwatInit(elemIdx, this->ppcw_[elemIdx]);
624 }
625 }
626
627 void updateFluidInPlace(const ElementContext& elemCtx)
628 {
629 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
630 updateFluidInPlace_(elemCtx, dofIdx);
631 }
632 }
633
634 void updateFluidInPlace(const unsigned globalDofIdx,
635 const IntensiveQuantities& intQuants,
636 const double totVolume)
637 {
638 this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
639 }
640
641private:
642 template <typename T>
643 using RemoveCVR = std::remove_cv_t<std::remove_reference_t<T>>;
644
645 template <typename, class = void>
646 struct HasGeoMech : public std::false_type {};
647
648 template <typename Problem>
649 struct HasGeoMech<
650 Problem, std::void_t<decltype(std::declval<Problem>().geoMechModel())>
651 > : public std::true_type {};
652
653 template <typename, class = void>
654 struct HasGeochemistry : public std::false_type {};
655
656 template <typename Problem>
657 struct HasGeochemistry<
658 Problem, std::void_t<decltype(std::declval<Problem>().geochemistryModel())>
659 > : public std::true_type {};
660
661 bool isDefunctParallelWell(const std::string& wname) const override
662 {
663 if (simulator_.gridView().comm().size() == 1)
664 return false;
665 const auto& parallelWells = simulator_.vanguard().parallelWells();
666 std::pair<std::string, bool> value {wname, true};
667 auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value);
668 return candidate == parallelWells.end() || *candidate != value;
669 }
670
671 bool isOwnedByCurrentRank(const std::string& wname) const override
672 {
673 return this->simulator_.problem().wellModel().isOwner(wname);
674 }
675
676 bool isOnCurrentRank(const std::string& wname) const override
677 {
678 return this->simulator_.problem().wellModel().hasLocalCells(wname);
679 }
680
681 void updateFluidInPlace_(const ElementContext& elemCtx, const unsigned dofIdx)
682 {
683 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
684 const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
685 const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx);
686
687 this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
688 }
689
690 void updateFluidInPlace_(const unsigned globalDofIdx,
691 const IntensiveQuantities& intQuants,
692 const double totVolume)
693 {
694 OPM_TIMEBLOCK_LOCAL(updateFluidInPlace, Subsystem::Output);
695
696 this->updateTotalVolumesAndPressures_(globalDofIdx, intQuants, totVolume);
697
698 if (this->computeFip_) {
699 this->updatePhaseInplaceVolumes_(globalDofIdx, intQuants, totVolume);
700 }
701 }
702
703 void createLocalRegion_(std::vector<int>& region)
704 {
705 // For CpGrid with LGRs, where level zero grid has been distributed,
706 // resize region is needed, since in this case the total amount of
707 // element - per process - in level zero grid and leaf grid do not
708 // coincide, in general.
709 region.resize(simulator_.gridView().size(0));
710 std::size_t elemIdx = 0;
711 for (const auto& elem : elements(simulator_.gridView())) {
712 if (elem.partitionType() != Dune::InteriorEntity) {
713 region[elemIdx] = 0;
714 }
715
716 ++elemIdx;
717 }
718 }
719
720 template <typename FluidState>
721 void aggregateAverageDensityContributions_(const FluidState& fs,
722 const unsigned int globalDofIdx,
723 const double porv)
724 {
725 auto pvCellValue = RegionPhasePoreVolAverage::CellValue{};
726 pvCellValue.porv = porv;
727
728 for (auto phaseIdx = 0*FluidSystem::numPhases;
729 phaseIdx < FluidSystem::numPhases; ++phaseIdx)
730 {
731 if (! FluidSystem::phaseIsActive(phaseIdx)) {
732 continue;
733 }
734
735 pvCellValue.value = getValue(fs.density(phaseIdx));
736 pvCellValue.sat = getValue(fs.saturation(phaseIdx));
737
739 ->addCell(globalDofIdx,
741 pvCellValue);
742 }
743 }
744
760 data::InterRegFlowMap::FlowRates
761 getComponentSurfaceRates(const ElementContext& elemCtx,
762 const Scalar faceArea,
763 const std::size_t scvfIdx,
764 const std::size_t timeIdx) const
765 {
766 using Component = data::InterRegFlowMap::Component;
767
768 auto rates = data::InterRegFlowMap::FlowRates {};
769
770 const auto& extQuant = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
771
772 const auto alpha = getValue(extQuant.extrusionFactor()) * faceArea;
773
774 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
775 const auto& up = elemCtx
776 .intensiveQuantities(extQuant.upstreamIndex(oilPhaseIdx), timeIdx);
777
778 const auto pvtReg = up.pvtRegionIndex();
779
780 const auto bO = getValue(getInvB_<FluidSystem, FluidState, Scalar>
781 (up.fluidState(), oilPhaseIdx, pvtReg));
782
783 const auto qO = alpha * bO * getValue(extQuant.volumeFlux(oilPhaseIdx));
784
785 rates[Component::Oil] += qO;
786
787 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
788 const auto Rs = getValue(
789 BlackOil::getRs_<FluidSystem, FluidState, Scalar>
790 (up.fluidState(), pvtReg));
791
792 rates[Component::Gas] += qO * Rs;
793 rates[Component::Disgas] += qO * Rs;
794 }
795 }
796
797 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
798 const auto& up = elemCtx
799 .intensiveQuantities(extQuant.upstreamIndex(gasPhaseIdx), timeIdx);
800
801 const auto pvtReg = up.pvtRegionIndex();
802
803 const auto bG = getValue(getInvB_<FluidSystem, FluidState, Scalar>
804 (up.fluidState(), gasPhaseIdx, pvtReg));
805
806 const auto qG = alpha * bG * getValue(extQuant.volumeFlux(gasPhaseIdx));
807
808 rates[Component::Gas] += qG;
809
810 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
811 const auto Rv = getValue(
812 BlackOil::getRv_<FluidSystem, FluidState, Scalar>
813 (up.fluidState(), pvtReg));
814
815 rates[Component::Oil] += qG * Rv;
816 rates[Component::Vapoil] += qG * Rv;
817 }
818 }
819
820 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
821 const auto& up = elemCtx
822 .intensiveQuantities(extQuant.upstreamIndex(waterPhaseIdx), timeIdx);
823
824 const auto pvtReg = up.pvtRegionIndex();
825
826 const auto bW = getValue(getInvB_<FluidSystem, FluidState, Scalar>
827 (up.fluidState(), waterPhaseIdx, pvtReg));
828
829 rates[Component::Water] +=
830 alpha * bW * getValue(extQuant.volumeFlux(waterPhaseIdx));
831 }
832
833 return rates;
834 }
835
836 template <typename FluidState>
837 Scalar hydroCarbonFraction(const FluidState& fs) const
838 {
839 if (this->eclState_.runspec().co2Storage()) {
840 // CO2 storage: Hydrocarbon volume is full pore-volume.
841 return 1.0;
842 }
843
844 // Common case. Hydrocarbon volume is fraction occupied by actual
845 // hydrocarbons.
846 auto hydrocarbon = Scalar {0};
847 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
848 hydrocarbon += getValue(fs.saturation(oilPhaseIdx));
849 }
850
851 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
852 hydrocarbon += getValue(fs.saturation(gasPhaseIdx));
853 }
854
855 return hydrocarbon;
856 }
857
858 void updateTotalVolumesAndPressures_(const unsigned globalDofIdx,
859 const IntensiveQuantities& intQuants,
860 const double totVolume)
861 {
862 const auto& fs = intQuants.fluidState();
863
864 const double pv = totVolume * intQuants.porosity().value();
865 const auto hydrocarbon = this->hydroCarbonFraction(fs);
866
867 if (! this->hydrocarbonPoreVolume_.empty()) {
868 this->fipC_.assignPoreVolume(globalDofIdx,
869 totVolume * intQuants.referencePorosity());
870
871 this->dynamicPoreVolume_[globalDofIdx] = pv;
872 this->hydrocarbonPoreVolume_[globalDofIdx] = pv * hydrocarbon;
873 }
874
875 if (!this->pressureTimesHydrocarbonVolume_.empty() &&
876 !this->pressureTimesPoreVolume_.empty())
877 {
878 assert(this->hydrocarbonPoreVolume_.size() == this->pressureTimesHydrocarbonVolume_.size());
879 assert(this->fipC_.get(Inplace::Phase::PoreVolume).size() == this->pressureTimesPoreVolume_.size());
880
881 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
882 this->pressureTimesPoreVolume_[globalDofIdx] =
883 getValue(fs.pressure(oilPhaseIdx)) * pv;
884
885 this->pressureTimesHydrocarbonVolume_[globalDofIdx] =
886 this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon;
887 }
888 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
889 this->pressureTimesPoreVolume_[globalDofIdx] =
890 getValue(fs.pressure(gasPhaseIdx)) * pv;
891
892 this->pressureTimesHydrocarbonVolume_[globalDofIdx] =
893 this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon;
894 }
895 else if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
896 this->pressureTimesPoreVolume_[globalDofIdx] =
897 getValue(fs.pressure(waterPhaseIdx)) * pv;
898 }
899 }
900 }
901
902 void updatePhaseInplaceVolumes_(const unsigned globalDofIdx,
903 const IntensiveQuantities& intQuants,
904 const double totVolume)
905 {
906 std::array<Scalar, FluidSystem::numPhases> fip {};
907 std::array<Scalar, FluidSystem::numPhases> fipr{}; // at reservoir condition
908
909 const auto& fs = intQuants.fluidState();
910 const auto pv = totVolume * intQuants.porosity().value();
911
912 for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) {
913 if (!FluidSystem::phaseIsActive(phaseIdx)) {
914 continue;
915 }
916
917 const auto b = getValue(fs.invB(phaseIdx));
918 const auto s = getValue(fs.saturation(phaseIdx));
919
920 fipr[phaseIdx] = s * pv;
921 fip [phaseIdx] = b * fipr[phaseIdx];
922 }
923
924 this->fipC_.assignVolumesSurface(globalDofIdx, fip);
925 this->fipC_.assignVolumesReservoir(globalDofIdx,
926 fs.saltConcentration().value(),
927 fipr);
928
929 if (FluidSystem::phaseIsActive(oilPhaseIdx) &&
930 FluidSystem::phaseIsActive(gasPhaseIdx))
931 {
932 this->updateOilGasDistribution(globalDofIdx, fs, fip);
933 }
934
935 if (FluidSystem::phaseIsActive(waterPhaseIdx) &&
936 FluidSystem::phaseIsActive(gasPhaseIdx))
937 {
938 this->updateGasWaterDistribution(globalDofIdx, fs, fip);
939 }
940
941 if (FluidSystem::phaseIsActive(gasPhaseIdx) &&
942 this->fipC_.hasCo2InGas())
943 {
944 this->updateCO2InGas(globalDofIdx, pv, intQuants);
945 }
946
947 if (this->fipC_.hasCo2InWater() &&
948 (FluidSystem::phaseIsActive(waterPhaseIdx) ||
949 FluidSystem::phaseIsActive(oilPhaseIdx)))
950 {
951 this->updateCO2InWater(globalDofIdx, pv, fs);
952 }
953
954 if constexpr(enableBioeffects) {
955 const auto surfVolWat = pv * getValue(fs.saturation(waterPhaseIdx)) *
956 getValue(fs.invB(waterPhaseIdx));
957 if (this->fipC_.hasMicrobialMass()) {
958 this->updateMicrobialMass(globalDofIdx, intQuants, surfVolWat);
959 }
960 if (this->fipC_.hasBiofilmMass()) {
961 this->updateBiofilmMass(globalDofIdx, intQuants, totVolume);
962 }
963 if constexpr(enableMICP) {
964 if (this->fipC_.hasOxygenMass()) {
965 this->updateOxygenMass(globalDofIdx, intQuants, surfVolWat);
966 }
967 if (this->fipC_.hasUreaMass()) {
968 this->updateUreaMass(globalDofIdx, intQuants, surfVolWat);
969 }
970 if (this->fipC_.hasCalciteMass()) {
971 this->updateCalciteMass(globalDofIdx, intQuants, totVolume);
972 }
973 }
974 }
975
976 if (this->fipC_.hasWaterMass() && FluidSystem::phaseIsActive(waterPhaseIdx))
977 {
978 this->updateWaterMass(globalDofIdx, fs, fip);
979 }
980 }
981
982 template <typename FluidState, typename FIPArray>
983 void updateOilGasDistribution(const unsigned globalDofIdx,
984 const FluidState& fs,
985 const FIPArray& fip)
986 {
987 // Gas dissolved in oil and vaporized oil
988 const auto gasInPlaceLiquid = getValue(fs.Rs()) * fip[oilPhaseIdx];
989 const auto oilInPlaceGas = getValue(fs.Rv()) * fip[gasPhaseIdx];
990
991 this->fipC_.assignOilGasDistribution(globalDofIdx, gasInPlaceLiquid, oilInPlaceGas);
992 }
993
994 template <typename FluidState, typename FIPArray>
995 void updateGasWaterDistribution(const unsigned globalDofIdx,
996 const FluidState& fs,
997 const FIPArray& fip)
998 {
999 // Gas dissolved in water and vaporized water
1000 const auto gasInPlaceWater = getValue(fs.Rsw()) * fip[waterPhaseIdx];
1001 const auto waterInPlaceGas = getValue(fs.Rvw()) * fip[gasPhaseIdx];
1002
1003 this->fipC_.assignGasWater(globalDofIdx, fip, gasInPlaceWater, waterInPlaceGas);
1004 }
1005
1006 template <typename IntensiveQuantities>
1007 void updateCO2InGas(const unsigned globalDofIdx,
1008 const double pv,
1009 const IntensiveQuantities& intQuants)
1010 {
1011 const auto& scaledDrainageInfo = this->simulator_.problem().materialLawManager()
1012 ->oilWaterScaledEpsInfoDrainage(globalDofIdx);
1013
1014 const auto& fs = intQuants.fluidState();
1015 Scalar sgcr = scaledDrainageInfo.Sgcr;
1016 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1017 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1018 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/false);
1019 }
1020
1021 Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr;
1022 if (this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseMaximumTrapped) ||
1023 this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped))
1024 {
1025 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1026 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1027 // Get the maximum trapped gas saturation
1028 trappedGasSaturation = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/true);
1029 }
1030 }
1031
1032 const Scalar sg = getValue(fs.saturation(gasPhaseIdx));
1033 Scalar strandedGasSaturation = scaledDrainageInfo.Sgcr;
1034 if (this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped) ||
1035 this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped))
1036 {
1037 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1038 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1039 const double krg = getValue(intQuants.relativePermeability(gasPhaseIdx));
1040 strandedGasSaturation = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
1041 }
1042 }
1043
1044 const typename FIPContainer<FluidSystem>::Co2InGasInput v{
1045 pv,
1046 sg,
1047 sgcr,
1048 getValue(fs.density(gasPhaseIdx)),
1049 FluidSystem::phaseIsActive(waterPhaseIdx)
1050 ? FluidSystem::convertRvwToXgW(getValue(fs.Rvw()), fs.pvtRegionIndex())
1051 : FluidSystem::convertRvToXgO(getValue(fs.Rv()), fs.pvtRegionIndex()),
1052 FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()),
1053 trappedGasSaturation,
1054 strandedGasSaturation,
1055 };
1056
1057 this->fipC_.assignCo2InGas(globalDofIdx, v);
1058 }
1059
1060 template <typename FluidState>
1061 void updateCO2InWater(const unsigned globalDofIdx,
1062 const double pv,
1063 const FluidState& fs)
1064 {
1065 const auto co2InWater = FluidSystem::phaseIsActive(oilPhaseIdx)
1066 ? this->co2InWaterFromOil(fs, pv)
1067 : this->co2InWaterFromWater(fs, pv);
1068
1069 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1070
1071 this->fipC_.assignCo2InWater(globalDofIdx, co2InWater, mM);
1072 }
1073
1074 template <typename FluidState>
1075 Scalar co2InWaterFromWater(const FluidState& fs, const double pv) const
1076 {
1077 const double rhow = getValue(fs.density(waterPhaseIdx));
1078 const double sw = getValue(fs.saturation(waterPhaseIdx));
1079 const double xwG = FluidSystem::convertRswToXwG(getValue(fs.Rsw()), fs.pvtRegionIndex());
1080
1081 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1082
1083 return xwG * pv * rhow * sw / mM;
1084 }
1085
1086 template <typename FluidState>
1087 Scalar co2InWaterFromOil(const FluidState& fs, const double pv) const
1088 {
1089 const double rhoo = getValue(fs.density(oilPhaseIdx));
1090 const double so = getValue(fs.saturation(oilPhaseIdx));
1091 const double xoG = FluidSystem::convertRsToXoG(getValue(fs.Rs()), fs.pvtRegionIndex());
1092
1093 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1094
1095 return xoG * pv * rhoo * so / mM;
1096 }
1097
1098 template <typename FluidState, typename FIPArray>
1099 void updateWaterMass(const unsigned globalDofIdx,
1100 const FluidState& fs,
1101 const FIPArray& fip
1102 )
1103 {
1104 const Scalar rhoW = FluidSystem::referenceDensity(waterPhaseIdx, fs.pvtRegionIndex());
1105
1106 this->fipC_.assignWaterMass(globalDofIdx, fip, rhoW);
1107 }
1108
1109 template <typename IntensiveQuantities>
1110 void updateMicrobialMass(const unsigned globalDofIdx,
1111 const IntensiveQuantities& intQuants,
1112 const double surfVolWat)
1113 {
1114 const Scalar mass = surfVolWat * intQuants.microbialConcentration().value();
1115
1116 this->fipC_.assignMicrobialMass(globalDofIdx, mass);
1117 }
1118
1119 template <typename IntensiveQuantities>
1120 void updateOxygenMass(const unsigned globalDofIdx,
1121 const IntensiveQuantities& intQuants,
1122 const double surfVolWat)
1123 {
1124 const Scalar mass = surfVolWat * intQuants.oxygenConcentration().value();
1125
1126 this->fipC_.assignOxygenMass(globalDofIdx, mass);
1127 }
1128
1129 template <typename IntensiveQuantities>
1130 void updateUreaMass(const unsigned globalDofIdx,
1131 const IntensiveQuantities& intQuants,
1132 const double surfVolWat)
1133 {
1134 const Scalar mass = surfVolWat * intQuants.ureaConcentration().value();
1135
1136 this->fipC_.assignUreaMass(globalDofIdx, mass);
1137 }
1138
1139 template <typename IntensiveQuantities>
1140 void updateBiofilmMass(const unsigned globalDofIdx,
1141 const IntensiveQuantities& intQuants,
1142 const double totVolume)
1143 {
1144 const Scalar mass = totVolume * intQuants.biofilmMass().value();
1145
1146 this->fipC_.assignBiofilmMass(globalDofIdx, mass);
1147 }
1148
1149 template <typename IntensiveQuantities>
1150 void updateCalciteMass(const unsigned globalDofIdx,
1151 const IntensiveQuantities& intQuants,
1152 const double totVolume)
1153 {
1154 const Scalar mass = totVolume * intQuants.calciteMass().value();
1155
1156 this->fipC_.assignCalciteMass(globalDofIdx, mass);
1157 }
1158
1160 void setupElementExtractors_()
1161 {
1162 using Entry = typename Extractor::Entry;
1163 using Context = typename Extractor::Context;
1164 using ScalarEntry = typename Extractor::ScalarEntry;
1165 using PhaseEntry = typename Extractor::PhaseEntry;
1166
1167 const bool hasResidual = simulator_.model().linearizer().residual().size() > 0;
1168 const auto& hysteresisConfig = simulator_.problem().materialLawManager()->hysteresisConfig();
1169
1170 auto extractors = std::array{
1171 Entry{PhaseEntry{&this->saturation_,
1172 [](const unsigned phase, const Context& ectx)
1173 { return getValue(ectx.fs.saturation(phase)); }
1174 }
1175 },
1176 Entry{PhaseEntry{&this->invB_,
1177 [](const unsigned phase, const Context& ectx)
1178 { return getValue(ectx.fs.invB(phase)); }
1179 }
1180 },
1181 Entry{PhaseEntry{&this->density_,
1182 [](const unsigned phase, const Context& ectx)
1183 { return getValue(ectx.fs.density(phase)); }
1184 }
1185 },
1186 Entry{PhaseEntry{&this->relativePermeability_,
1187 [](const unsigned phase, const Context& ectx)
1188 { return getValue(ectx.intQuants.relativePermeability(phase)); }
1189 }
1190 },
1191 Entry{PhaseEntry{&this->viscosity_,
1192 [this](const unsigned phaseIdx, const Context& ectx)
1193 {
1194 if (this->extboC_.allocated() && phaseIdx == oilPhaseIdx) {
1195 return getValue(ectx.intQuants.oilViscosity());
1196 }
1197 else if (this->extboC_.allocated() && phaseIdx == gasPhaseIdx) {
1198 return getValue(ectx.intQuants.gasViscosity());
1199 }
1200 else {
1201 return getValue(ectx.fs.viscosity(phaseIdx));
1202 }
1203 }
1204 }
1205 },
1206 Entry{PhaseEntry{&this->residual_,
1207 [&modelResid = this->simulator_.model().linearizer().residual()]
1208 (const unsigned phaseIdx, const Context& ectx)
1209 {
1210 const unsigned sIdx = FluidSystem::solventComponentIndex(phaseIdx);
1211 const unsigned activeCompIdx = FluidSystem::canonicalToActiveCompIdx(sIdx);
1212 return modelResid[ectx.globalDofIdx][activeCompIdx];
1213 }
1214 },
1215 hasResidual
1216 },
1217 Entry{ScalarEntry{&this->rockCompPorvMultiplier_,
1218 [&problem = this->simulator_.problem()](const Context& ectx)
1219 {
1220 return problem.template
1221 rockCompPoroMultiplier<Scalar>(ectx.intQuants,
1222 ectx.globalDofIdx);
1223 }
1224 }
1225 },
1226 Entry{ScalarEntry{&this->rockCompTransMultiplier_,
1227 [&problem = this->simulator_.problem()](const Context& ectx)
1228 {
1229 return problem.
1230 template rockCompTransMultiplier<Scalar>(ectx.intQuants,
1231 ectx.globalDofIdx);
1232 }}
1233 },
1234 Entry{ScalarEntry{&this->minimumOilPressure_,
1235 [&problem = this->simulator_.problem()](const Context& ectx)
1236 {
1237 return std::min(getValue(ectx.fs.pressure(oilPhaseIdx)),
1238 problem.minOilPressure(ectx.globalDofIdx));
1239 }
1240 }
1241 },
1242 Entry{ScalarEntry{&this->bubblePointPressure_,
1243 [&failedCells = this->failedCellsPb_,
1244 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1245 {
1246 try {
1247 return getValue(
1248 FluidSystem::bubblePointPressure(ectx.fs,
1249 ectx.intQuants.pvtRegionIndex())
1250 );
1251 } catch (const NumericalProblem&) {
1252 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1253 failedCells.push_back(cartesianIdx);
1254 return Scalar{0};
1255 }
1256 }
1257 }
1258 },
1259 Entry{ScalarEntry{&this->dewPointPressure_,
1260 [&failedCells = this->failedCellsPd_,
1261 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1262 {
1263 try {
1264 return getValue(
1265 FluidSystem::dewPointPressure(ectx.fs,
1266 ectx.intQuants.pvtRegionIndex())
1267 );
1268 } catch (const NumericalProblem&) {
1269 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1270 failedCells.push_back(cartesianIdx);
1271 return Scalar{0};
1272 }
1273 }
1274 }
1275 },
1276 Entry{ScalarEntry{&this->overburdenPressure_,
1277 [&problem = simulator_.problem()](const Context& ectx)
1278 { return problem.overburdenPressure(ectx.globalDofIdx); }
1279 }
1280 },
1281 Entry{ScalarEntry{&this->temperature_,
1282 [](const Context& ectx)
1283 { return getValue(ectx.fs.temperature(oilPhaseIdx)); }
1284 }
1285 },
1286 Entry{ScalarEntry{&this->sSol_,
1287 [](const Context& ectx)
1288 { return getValue(ectx.intQuants.solventSaturation()); }
1289 }
1290 },
1291 Entry{ScalarEntry{&this->rswSol_,
1292 [](const Context& ectx)
1293 { return getValue(ectx.intQuants.rsSolw()); }
1294 }
1295 },
1296 Entry{ScalarEntry{&this->cPolymer_,
1297 [](const Context& ectx)
1298 { return getValue(ectx.intQuants.polymerConcentration()); }
1299 }
1300 },
1301 Entry{ScalarEntry{&this->cFoam_,
1302 [](const Context& ectx)
1303 { return getValue(ectx.intQuants.foamConcentration()); }
1304 }
1305 },
1306 Entry{ScalarEntry{&this->cSalt_,
1307 [](const Context& ectx)
1308 { return getValue(ectx.fs.saltConcentration()); }
1309 }
1310 },
1311 Entry{ScalarEntry{&this->pSalt_,
1312 [](const Context& ectx)
1313 { return getValue(ectx.fs.saltSaturation()); }
1314 }
1315 },
1316 Entry{ScalarEntry{&this->permFact_,
1317 [](const Context& ectx)
1318 { return getValue(ectx.intQuants.permFactor()); }
1319 }
1320 },
1321 Entry{ScalarEntry{&this->rPorV_,
1322 [&model = this->simulator_.model()](const Context& ectx)
1323 {
1324 const auto totVolume = model.dofTotalVolume(ectx.globalDofIdx);
1325 return totVolume * getValue(ectx.intQuants.porosity());
1326 }
1327 }
1328 },
1329 Entry{ScalarEntry{&this->rs_,
1330 [](const Context& ectx)
1331 { return getValue(ectx.fs.Rs()); }
1332 }
1333 },
1334 Entry{ScalarEntry{&this->rv_,
1335 [](const Context& ectx)
1336 { return getValue(ectx.fs.Rv()); }
1337 }
1338 },
1339 Entry{ScalarEntry{&this->rsw_,
1340 [](const Context& ectx)
1341 { return getValue(ectx.fs.Rsw()); }
1342 }
1343 },
1344 Entry{ScalarEntry{&this->rvw_,
1345 [](const Context& ectx)
1346 { return getValue(ectx.fs.Rvw()); }
1347 }
1348 },
1349 Entry{ScalarEntry{&this->ppcw_,
1350 [&matLawManager = *this->simulator_.problem().materialLawManager()]
1351 (const Context& ectx)
1352 {
1353 return matLawManager.
1354 oilWaterScaledEpsInfoDrainage(ectx.globalDofIdx).maxPcow;
1355 }
1356 }
1357 },
1358 Entry{ScalarEntry{&this->drsdtcon_,
1359 [&problem = this->simulator_.problem()](const Context& ectx)
1360 {
1361 return problem.drsdtcon(ectx.globalDofIdx,
1362 ectx.episodeIndex);
1363 }
1364 }
1365 },
1366 Entry{ScalarEntry{&this->pcgw_,
1367 [](const Context& ectx)
1368 {
1369 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
1370 getValue(ectx.fs.pressure(waterPhaseIdx));
1371 }
1372 }
1373 },
1374 Entry{ScalarEntry{&this->pcow_,
1375 [](const Context& ectx)
1376 {
1377 return getValue(ectx.fs.pressure(oilPhaseIdx)) -
1378 getValue(ectx.fs.pressure(waterPhaseIdx));
1379 }
1380 }
1381 },
1382 Entry{ScalarEntry{&this->pcog_,
1383 [](const Context& ectx)
1384 {
1385 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
1386 getValue(ectx.fs.pressure(oilPhaseIdx));
1387 }
1388 }
1389 },
1390 Entry{ScalarEntry{&this->fluidPressure_,
1391 [](const Context& ectx)
1392 {
1393 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1394 // Output oil pressure as default
1395 return getValue(ectx.fs.pressure(oilPhaseIdx));
1396 }
1397 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1398 // Output gas if oil is not present
1399 return getValue(ectx.fs.pressure(gasPhaseIdx));
1400 }
1401 else {
1402 // Output water if neither oil nor gas is present
1403 return getValue(ectx.fs.pressure(waterPhaseIdx));
1404 }
1405 }
1406 }
1407 },
1408 Entry{ScalarEntry{&this->gasDissolutionFactor_,
1409 [&problem = this->simulator_.problem()](const Context& ectx)
1410 {
1411 const Scalar SoMax = problem.maxOilSaturation(ectx.globalDofIdx);
1412 return FluidSystem::template
1413 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1414 oilPhaseIdx,
1415 ectx.pvtRegionIdx,
1416 SoMax);
1417 }
1418 }
1419 },
1420 Entry{ScalarEntry{&this->oilVaporizationFactor_,
1421 [&problem = this->simulator_.problem()](const Context& ectx)
1422 {
1423 const Scalar SoMax = problem.maxOilSaturation(ectx.globalDofIdx);
1424 return FluidSystem::template
1425 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1426 gasPhaseIdx,
1427 ectx.pvtRegionIdx,
1428 SoMax);
1429 }
1430 }
1431 },
1432 Entry{ScalarEntry{&this->gasDissolutionFactorInWater_,
1433 [&problem = this->simulator_.problem()](const Context& ectx)
1434 {
1435 const Scalar SwMax = problem.maxWaterSaturation(ectx.globalDofIdx);
1436 return FluidSystem::template
1437 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1438 waterPhaseIdx,
1439 ectx.pvtRegionIdx,
1440 SwMax);
1441 }
1442 }
1443 },
1444 Entry{ScalarEntry{&this->waterVaporizationFactor_,
1445 [](const Context& ectx)
1446 {
1447 return FluidSystem::template
1448 saturatedVaporizationFactor<FluidState, Scalar>(ectx.fs,
1449 gasPhaseIdx,
1450 ectx.pvtRegionIdx);
1451 }
1452 }
1453 },
1454 Entry{ScalarEntry{&this->gasFormationVolumeFactor_,
1455 [](const Context& ectx)
1456 {
1457 return 1.0 / FluidSystem::template
1458 inverseFormationVolumeFactor<FluidState, Scalar>(ectx.fs,
1459 gasPhaseIdx,
1460 ectx.pvtRegionIdx);
1461 }
1462 }
1463 },
1464 Entry{ScalarEntry{&this->saturatedOilFormationVolumeFactor_,
1465 [](const Context& ectx)
1466 {
1467 return 1.0 / FluidSystem::template
1468 saturatedInverseFormationVolumeFactor<FluidState, Scalar>(ectx.fs,
1469 oilPhaseIdx,
1470 ectx.pvtRegionIdx);
1471 }
1472 }
1473 },
1474 Entry{ScalarEntry{&this->oilSaturationPressure_,
1475 [](const Context& ectx)
1476 {
1477 return FluidSystem::template
1478 saturationPressure<FluidState, Scalar>(ectx.fs,
1479 oilPhaseIdx,
1480 ectx.pvtRegionIdx);
1481 }
1482 }
1483 },
1484 Entry{ScalarEntry{&this->soMax_,
1485 [&problem = this->simulator_.problem()](const Context& ectx)
1486 {
1487 return std::max(getValue(ectx.fs.saturation(oilPhaseIdx)),
1488 problem.maxOilSaturation(ectx.globalDofIdx));
1489 }
1490 },
1491 !hysteresisConfig.enableHysteresis()
1492 },
1493 Entry{ScalarEntry{&this->swMax_,
1494 [&problem = this->simulator_.problem()](const Context& ectx)
1495 {
1496 return std::max(getValue(ectx.fs.saturation(waterPhaseIdx)),
1497 problem.maxWaterSaturation(ectx.globalDofIdx));
1498 }
1499 },
1500 !hysteresisConfig.enableHysteresis()
1501 },
1502 Entry{ScalarEntry{&this->soMax_,
1503 [](const Context& ectx)
1504 { return ectx.hParams.somax; }
1505 },
1506 hysteresisConfig.enableHysteresis() &&
1507 hysteresisConfig.enableNonWettingHysteresis() &&
1508 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1509 FluidSystem::phaseIsActive(waterPhaseIdx)
1510 },
1511 Entry{ScalarEntry{&this->swMax_,
1512 [](const Context& ectx)
1513 { return ectx.hParams.swmax; }
1514 },
1515 hysteresisConfig.enableHysteresis() &&
1516 hysteresisConfig.enableWettingHysteresis() &&
1517 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1518 FluidSystem::phaseIsActive(waterPhaseIdx)
1519 },
1520 Entry{ScalarEntry{&this->swmin_,
1521 [](const Context& ectx)
1522 { return ectx.hParams.swmin; }
1523 },
1524 hysteresisConfig.enableHysteresis() &&
1525 hysteresisConfig.enablePCHysteresis() &&
1526 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1527 FluidSystem::phaseIsActive(waterPhaseIdx)
1528 },
1529 Entry{ScalarEntry{&this->sgmax_,
1530 [](const Context& ectx)
1531 { return ectx.hParams.sgmax; }
1532 },
1533 hysteresisConfig.enableHysteresis() &&
1534 hysteresisConfig.enableNonWettingHysteresis() &&
1535 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1536 FluidSystem::phaseIsActive(gasPhaseIdx)
1537 },
1538 Entry{ScalarEntry{&this->shmax_,
1539 [](const Context& ectx)
1540 { return ectx.hParams.shmax; }
1541 },
1542 hysteresisConfig.enableHysteresis() &&
1543 hysteresisConfig.enableWettingHysteresis() &&
1544 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1545 FluidSystem::phaseIsActive(gasPhaseIdx)
1546 },
1547 Entry{ScalarEntry{&this->somin_,
1548 [](const Context& ectx)
1549 { return ectx.hParams.somin; }
1550 },
1551 hysteresisConfig.enableHysteresis() &&
1552 hysteresisConfig.enablePCHysteresis() &&
1553 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1554 FluidSystem::phaseIsActive(gasPhaseIdx)
1555 },
1556 Entry{[&model = this->simulator_.model(), this](const Context& ectx)
1557 {
1558 // Note: We intentionally exclude effects of rock
1559 // compressibility by using referencePorosity() here.
1560 const auto porv = ectx.intQuants.referencePorosity()
1561 * model.dofTotalVolume(ectx.globalDofIdx);
1562
1563 this->aggregateAverageDensityContributions_(ectx.fs, ectx.globalDofIdx,
1564 static_cast<double>(porv));
1565 }, this->regionAvgDensity_.has_value()
1566 },
1567 Entry{[&extboC = this->extboC_](const Context& ectx)
1568 {
1569 extboC.assignVolumes(ectx.globalDofIdx,
1570 ectx.intQuants.xVolume().value(),
1571 ectx.intQuants.yVolume().value());
1572 extboC.assignZFraction(ectx.globalDofIdx,
1573 ectx.intQuants.zFraction().value());
1574
1575 const Scalar stdVolOil = getValue(ectx.fs.saturation(oilPhaseIdx)) *
1576 getValue(ectx.fs.invB(oilPhaseIdx)) +
1577 getValue(ectx.fs.saturation(gasPhaseIdx)) *
1578 getValue(ectx.fs.invB(gasPhaseIdx)) *
1579 getValue(ectx.fs.Rv());
1580 const Scalar stdVolGas = getValue(ectx.fs.saturation(gasPhaseIdx)) *
1581 getValue(ectx.fs.invB(gasPhaseIdx)) *
1582 (1.0 - ectx.intQuants.yVolume().value()) +
1583 getValue(ectx.fs.saturation(oilPhaseIdx)) *
1584 getValue(ectx.fs.invB(oilPhaseIdx)) *
1585 getValue(ectx.fs.Rs()) *
1586 (1.0 - ectx.intQuants.xVolume().value());
1587 const Scalar stdVolCo2 = getValue(ectx.fs.saturation(gasPhaseIdx)) *
1588 getValue(ectx.fs.invB(gasPhaseIdx)) *
1589 ectx.intQuants.yVolume().value() +
1590 getValue(ectx.fs.saturation(oilPhaseIdx)) *
1591 getValue(ectx.fs.invB(oilPhaseIdx)) *
1592 getValue(ectx.fs.Rs()) *
1593 ectx.intQuants.xVolume().value();
1594 const Scalar rhoO = FluidSystem::referenceDensity(gasPhaseIdx, ectx.pvtRegionIdx);
1595 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx, ectx.pvtRegionIdx);
1596 const Scalar rhoCO2 = ectx.intQuants.zRefDensity();
1597 const Scalar stdMassTotal = 1.0e-10 + stdVolOil * rhoO + stdVolGas * rhoG + stdVolCo2 * rhoCO2;
1598 extboC.assignMassFractions(ectx.globalDofIdx,
1599 stdVolGas * rhoG / stdMassTotal,
1600 stdVolOil * rhoO / stdMassTotal,
1601 stdVolCo2 * rhoCO2 / stdMassTotal);
1602 }, this->extboC_.allocated()
1603 },
1604 Entry{[&bioeffectsC = this->bioeffectsC_](const Context& ectx)
1605 {
1606 bioeffectsC.assign(ectx.globalDofIdx,
1607 ectx.intQuants.microbialConcentration().value(),
1608 ectx.intQuants.biofilmVolumeFraction().value());
1609 if (Indices::enableMICP) {
1610 bioeffectsC.assign(ectx.globalDofIdx,
1611 ectx.intQuants.oxygenConcentration().value(),
1612 ectx.intQuants.ureaConcentration().value(),
1613 ectx.intQuants.calciteVolumeFraction().value());
1614 }
1615 }, this->bioeffectsC_.allocated()
1616 },
1617 Entry{[&runspec = this->eclState_.runspec(),
1618 &CO2H2C = this->CO2H2C_](const Context& ectx)
1619 {
1620 const auto xwg = FluidSystem::convertRswToXwG(getValue(ectx.fs.Rsw()), ectx.pvtRegionIdx);
1621 const auto xgw = FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.pvtRegionIdx);
1622 CO2H2C.assign(ectx.globalDofIdx,
1623 FluidSystem::convertXwGToxwG(xwg, ectx.pvtRegionIdx),
1624 FluidSystem::convertXgWToxgW(xgw, ectx.pvtRegionIdx),
1625 runspec.co2Storage());
1626 }, this->CO2H2C_.allocated()
1627 },
1628 Entry{[&rftC = this->rftC_,
1629 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1630 {
1631 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1632 rftC.assign(cartesianIdx,
1633 [&fs = ectx.fs]() { return getValue(fs.pressure(oilPhaseIdx)); },
1634 [&fs = ectx.fs]() { return getValue(fs.saturation(waterPhaseIdx)); },
1635 [&fs = ectx.fs]() { return getValue(fs.saturation(gasPhaseIdx)); });
1636 }
1637 },
1638 Entry{[&tC = this->tracerC_,
1639 &tM = this->simulator_.problem().tracerModel()](const Context& ectx)
1640 {
1641 tC.assignFreeConcentrations(ectx.globalDofIdx,
1642 [gIdx = ectx.globalDofIdx, &tM](const unsigned tracerIdx)
1643 { return tM.freeTracerConcentration(tracerIdx, gIdx); });
1644 tC.assignSolConcentrations(ectx.globalDofIdx,
1645 [gIdx = ectx.globalDofIdx, &tM](const unsigned tracerIdx)
1646 { return tM.solTracerConcentration(tracerIdx, gIdx); });
1647 }
1648 },
1649 Entry{[&flowsInf = this->simulator_.problem().model().linearizer().getFlowsInfo(),
1650 &flowsC = this->flowsC_,
1651 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1652 {
1653 const auto gas_idx = Indices::gasEnabled ?
1654 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(gasCompIdx) : -1;
1655 const auto oil_idx = Indices::oilEnabled ?
1656 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(oilCompIdx) : -1;
1657 const auto water_idx = Indices::waterEnabled ?
1658 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(waterCompIdx) : -1;
1659 const auto& flowsInfos = flowsInf[ectx.globalDofIdx];
1660 if (!flowsC.blockFlows().empty()) {
1661 const std::vector<int>& blockIdxs = flowsC.blockFlows();
1662 const unsigned cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1663 if (std::ranges::binary_search(blockIdxs, cartesianIdx)) {
1664 const auto compIdxs = std::array{ gasCompIdx, oilCompIdx, waterCompIdx };
1665 const auto compEnabled = std::array{ Indices::gasEnabled, Indices::oilEnabled, Indices::waterEnabled };
1666 for (const auto& flowsInfo : flowsInfos) {
1667 if (flowsInfo.faceId < 0) {
1668 continue;
1669 }
1670 for (unsigned ii = 0; ii < compIdxs.size(); ++ii) {
1671 if (!compEnabled[ii]) {
1672 continue;
1673 }
1674 if (flowsC.hasBlockFlowValue(cartesianIdx, flowsInfo.faceId, compIdxs[ii])) {
1675 flowsC.assignBlockFlows(flowsC.blockFlowsIds(cartesianIdx, flowsInfo.faceId, compIdxs[ii]),
1676 flowsInfo.faceId,
1677 compIdxs[ii],
1678 flowsInfo.flow[conti0EqIdx
1679 + FluidSystem::canonicalToActiveCompIdx(compIdxs[ii])]);
1680 }
1681 }
1682 }
1683 }
1684 }
1685 else {
1686 for (const auto& flowsInfo : flowsInfos) {
1687 flowsC.assignFlows(ectx.globalDofIdx,
1688 flowsInfo.faceId,
1689 flowsInfo.nncId,
1690 value_or_zero(gas_idx, flowsInfo.flow),
1691 value_or_zero(oil_idx, flowsInfo.flow),
1692 value_or_zero(water_idx, flowsInfo.flow));
1693 }
1694 }
1695 }, !this->simulator_.problem().model().linearizer().getFlowsInfo().empty()
1696 },
1697 Entry{[&floresInf = this->simulator_.problem().model().linearizer().getFloresInfo(),
1698 &flowsC = this->flowsC_](const Context& ectx)
1699 {
1700 const auto gas_idx = Indices::gasEnabled ?
1701 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(gasCompIdx) : -1;
1702 const auto oil_idx = Indices::oilEnabled ?
1703 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(oilCompIdx) : -1;
1704 const auto water_idx = Indices::waterEnabled ?
1705 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(waterCompIdx) : -1;
1706 const auto& floresInfos = floresInf[ectx.globalDofIdx];
1707 for (const auto& floresInfo : floresInfos) {
1708 flowsC.assignFlores(ectx.globalDofIdx,
1709 floresInfo.faceId,
1710 floresInfo.nncId,
1711 value_or_zero(gas_idx, floresInfo.flow),
1712 value_or_zero(oil_idx, floresInfo.flow),
1713 value_or_zero(water_idx, floresInfo.flow));
1714 }
1715 }, !this->simulator_.problem().model().linearizer().getFloresInfo().empty()
1716 },
1717 Entry{[&velocityInf = this->simulator_.problem().model().linearizer().getVelocityInfo(),
1718 &flowsC = this->flowsC_,
1719 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1720 {
1721 const auto& velocityInfos = velocityInf[ectx.globalDofIdx];
1722 const std::vector<int>& blockIdxs = flowsC.blockVelocity();
1723 const unsigned cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1724 if (std::ranges::binary_search(blockIdxs, cartesianIdx)) {
1725 const auto compIdxs = std::array{ gasCompIdx, oilCompIdx, waterCompIdx };
1726 const auto compEnabled = std::array{ Indices::gasEnabled, Indices::oilEnabled, Indices::waterEnabled };
1727 for (const auto& velocityInfo : velocityInfos) {
1728 if (velocityInfo.faceId < 0) {
1729 continue;
1730 }
1731 for (unsigned ii = 0; ii < compIdxs.size(); ++ii) {
1732 if (!compEnabled[ii]) {
1733 continue;
1734 }
1735 if (flowsC.hasBlockVelocityValue(cartesianIdx, velocityInfo.faceId, compIdxs[ii])) {
1736 flowsC.assignBlockVelocity(flowsC.blockVelocityIds(cartesianIdx, velocityInfo.faceId, compIdxs[ii]),
1737 velocityInfo.faceId,
1738 compIdxs[ii],
1739 velocityInfo.velocity[conti0EqIdx
1740 + FluidSystem::canonicalToActiveCompIdx(compIdxs[ii])]);
1741 }
1742 }
1743 }
1744 }
1745 }, !this->flowsC_.blockVelocity().empty() &&
1746 !this->simulator_.problem().model().linearizer().getVelocityInfo().empty()
1747 },
1748 // hack to make the intial output of rs and rv Ecl compatible.
1749 // For cells with swat == 1 Ecl outputs; rs = rsSat and rv=rvSat, in all but the initial step
1750 // where it outputs rs and rv values calculated by the initialization. To be compatible we overwrite
1751 // rs and rv with the values computed in the initially.
1752 // Volume factors, densities and viscosities need to be recalculated with the updated rs and rv values.
1753 Entry{ScalarEntry{&this->rv_,
1754 [&problem = this->simulator_.problem()](const Context& ectx)
1755 { return problem.initialFluidState(ectx.globalDofIdx).Rv(); }
1756 },
1757 simulator_.episodeIndex() < 0 &&
1758 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1759 FluidSystem::phaseIsActive(gasPhaseIdx)
1760 },
1761 Entry{ScalarEntry{&this->rs_,
1762 [&problem = this->simulator_.problem()](const Context& ectx)
1763 { return problem.initialFluidState(ectx.globalDofIdx).Rs(); }
1764 },
1765 simulator_.episodeIndex() < 0 &&
1766 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1767 FluidSystem::phaseIsActive(gasPhaseIdx)
1768 },
1769 Entry{ScalarEntry{&this->rsw_,
1770 [&problem = this->simulator_.problem()](const Context& ectx)
1771 { return problem.initialFluidState(ectx.globalDofIdx).Rsw(); }
1772 },
1773 simulator_.episodeIndex() < 0 &&
1774 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1775 FluidSystem::phaseIsActive(gasPhaseIdx)
1776 },
1777 Entry{ScalarEntry{&this->rvw_,
1778 [&problem = this->simulator_.problem()](const Context& ectx)
1779 { return problem.initialFluidState(ectx.globalDofIdx).Rvw(); }
1780 },
1781 simulator_.episodeIndex() < 0 &&
1782 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1783 FluidSystem::phaseIsActive(gasPhaseIdx)
1784 },
1785 // re-compute the volume factors, viscosities and densities if asked for
1786 Entry{PhaseEntry{&this->density_,
1787 [&problem = this->simulator_.problem()](const unsigned phase,
1788 const Context& ectx)
1789 {
1790 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1791 return FluidSystem::density(fsInitial,
1792 phase,
1793 ectx.intQuants.pvtRegionIndex());
1794 }
1795 },
1796 simulator_.episodeIndex() < 0 &&
1797 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1798 FluidSystem::phaseIsActive(gasPhaseIdx)
1799 },
1800 Entry{PhaseEntry{&this->invB_,
1801 [&problem = this->simulator_.problem()](const unsigned phase,
1802 const Context& ectx)
1803 {
1804 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1805 return FluidSystem::inverseFormationVolumeFactor(fsInitial,
1806 phase,
1807 ectx.intQuants.pvtRegionIndex());
1808 }
1809 },
1810 simulator_.episodeIndex() < 0 &&
1811 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1812 FluidSystem::phaseIsActive(gasPhaseIdx)
1813 },
1814 Entry{PhaseEntry{&this->viscosity_,
1815 [&problem = this->simulator_.problem()](const unsigned phase,
1816 const Context& ectx)
1817 {
1818 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1819 return FluidSystem::viscosity(fsInitial,
1820 phase,
1821 ectx.intQuants.pvtRegionIndex());
1822 }
1823 },
1824 simulator_.episodeIndex() < 0 &&
1825 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1826 FluidSystem::phaseIsActive(gasPhaseIdx)
1827 },
1828 };
1829
1830 // Setup active extractors
1831 this->extractors_ = Extractor::removeInactive(extractors);
1832
1833 // Geochemistry
1834 if constexpr (getPropValue<TypeTag, Properties::EnableGeochemistry>()) {
1835 if (this->geochemC_.allocated()) {
1836 this->extractors_.emplace_back(
1837 [&gC = this->geochemC_,
1838 &gM = this->simulator_.problem().geochemistryModel()](const Context& ectx)
1839 {
1840 gC.assignSpeciesConcentrations(
1841 ectx.globalDofIdx,
1842 [gIdx = ectx.globalDofIdx, &gM](const unsigned speciesIdx)
1843 { return gM.speciesConcentration(speciesIdx, gIdx); }
1844 );
1845 gC.assignMineralConcentrations(
1846 ectx.globalDofIdx,
1847 [gIdx = ectx.globalDofIdx, &gM](const unsigned mineralIdx)
1848 { return gM.mineralConcentration(mineralIdx, gIdx); }
1849 );
1850 gC.assignPH(ectx.globalDofIdx, gM.PH(ectx.globalDofIdx));
1851 },
1852 true
1853 );
1854 }
1855 }
1856
1857 // Geomechanics
1858 if constexpr (getPropValue<TypeTag, Properties::EnableMech>()) {
1859 if (this->mech_.allocated()) {
1860 this->extractors_.emplace_back(
1861 [&mech = this->mech_,
1862 &model = simulator_.problem().geoMechModel()](const Context& ectx)
1863 {
1864 mech.assignDelStress(ectx.globalDofIdx,
1865 model.delstress(ectx.globalDofIdx));
1866
1867 mech.assignDisplacement(ectx.globalDofIdx,
1868 model.disp(ectx.globalDofIdx, /*include_fracture*/true));
1869
1870 // is the tresagii stress which make rock fracture
1871 mech.assignFracStress(ectx.globalDofIdx,
1872 model.fractureStress(ectx.globalDofIdx));
1873
1874 mech.assignLinStress(ectx.globalDofIdx,
1875 model.linstress(ectx.globalDofIdx));
1876
1877 mech.assignPotentialForces(ectx.globalDofIdx,
1878 model.mechPotentialForce(ectx.globalDofIdx),
1879 model.mechPotentialPressForce(ectx.globalDofIdx),
1880 model.mechPotentialTempForce(ectx.globalDofIdx));
1881
1882 mech.assignStrain(ectx.globalDofIdx,
1883 model.strain(ectx.globalDofIdx, /*include_fracture*/true));
1884
1885 // Total stress is not stored but calculated result is Voigt notation
1886 mech.assignStress(ectx.globalDofIdx,
1887 model.stress(ectx.globalDofIdx, /*include_fracture*/true));
1888 },
1889 true
1890 );
1891 }
1892 }
1893 }
1894
1896 void setupBlockExtractors_(const bool isSubStep,
1897 const int reportStepNum)
1898 {
1899 using Entry = typename BlockExtractor::Entry;
1900 using Context = typename BlockExtractor::Context;
1901 using PhaseEntry = typename BlockExtractor::PhaseEntry;
1902 using ScalarEntry = typename BlockExtractor::ScalarEntry;
1903
1904 using namespace std::string_view_literals;
1905
1906 const auto pressure_handler =
1907 Entry{ScalarEntry{std::vector{"BPR"sv, "BPRESSUR"sv},
1908 [](const Context& ectx)
1909 {
1910 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1911 return getValue(ectx.fs.pressure(oilPhaseIdx));
1912 }
1913 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1914 return getValue(ectx.fs.pressure(gasPhaseIdx));
1915 }
1916 else { //if (FluidSystem::phaseIsActive(waterPhaseIdx))
1917 return getValue(ectx.fs.pressure(waterPhaseIdx));
1918 }
1919 }
1920 }
1921 };
1922
1923 const auto handlers = std::array{
1924 pressure_handler,
1925 Entry{PhaseEntry{std::array{
1926 std::array{"BWSAT"sv, "BOSAT"sv, "BGSAT"sv},
1927 std::array{"BSWAT"sv, "BSOIL"sv, "BSGAS"sv}
1928 },
1929 [](const unsigned phaseIdx, const Context& ectx)
1930 {
1931 return getValue(ectx.fs.saturation(phaseIdx));
1932 }
1933 }
1934 },
1935 Entry{ScalarEntry{"BNSAT",
1936 [](const Context& ectx)
1937 {
1938 return ectx.intQuants.solventSaturation().value();
1939 }
1940 }
1941 },
1942 Entry{ScalarEntry{std::vector{"BTCNFHEA"sv, "BTEMP"sv},
1943 [](const Context& ectx)
1944 {
1945 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1946 return getValue(ectx.fs.temperature(oilPhaseIdx));
1947 }
1948 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1949 return getValue(ectx.fs.temperature(gasPhaseIdx));
1950 }
1951 else { //if (FluidSystem::phaseIsActive(waterPhaseIdx))
1952 return getValue(ectx.fs.temperature(waterPhaseIdx));
1953 }
1954 }
1955 }
1956 },
1957 Entry{PhaseEntry{std::array{
1958 std::array{"BWKR"sv, "BOKR"sv, "BGKR"sv},
1959 std::array{"BKRW"sv, "BKRO"sv, "BKRG"sv}
1960 },
1961 [](const unsigned phaseIdx, const Context& ectx)
1962 {
1963 return getValue(ectx.intQuants.relativePermeability(phaseIdx));
1964 }
1965 }
1966 },
1967 Entry{ScalarEntry{"BKROG",
1968 [&problem = this->simulator_.problem()](const Context& ectx)
1969 {
1970 const auto& materialParams =
1971 problem.materialLawParams(ectx.elemCtx,
1972 ectx.dofIdx,
1973 /* timeIdx = */ 0);
1974 return getValue(MaterialLaw::template
1975 relpermOilInOilGasSystem<Evaluation>(materialParams,
1976 ectx.fs));
1977 }
1978 }
1979 },
1980 Entry{ScalarEntry{"BKROW",
1981 [&problem = this->simulator_.problem()](const Context& ectx)
1982 {
1983 const auto& materialParams = problem.materialLawParams(ectx.elemCtx,
1984 ectx.dofIdx,
1985 /* timeIdx = */ 0);
1986 return getValue(MaterialLaw::template
1987 relpermOilInOilWaterSystem<Evaluation>(materialParams,
1988 ectx.fs));
1989 }
1990 }
1991 },
1992 Entry{ScalarEntry{"BWPC",
1993 [](const Context& ectx)
1994 {
1995 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1996 return getValue(ectx.fs.pressure(oilPhaseIdx)) -
1997 getValue(ectx.fs.pressure(waterPhaseIdx));
1998 }
1999 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
2000 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
2001 getValue(ectx.fs.pressure(waterPhaseIdx));
2002 }
2003 else {
2004 return Scalar(0.0);
2005 }
2006 }
2007 }
2008 },
2009 Entry{ScalarEntry{"BGPC",
2010 [](const Context& ectx)
2011 {
2012 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2013 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
2014 getValue(ectx.fs.pressure(oilPhaseIdx));
2015 }
2016 else if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
2017 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
2018 getValue(ectx.fs.pressure(waterPhaseIdx));
2019 }
2020 else {
2021 return Scalar(0.0);
2022 }
2023 }
2024 }
2025 },
2026 Entry{ScalarEntry{"BWPR",
2027 [](const Context& ectx)
2028 {
2029 return getValue(ectx.fs.pressure(waterPhaseIdx));
2030 }
2031 }
2032 },
2033 Entry{ScalarEntry{"BGPR",
2034 [](const Context& ectx)
2035 {
2036 return getValue(ectx.fs.pressure(gasPhaseIdx));
2037 }
2038 }
2039 },
2040 Entry{PhaseEntry{std::array{
2041 std::array{"BVWAT"sv, "BVOIL"sv, "BVGAS"sv},
2042 std::array{"BWVIS"sv, "BOVIS"sv, "BGVIS"sv}
2043 },
2044 [](const unsigned phaseIdx, const Context& ectx)
2045 {
2046 return getValue(ectx.fs.viscosity(phaseIdx));
2047 }
2048 }
2049 },
2050 Entry{PhaseEntry{std::array{
2051 std::array{"BWDEN"sv, "BODEN"sv, "BGDEN"sv},
2052 std::array{"BDENW"sv, "BDENO"sv, "BDENG"sv}
2053 },
2054 [](const unsigned phaseIdx, const Context& ectx)
2055 {
2056 return getValue(ectx.fs.density(phaseIdx));
2057 }
2058 }
2059 },
2060 Entry{ScalarEntry{"BFLOGI",
2061 [&flowsC = this->flowsC_,
2062 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2063 {
2064 const unsigned index = !flowsC.blockFlows().empty() ?
2065 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2066 FaceDir::ToIntersectionIndex(Dir::XPlus), gasCompIdx) : ectx.globalDofIdx;
2067 return flowsC.getFlow(index, Dir::XPlus, gasCompIdx);
2068 }
2069 }
2070 },
2071 Entry{ScalarEntry{"BFLOGI-",
2072 [&flowsC = this->flowsC_,
2073 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2074 {
2075 const unsigned index = !flowsC.blockFlows().empty() ?
2076 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2077 FaceDir::ToIntersectionIndex(Dir::XMinus), gasCompIdx) : ectx.globalDofIdx;
2078 return flowsC.getFlow(index, Dir::XMinus, gasCompIdx);
2079 }
2080 }
2081 },
2082 Entry{ScalarEntry{"BFLOGJ",
2083 [&flowsC = this->flowsC_,
2084 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2085 {
2086 const unsigned index = !flowsC.blockFlows().empty() ?
2087 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2088 FaceDir::ToIntersectionIndex(Dir::YPlus), gasCompIdx) : ectx.globalDofIdx;
2089 return flowsC.getFlow(index, Dir::YPlus, gasCompIdx);
2090 }
2091 }
2092 },
2093 Entry{ScalarEntry{"BFLOGJ-",
2094 [&flowsC = this->flowsC_,
2095 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2096 {
2097 const unsigned index = !flowsC.blockFlows().empty() ?
2098 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2099 FaceDir::ToIntersectionIndex(Dir::YMinus), gasCompIdx) : ectx.globalDofIdx;
2100 return flowsC.getFlow(index, Dir::YMinus, gasCompIdx);
2101 }
2102 }
2103 },
2104 Entry{ScalarEntry{"BFLOGK",
2105 [&flowsC = this->flowsC_,
2106 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2107 {
2108 const unsigned index = !flowsC.blockFlows().empty() ?
2109 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2110 FaceDir::ToIntersectionIndex(Dir::ZPlus), gasCompIdx) : ectx.globalDofIdx;
2111 return flowsC.getFlow(index, Dir::ZPlus, gasCompIdx);
2112 }
2113 }
2114 },
2115 Entry{ScalarEntry{"BFLOGK-",
2116 [&flowsC = this->flowsC_,
2117 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2118 {
2119 const unsigned index = !flowsC.blockFlows().empty() ?
2120 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2121 FaceDir::ToIntersectionIndex(Dir::ZMinus), gasCompIdx) : ectx.globalDofIdx;
2122 return flowsC.getFlow(index, Dir::ZMinus, gasCompIdx);
2123 }
2124 }
2125 },
2126 Entry{ScalarEntry{"BFLOOI",
2127 [&flowsC = this->flowsC_,
2128 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2129 {
2130 const unsigned index = !flowsC.blockFlows().empty() ?
2131 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2132 FaceDir::ToIntersectionIndex(Dir::XPlus), oilCompIdx) : ectx.globalDofIdx;
2133 return flowsC.getFlow(index, Dir::XPlus, oilCompIdx);
2134 }
2135 }
2136 },
2137 Entry{ScalarEntry{"BFLOOI-",
2138 [&flowsC = this->flowsC_,
2139 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2140 {
2141 const unsigned index = !flowsC.blockFlows().empty() ?
2142 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2143 FaceDir::ToIntersectionIndex(Dir::XMinus), oilCompIdx) : ectx.globalDofIdx;
2144 return flowsC.getFlow(index, Dir::XMinus, oilCompIdx);
2145 }
2146 }
2147 },
2148 Entry{ScalarEntry{"BFLOOJ",
2149 [&flowsC = this->flowsC_,
2150 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2151 {
2152 const unsigned index = !flowsC.blockFlows().empty() ?
2153 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2154 FaceDir::ToIntersectionIndex(Dir::YPlus), oilCompIdx) : ectx.globalDofIdx;
2155 return flowsC.getFlow(index, Dir::YPlus, oilCompIdx);
2156 }
2157 }
2158 },
2159 Entry{ScalarEntry{"BFLOOJ-",
2160 [&flowsC = this->flowsC_,
2161 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2162 {
2163 const unsigned index = !flowsC.blockFlows().empty() ?
2164 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2165 FaceDir::ToIntersectionIndex(Dir::YMinus), oilCompIdx) : ectx.globalDofIdx;
2166 return flowsC.getFlow(index, Dir::YMinus, oilCompIdx);
2167 }
2168 }
2169 },
2170 Entry{ScalarEntry{"BFLOOK",
2171 [&flowsC = this->flowsC_,
2172 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2173 {
2174 const unsigned index = !flowsC.blockFlows().empty() ?
2175 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2176 FaceDir::ToIntersectionIndex(Dir::ZPlus), oilCompIdx) : ectx.globalDofIdx;
2177 return flowsC.getFlow(index, Dir::ZPlus, oilCompIdx);
2178 }
2179 }
2180 },
2181 Entry{ScalarEntry{"BFLOOK-",
2182 [&flowsC = this->flowsC_,
2183 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2184 {
2185 const unsigned index = !flowsC.blockFlows().empty() ?
2186 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2187 FaceDir::ToIntersectionIndex(Dir::ZMinus), oilCompIdx) : ectx.globalDofIdx;
2188 return flowsC.getFlow(index, Dir::ZMinus, oilCompIdx);
2189 }
2190 }
2191 },
2192 Entry{ScalarEntry{"BFLOWI",
2193 [&flowsC = this->flowsC_,
2194 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2195 {
2196 const unsigned index = !flowsC.blockFlows().empty() ?
2197 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2198 FaceDir::ToIntersectionIndex(Dir::XPlus), waterCompIdx) : ectx.globalDofIdx;
2199 return flowsC.getFlow(index, Dir::XPlus, waterCompIdx);
2200 }
2201 }
2202 },
2203 Entry{ScalarEntry{"BFLOWI-",
2204 [&flowsC = this->flowsC_,
2205 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2206 {
2207 const unsigned index = !flowsC.blockFlows().empty() ?
2208 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2209 FaceDir::ToIntersectionIndex(Dir::XMinus), waterCompIdx) : ectx.globalDofIdx;
2210 return flowsC.getFlow(index, Dir::XMinus, waterCompIdx);
2211 }
2212 }
2213 },
2214 Entry{ScalarEntry{"BFLOWJ",
2215 [&flowsC = this->flowsC_,
2216 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2217 {
2218 const unsigned index = !flowsC.blockFlows().empty() ?
2219 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2220 FaceDir::ToIntersectionIndex(Dir::YPlus), waterCompIdx) : ectx.globalDofIdx;
2221 return flowsC.getFlow(index, Dir::YPlus, waterCompIdx);
2222 }
2223 }
2224 },
2225 Entry{ScalarEntry{"BFLOWJ-",
2226 [&flowsC = this->flowsC_,
2227 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2228 {
2229 const unsigned index = !flowsC.blockFlows().empty() ?
2230 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2231 FaceDir::ToIntersectionIndex(Dir::YMinus), waterCompIdx) : ectx.globalDofIdx;
2232 return flowsC.getFlow(index, Dir::YMinus, waterCompIdx);
2233 }
2234 }
2235 },
2236 Entry{ScalarEntry{"BFLOWK",
2237 [&flowsC = this->flowsC_,
2238 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2239 {
2240 const unsigned index = !flowsC.blockFlows().empty() ?
2241 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2242 FaceDir::ToIntersectionIndex(Dir::ZPlus), waterCompIdx) : ectx.globalDofIdx;
2243 return flowsC.getFlow(index, Dir::ZPlus, waterCompIdx);
2244 }
2245 }
2246 },
2247 Entry{ScalarEntry{"BFLOWK-",
2248 [&flowsC = this->flowsC_,
2249 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2250 {
2251 const unsigned index = !flowsC.blockFlows().empty() ?
2252 flowsC.blockFlowsIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2253 FaceDir::ToIntersectionIndex(Dir::ZMinus), waterCompIdx) : ectx.globalDofIdx;
2254 return flowsC.getFlow(index, Dir::ZMinus, waterCompIdx);
2255 }
2256 }
2257 },
2258 Entry{ScalarEntry{"BVELGI",
2259 [&flowsC = this->flowsC_,
2260 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2261 {
2262 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2263 FaceDir::ToIntersectionIndex(Dir::XPlus), gasCompIdx);
2264 return flowsC.getVelocity(index, Dir::XPlus, gasCompIdx);
2265 }
2266 }
2267 },
2268 Entry{ScalarEntry{"BVELGI-",
2269 [&flowsC = this->flowsC_,
2270 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2271 {
2272 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2273 FaceDir::ToIntersectionIndex(Dir::XMinus), gasCompIdx);
2274 return flowsC.getVelocity(index, Dir::XMinus, gasCompIdx);
2275 }
2276 }
2277 },
2278 Entry{ScalarEntry{"BVELGJ",
2279 [&flowsC = this->flowsC_,
2280 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2281 {
2282 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2283 FaceDir::ToIntersectionIndex(Dir::YPlus), gasCompIdx);
2284 return flowsC.getVelocity(index, Dir::YPlus, gasCompIdx);
2285 }
2286 }
2287 },
2288 Entry{ScalarEntry{"BVELGJ-",
2289 [&flowsC = this->flowsC_,
2290 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2291 {
2292 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2293 FaceDir::ToIntersectionIndex(Dir::YMinus), gasCompIdx);
2294 return flowsC.getVelocity(index, Dir::YMinus, gasCompIdx);
2295 }
2296 }
2297 },
2298 Entry{ScalarEntry{"BVELGK",
2299 [&flowsC = this->flowsC_,
2300 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2301 {
2302 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2303 FaceDir::ToIntersectionIndex(Dir::ZPlus), gasCompIdx);
2304 return flowsC.getVelocity(index, Dir::ZPlus, gasCompIdx);
2305 }
2306 }
2307 },
2308 Entry{ScalarEntry{"BVELGK-",
2309 [&flowsC = this->flowsC_,
2310 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2311 {
2312 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2313 FaceDir::ToIntersectionIndex(Dir::ZMinus), gasCompIdx);
2314 return flowsC.getVelocity(index, Dir::ZMinus, gasCompIdx);
2315 }
2316 }
2317 },
2318 Entry{ScalarEntry{"BVELOI",
2319 [&flowsC = this->flowsC_,
2320 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2321 {
2322 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2323 FaceDir::ToIntersectionIndex(Dir::XPlus), oilCompIdx);
2324 return flowsC.getVelocity(index, Dir::XPlus, oilCompIdx);
2325 }
2326 }
2327 },
2328 Entry{ScalarEntry{"BVELOI-",
2329 [&flowsC = this->flowsC_,
2330 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2331 {
2332 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2333 FaceDir::ToIntersectionIndex(Dir::XMinus), oilCompIdx);
2334 return flowsC.getVelocity(index, Dir::XMinus, oilCompIdx);
2335 }
2336 }
2337 },
2338 Entry{ScalarEntry{"BVELOJ",
2339 [&flowsC = this->flowsC_,
2340 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2341 {
2342 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2343 FaceDir::ToIntersectionIndex(Dir::YPlus), oilCompIdx);
2344 return flowsC.getVelocity(index, Dir::YPlus, oilCompIdx);
2345 }
2346 }
2347 },
2348 Entry{ScalarEntry{"BVELOJ-",
2349 [&flowsC = this->flowsC_,
2350 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2351 {
2352 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2353 FaceDir::ToIntersectionIndex(Dir::YMinus), oilCompIdx);
2354 return flowsC.getVelocity(index, Dir::YMinus, oilCompIdx);
2355 }
2356 }
2357 },
2358 Entry{ScalarEntry{"BVELOK",
2359 [&flowsC = this->flowsC_,
2360 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2361 {
2362 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2363 FaceDir::ToIntersectionIndex(Dir::ZPlus), oilCompIdx);
2364 return flowsC.getVelocity(index, Dir::ZPlus, oilCompIdx);
2365 }
2366 }
2367 },
2368 Entry{ScalarEntry{"BVELOK-",
2369 [&flowsC = this->flowsC_,
2370 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2371 {
2372 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2373 FaceDir::ToIntersectionIndex(Dir::ZMinus), oilCompIdx);
2374 return flowsC.getVelocity(index, Dir::ZMinus, oilCompIdx);
2375 }
2376 }
2377 },
2378 Entry{ScalarEntry{"BVELWI",
2379 [&flowsC = this->flowsC_,
2380 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2381 {
2382 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2383 FaceDir::ToIntersectionIndex(Dir::XPlus), waterCompIdx);
2384 return flowsC.getVelocity(index, Dir::XPlus, waterCompIdx);
2385 }
2386 }
2387 },
2388 Entry{ScalarEntry{"BVELWI-",
2389 [&flowsC = this->flowsC_,
2390 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2391 {
2392 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2393 FaceDir::ToIntersectionIndex(Dir::XMinus), waterCompIdx);
2394 return flowsC.getVelocity(index, Dir::XMinus, waterCompIdx);
2395 }
2396 }
2397 },
2398 Entry{ScalarEntry{"BVELWJ",
2399 [&flowsC = this->flowsC_,
2400 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2401 {
2402 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2403 FaceDir::ToIntersectionIndex(Dir::YPlus), waterCompIdx);
2404 return flowsC.getVelocity(index, Dir::YPlus, waterCompIdx);
2405 }
2406 }
2407 },
2408 Entry{ScalarEntry{"BVELWJ-",
2409 [&flowsC = this->flowsC_,
2410 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2411 {
2412 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2413 FaceDir::ToIntersectionIndex(Dir::YMinus), waterCompIdx);
2414 return flowsC.getVelocity(index, Dir::YMinus, waterCompIdx);
2415 }
2416 }
2417 },
2418 Entry{ScalarEntry{"BVELWK",
2419 [&flowsC = this->flowsC_,
2420 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2421 {
2422 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2423 FaceDir::ToIntersectionIndex(Dir::ZPlus), waterCompIdx);
2424 return flowsC.getVelocity(index, Dir::ZPlus, waterCompIdx);
2425 }
2426 }
2427 },
2428 Entry{ScalarEntry{"BVELWK-",
2429 [&flowsC = this->flowsC_,
2430 &vanguard = this->simulator_.vanguard()](const Context& ectx)
2431 {
2432 const unsigned index = flowsC.blockVelocityIds(vanguard.cartesianIndex(ectx.globalDofIdx),
2433 FaceDir::ToIntersectionIndex(Dir::ZMinus), waterCompIdx);
2434 return flowsC.getVelocity(index, Dir::ZMinus, waterCompIdx);
2435 }
2436 }
2437 },
2438 Entry{ScalarEntry{"BRPV",
2439 [&model = this->simulator_.model()](const Context& ectx)
2440 {
2441 return getValue(ectx.intQuants.porosity()) *
2442 model.dofTotalVolume(ectx.globalDofIdx);
2443 }
2444 }
2445 },
2446 Entry{PhaseEntry{std::array{"BWPV"sv, "BOPV"sv, "BGPV"sv},
2447 [&model = this->simulator_.model()](const unsigned phaseIdx,
2448 const Context& ectx)
2449 {
2450 return getValue(ectx.fs.saturation(phaseIdx)) *
2451 getValue(ectx.intQuants.porosity()) *
2452 model.dofTotalVolume(ectx.globalDofIdx);
2453 }
2454 }
2455 },
2456 Entry{ScalarEntry{"BRS",
2457 [](const Context& ectx)
2458 {
2459 return getValue(ectx.fs.Rs());
2460 }
2461 }
2462 },
2463 Entry{ScalarEntry{"BRV",
2464 [](const Context& ectx)
2465 {
2466 return getValue(ectx.fs.Rv());
2467 }
2468 }
2469 },
2470 Entry{ScalarEntry{"BOIP",
2471 [&model = this->simulator_.model()](const Context& ectx)
2472 {
2473 return (getValue(ectx.fs.invB(oilPhaseIdx)) *
2474 getValue(ectx.fs.saturation(oilPhaseIdx)) +
2475 getValue(ectx.fs.Rv()) *
2476 getValue(ectx.fs.invB(gasPhaseIdx)) *
2477 getValue(ectx.fs.saturation(gasPhaseIdx))) *
2478 model.dofTotalVolume(ectx.globalDofIdx) *
2479 getValue(ectx.intQuants.porosity());
2480 }
2481 }
2482 },
2483 Entry{ScalarEntry{"BGIP",
2484 [&model = this->simulator_.model()](const Context& ectx)
2485 {
2486 Scalar result = getValue(ectx.fs.invB(gasPhaseIdx)) *
2487 getValue(ectx.fs.saturation(gasPhaseIdx));
2488
2489 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2490 result += getValue(ectx.fs.Rs()) *
2491 getValue(ectx.fs.invB(oilPhaseIdx)) *
2492 getValue(ectx.fs.saturation(oilPhaseIdx));
2493 }
2494 else {
2495 result += getValue(ectx.fs.Rsw()) *
2496 getValue(ectx.fs.invB(waterPhaseIdx)) *
2497 getValue(ectx.fs.saturation(waterPhaseIdx));
2498 }
2499
2500 return result *
2501 model.dofTotalVolume(ectx.globalDofIdx) *
2502 getValue(ectx.intQuants.porosity());
2503 }
2504 }
2505 },
2506 Entry{ScalarEntry{"BWIP",
2507 [&model = this->simulator_.model()](const Context& ectx)
2508 {
2509 return getValue(ectx.fs.invB(waterPhaseIdx)) *
2510 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2511 model.dofTotalVolume(ectx.globalDofIdx) *
2512 getValue(ectx.intQuants.porosity());
2513 }
2514 }
2515 },
2516 Entry{ScalarEntry{"BOIPL",
2517 [&model = this->simulator_.model()](const Context& ectx)
2518 {
2519 return getValue(ectx.fs.invB(oilPhaseIdx)) *
2520 getValue(ectx.fs.saturation(oilPhaseIdx)) *
2521 model.dofTotalVolume(ectx.globalDofIdx) *
2522 getValue(ectx.intQuants.porosity());
2523 }
2524 }
2525 },
2526 Entry{ScalarEntry{"BGIPL",
2527 [&model = this->simulator_.model()](const Context& ectx)
2528 {
2529 Scalar result;
2530 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2531 result = getValue(ectx.fs.Rs()) *
2532 getValue(ectx.fs.invB(oilPhaseIdx)) *
2533 getValue(ectx.fs.saturation(oilPhaseIdx));
2534 }
2535 else {
2536 result = getValue(ectx.fs.Rsw()) *
2537 getValue(ectx.fs.invB(waterPhaseIdx)) *
2538 getValue(ectx.fs.saturation(waterPhaseIdx));
2539 }
2540 return result *
2541 model.dofTotalVolume(ectx.globalDofIdx) *
2542 getValue(ectx.intQuants.porosity());
2543 }
2544 }
2545 },
2546 Entry{ScalarEntry{"BGIPG",
2547 [&model = this->simulator_.model()](const Context& ectx)
2548 {
2549 return getValue(ectx.fs.invB(gasPhaseIdx)) *
2550 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2551 model.dofTotalVolume(ectx.globalDofIdx) *
2552 getValue(ectx.intQuants.porosity());
2553 }
2554 }
2555 },
2556 Entry{ScalarEntry{"BOIPG",
2557 [&model = this->simulator_.model()](const Context& ectx)
2558 {
2559 return getValue(ectx.fs.Rv()) *
2560 getValue(ectx.fs.invB(gasPhaseIdx)) *
2561 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2562 model.dofTotalVolume(ectx.globalDofIdx) *
2563 getValue(ectx.intQuants.porosity());
2564 }
2565 }
2566 },
2567 Entry{PhaseEntry{std::array{"BPPW"sv, "BPPO"sv, "BPPG"sv},
2568 [&simConfig = this->eclState_.getSimulationConfig(),
2569 &grav = this->simulator_.problem().gravity(),
2570 &regionAvgDensity = this->regionAvgDensity_,
2571 &problem = this->simulator_.problem(),
2572 &regions = this->regions_](const unsigned phaseIdx, const Context& ectx)
2573 {
2574 auto phase = RegionPhasePoreVolAverage::Phase{};
2575 phase.ix = phaseIdx;
2576
2577 // Note different region handling here. FIPNUM is
2578 // one-based, but we need zero-based lookup in
2579 // DatumDepth. On the other hand, pvtRegionIndex is
2580 // zero-based but we need one-based lookup in
2581 // RegionPhasePoreVolAverage.
2582
2583 // Subtract one to convert FIPNUM to region index.
2584 const auto datum = simConfig.datumDepths()(regions["FIPNUM"][ectx.dofIdx] - 1);
2585
2586 // Add one to convert region index to region ID.
2587 const auto region = RegionPhasePoreVolAverage::Region {
2588 ectx.elemCtx.primaryVars(ectx.dofIdx, /*timeIdx=*/0).pvtRegionIndex() + 1
2589 };
2590
2591 const auto density = regionAvgDensity->value("PVTNUM", phase, region);
2592
2593 const auto press = getValue(ectx.fs.pressure(phase.ix));
2594 const auto dz = problem.dofCenterDepth(ectx.globalDofIdx) - datum;
2595 return press - density*dz*grav[GridView::dimensionworld - 1];
2596 }
2597 }
2598 },
2599 Entry{ScalarEntry{"BAMIP",
2600 [&model = this->simulator_.model()](const Context& ectx)
2601 {
2602 const Scalar rhoW = FluidSystem::referenceDensity(waterPhaseIdx,
2603 ectx.intQuants.pvtRegionIndex());
2604 return getValue(ectx.fs.invB(waterPhaseIdx)) *
2605 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2606 rhoW *
2607 model.dofTotalVolume(ectx.globalDofIdx) *
2608 getValue(ectx.intQuants.porosity());
2609 }
2610 }
2611 },
2612 Entry{ScalarEntry{"BMMIP",
2613 [&model = this->simulator_.model()](const Context& ectx)
2614 {
2615 return getValue(ectx.intQuants.microbialConcentration()) *
2616 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2617 getValue(ectx.intQuants.porosity()) *
2618 model.dofTotalVolume(ectx.globalDofIdx);
2619 }
2620 }
2621 },
2622 Entry{ScalarEntry{"BMOIP",
2623 [&model = this->simulator_.model()](const Context& ectx)
2624 {
2625 return getValue(ectx.intQuants.oxygenConcentration()) *
2626 getValue(ectx.intQuants.porosity()) *
2627 model.dofTotalVolume(ectx.globalDofIdx);
2628 }
2629 }
2630 },
2631 Entry{ScalarEntry{"BMUIP",
2632 [&model = this->simulator_.model()](const Context& ectx)
2633 {
2634 return getValue(ectx.intQuants.ureaConcentration()) *
2635 getValue(ectx.intQuants.porosity()) *
2636 model.dofTotalVolume(ectx.globalDofIdx) * 1;
2637 }
2638 }
2639 },
2640 Entry{ScalarEntry{"BMBIP",
2641 [&model = this->simulator_.model()](const Context& ectx)
2642 {
2643 return model.dofTotalVolume(ectx.globalDofIdx) *
2644 getValue(ectx.intQuants.biofilmMass());
2645 }
2646 }
2647 },
2648 Entry{ScalarEntry{"BMCIP",
2649 [&model = this->simulator_.model()](const Context& ectx)
2650 {
2651 return model.dofTotalVolume(ectx.globalDofIdx) *
2652 getValue(ectx.intQuants.calciteMass());
2653 }
2654 }
2655 },
2656 Entry{ScalarEntry{"BGMIP",
2657 [&model = this->simulator_.model()](const Context& ectx)
2658 {
2659 Scalar result = getValue(ectx.fs.invB(gasPhaseIdx)) *
2660 getValue(ectx.fs.saturation(gasPhaseIdx));
2661
2662 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2663 result += getValue(ectx.fs.Rs()) *
2664 getValue(ectx.fs.invB(oilPhaseIdx)) *
2665 getValue(ectx.fs.saturation(oilPhaseIdx));
2666 }
2667 else {
2668 result += getValue(ectx.fs.Rsw()) *
2669 getValue(ectx.fs.invB(waterPhaseIdx)) *
2670 getValue(ectx.fs.saturation(waterPhaseIdx));
2671 }
2672 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2673 ectx.intQuants.pvtRegionIndex());
2674 return result *
2675 model.dofTotalVolume(ectx.globalDofIdx) *
2676 getValue(ectx.intQuants.porosity()) *
2677 rhoG;
2678 }
2679 }
2680 },
2681 Entry{ScalarEntry{"BGMGP",
2682 [&model = this->simulator_.model()](const Context& ectx)
2683 {
2684 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2685 ectx.intQuants.pvtRegionIndex());
2686 return getValue(ectx.fs.invB(gasPhaseIdx)) *
2687 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2688 model.dofTotalVolume(ectx.globalDofIdx) *
2689 getValue(ectx.intQuants.porosity()) *
2690 rhoG;
2691 }
2692 }
2693 },
2694 Entry{ScalarEntry{"BGMDS",
2695 [&model = this->simulator_.model()](const Context& ectx)
2696 {
2697 Scalar result;
2698 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2699 result = getValue(ectx.fs.Rs()) *
2700 getValue(ectx.fs.invB(oilPhaseIdx)) *
2701 getValue(ectx.fs.saturation(oilPhaseIdx));
2702 }
2703 else {
2704 result = getValue(ectx.fs.Rsw()) *
2705 getValue(ectx.fs.invB(waterPhaseIdx)) *
2706 getValue(ectx.fs.saturation(waterPhaseIdx));
2707 }
2708 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2709 ectx.intQuants.pvtRegionIndex());
2710 return result *
2711 model.dofTotalVolume(ectx.globalDofIdx) *
2712 getValue(ectx.intQuants.porosity()) *
2713 rhoG;
2714 }
2715 }
2716 },
2717 Entry{ScalarEntry{"BGMST",
2718 [&model = this->simulator_.model(),
2719 &problem = this->simulator_.problem()](const Context& ectx)
2720 {
2721 const auto& scaledDrainageInfo = problem.materialLawManager()
2722 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2723 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2724 Scalar strandedGas = scaledDrainageInfo.Sgcr;
2725 if (problem.materialLawManager()->enableHysteresis()) {
2726 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2727 const Scalar krg = getValue(ectx.intQuants.relativePermeability(gasPhaseIdx));
2728 strandedGas = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
2729 }
2730 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2731 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2732 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2733 return (1.0 - xgW) *
2734 model.dofTotalVolume(ectx.globalDofIdx) *
2735 getValue(ectx.intQuants.porosity()) *
2736 getValue(ectx.fs.density(gasPhaseIdx)) *
2737 std::min(strandedGas, sg);
2738 }
2739 }
2740 },
2741 Entry{ScalarEntry{"BGMUS",
2742 [&model = this->simulator_.model(),
2743 &problem = this->simulator_.problem()](const Context& ectx)
2744 {
2745 const auto& scaledDrainageInfo = problem.materialLawManager()
2746 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2747 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2748 Scalar strandedGas = scaledDrainageInfo.Sgcr;
2749 if (problem.materialLawManager()->enableHysteresis()) {
2750 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2751 const Scalar krg = getValue(ectx.intQuants.relativePermeability(gasPhaseIdx));
2752 strandedGas = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
2753 }
2754 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2755 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2756 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2757 return (1.0 - xgW) *
2758 model.dofTotalVolume(ectx.globalDofIdx) *
2759 getValue(ectx.intQuants.porosity()) *
2760 getValue(ectx.fs.density(gasPhaseIdx)) *
2761 std::max(Scalar{0.0}, sg - strandedGas);
2762 }
2763 }
2764 },
2765 Entry{ScalarEntry{"BGMTR",
2766 [&model = this->simulator_.model(),
2767 &problem = this->simulator_.problem()](const Context& ectx)
2768 {
2769 const auto& scaledDrainageInfo = problem.materialLawManager()
2770 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2771 Scalar trappedGas = scaledDrainageInfo.Sgcr;
2772 if (problem.materialLawManager()->enableHysteresis()) {
2773 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2774 trappedGas = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/true);
2775 }
2776 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2777 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2778 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2779 return (1.0 - xgW) *
2780 model.dofTotalVolume(ectx.globalDofIdx) *
2781 getValue(ectx.intQuants.porosity()) *
2782 getValue(ectx.fs.density(gasPhaseIdx)) *
2783 std::min(trappedGas, getValue(ectx.fs.saturation(gasPhaseIdx)));
2784 }
2785 }
2786 },
2787 Entry{ScalarEntry{"BGMMO",
2788 [&model = this->simulator_.model(),
2789 &problem = this->simulator_.problem()](const Context& ectx)
2790 {
2791 const auto& scaledDrainageInfo = problem.materialLawManager()
2792 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2793 Scalar trappedGas = scaledDrainageInfo.Sgcr;
2794 if (problem.materialLawManager()->enableHysteresis()) {
2795 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2796 trappedGas = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/true);
2797 }
2798 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2799 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2800 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2801 return (1.0 - xgW) *
2802 model.dofTotalVolume(ectx.globalDofIdx) *
2803 getValue(ectx.intQuants.porosity()) *
2804 getValue(ectx.fs.density(gasPhaseIdx)) *
2805 std::max(Scalar{0.0}, getValue(ectx.fs.saturation(gasPhaseIdx)) - trappedGas);
2806 }
2807 }
2808 },
2809 Entry{ScalarEntry{"BGKTR",
2810 [&model = this->simulator_.model(),
2811 &problem = this->simulator_.problem()](const Context& ectx)
2812 {
2813 const auto& scaledDrainageInfo = problem.materialLawManager()
2814 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2815 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2816 Scalar sgcr = scaledDrainageInfo.Sgcr;
2817 if (problem.materialLawManager()->enableHysteresis()) {
2818 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2819 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2820 }
2821 if (sg > sgcr) {
2822 return 0.0;
2823 }
2824 else {
2825 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2826 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2827 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2828 return (1.0 - xgW) *
2829 model.dofTotalVolume(ectx.globalDofIdx) *
2830 getValue(ectx.intQuants.porosity()) *
2831 getValue(ectx.fs.density(gasPhaseIdx)) *
2832 getValue(ectx.fs.saturation(gasPhaseIdx));
2833 }
2834 }
2835 }
2836 },
2837 Entry{ScalarEntry{"BGKMO",
2838 [&model = this->simulator_.model(),
2839 &problem = this->simulator_.problem()](const Context& ectx)
2840 {
2841 const auto& scaledDrainageInfo = problem.materialLawManager()
2842 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2843 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2844 Scalar sgcr = scaledDrainageInfo.Sgcr;
2845 if (problem.materialLawManager()->enableHysteresis()) {
2846 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2847 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2848 }
2849 if (sgcr >= sg) {
2850 return 0.0;
2851 }
2852 else {
2853 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2854 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2855 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2856 return (1.0 - xgW) *
2857 model.dofTotalVolume(ectx.globalDofIdx) *
2858 getValue(ectx.intQuants.porosity()) *
2859 getValue(ectx.fs.density(gasPhaseIdx)) *
2860 getValue(ectx.fs.saturation(gasPhaseIdx));
2861 }
2862 }
2863 }
2864 },
2865 Entry{ScalarEntry{"BGCDI",
2866 [&model = this->simulator_.model(),
2867 &problem = this->simulator_.problem()](const Context& ectx)
2868 {
2869 const auto& scaledDrainageInfo = problem.materialLawManager()
2870 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2871 Scalar sgcr = scaledDrainageInfo.Sgcr;
2872 if (problem.materialLawManager()->enableHysteresis()) {
2873 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2874 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2875 }
2876 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2877 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2878 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2879 return (1.0 - xgW) *
2880 model.dofTotalVolume(ectx.globalDofIdx) *
2881 getValue(ectx.intQuants.porosity()) *
2882 getValue(ectx.fs.density(gasPhaseIdx)) *
2883 std::min(sgcr, getValue(ectx.fs.saturation(gasPhaseIdx))) /
2884 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2885 }
2886 }
2887 },
2888 Entry{ScalarEntry{"BGCDM",
2889 [&model = this->simulator_.model(),
2890 &problem = this->simulator_.problem()](const Context& ectx)
2891 {
2892 const auto& scaledDrainageInfo = problem.materialLawManager()
2893 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2894 Scalar sgcr = scaledDrainageInfo.Sgcr;
2895 if (problem.materialLawManager()->enableHysteresis()) {
2896 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2897 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2898 }
2899 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2900 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2901 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2902 return (1.0 - xgW) *
2903 model.dofTotalVolume(ectx.globalDofIdx) *
2904 getValue(ectx.intQuants.porosity()) *
2905 getValue(ectx.fs.density(gasPhaseIdx)) *
2906 std::max(Scalar{0.0}, getValue(ectx.fs.saturation(gasPhaseIdx)) - sgcr) /
2907 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2908 }
2909 }
2910 },
2911 Entry{ScalarEntry{"BGKDI",
2912 [&model = this->simulator_.model(),
2913 &problem = this->simulator_.problem()](const Context& ectx)
2914 {
2915 const auto& scaledDrainageInfo = problem.materialLawManager()
2916 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2917 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2918 Scalar sgcr = scaledDrainageInfo.Sgcr;
2919 if (problem.materialLawManager()->enableHysteresis()) {
2920 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2921 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2922 }
2923 if (sg > sgcr) {
2924 return 0.0;
2925 }
2926 else {
2927 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2928 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2929 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2930 return (1.0 - xgW) *
2931 model.dofTotalVolume(ectx.globalDofIdx) *
2932 getValue(ectx.intQuants.porosity()) *
2933 getValue(ectx.fs.density(gasPhaseIdx)) *
2934 getValue(ectx.fs.saturation(gasPhaseIdx)) /
2935 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2936 }
2937 }
2938 }
2939 },
2940 Entry{ScalarEntry{"BGKDM",
2941 [&model = this->simulator_.model(),
2942 &problem = this->simulator_.problem()](const Context& ectx)
2943 {
2944 const auto& scaledDrainageInfo = problem.materialLawManager()
2945 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2946 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2947 Scalar sgcr = scaledDrainageInfo.Sgcr;
2948 if (problem.materialLawManager()->enableHysteresis()) {
2949 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2950 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2951 }
2952 if (sgcr >= sg) {
2953 return 0.0;
2954 }
2955 else {
2956 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2957 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2958 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2959 return (1.0 - xgW) *
2960 model.dofTotalVolume(ectx.globalDofIdx) *
2961 getValue(ectx.intQuants.porosity()) *
2962 getValue(ectx.fs.density(gasPhaseIdx)) *
2963 getValue(ectx.fs.saturation(gasPhaseIdx)) /
2964 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2965 }
2966 }
2967 }
2968 },
2969 Entry{ScalarEntry{"BWCD",
2970 [&model = this->simulator_.model()](const Context& ectx)
2971 {
2972 Scalar result;
2973 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2974 result = getValue(ectx.fs.Rs()) *
2975 getValue(ectx.fs.invB(oilPhaseIdx)) *
2976 getValue(ectx.fs.saturation(oilPhaseIdx));
2977 }
2978 else {
2979 result = getValue(ectx.fs.Rsw()) *
2980 getValue(ectx.fs.invB(waterPhaseIdx)) *
2981 getValue(ectx.fs.saturation(waterPhaseIdx));
2982 }
2983 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2984 ectx.intQuants.pvtRegionIndex());
2985 return result *
2986 model.dofTotalVolume(ectx.globalDofIdx) *
2987 getValue(ectx.intQuants.porosity()) *
2988 rhoG /
2989 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2990 }
2991 }
2992 },
2993 Entry{ScalarEntry{"BWIPG",
2994 [&model = this->simulator_.model()](const Context& ectx)
2995 {
2996 Scalar result = 0.0;
2997 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
2998 result = getValue(ectx.fs.Rvw()) *
2999 getValue(ectx.fs.invB(gasPhaseIdx)) *
3000 getValue(ectx.fs.saturation(gasPhaseIdx));
3001 }
3002 return result *
3003 model.dofTotalVolume(ectx.globalDofIdx) *
3004 getValue(ectx.intQuants.porosity());
3005 }
3006 }
3007 },
3008 Entry{ScalarEntry{"BWIPL",
3009 [&model = this->simulator_.model()](const Context& ectx)
3010 {
3011 return getValue(ectx.fs.invB(waterPhaseIdx)) *
3012 getValue(ectx.fs.saturation(waterPhaseIdx)) *
3013 model.dofTotalVolume(ectx.globalDofIdx) *
3014 getValue(ectx.intQuants.porosity());
3015 }
3016 }
3017 },
3018 };
3019
3020 this->blockExtractors_ = BlockExtractor::setupExecMap(this->blockData_, handlers);
3021
3022 this->extraBlockData_.clear();
3023 if (reportStepNum > 0 && !isSubStep) {
3024 // check we need extra block pressures for RPTSCHED
3025 const auto& rpt = this->schedule_[reportStepNum - 1].rpt_config.get();
3026 if (rpt.contains("WELLS") && rpt.at("WELLS") > 1) {
3027 this->setupExtraBlockData(reportStepNum,
3028 [&c = this->collectOnIORank_](const int idx)
3029 { return c.isCartIdxOnThisRank(idx); });
3030
3031 const auto extraHandlers = std::array{
3032 pressure_handler,
3033 };
3034
3035 this->extraBlockExtractors_ = BlockExtractor::setupExecMap(this->extraBlockData_, extraHandlers);
3036 }
3037 }
3038 }
3039
3040 const Simulator& simulator_;
3041 const CollectDataOnIORankType& collectOnIORank_;
3042 std::vector<typename Extractor::Entry> extractors_;
3043 typename BlockExtractor::ExecMap blockExtractors_;
3044 typename BlockExtractor::ExecMap extraBlockExtractors_;
3045};
3046
3047} // namespace Opm
3048
3049#endif // OPM_OUTPUT_BLACK_OIL_MODULE_HPP
Contains the classes required to extend the black-oil model by energy.
Declares the properties required by the black oil model.
Definition: CollectDataOnIORank.hpp:56
The base class for the element-centered finite-volume discretization scheme.
Definition: ecfvdiscretization.hh:160
void assignMicrobialMass(const unsigned globalDofIdx, const Scalar microbialMass)
void assignCalciteMass(const unsigned globalDofIdx, const Scalar calciteMass)
bool hasCo2InGas() const
void assignCo2InWater(const unsigned globalDofIdx, const Scalar co2InWater, const Scalar mM)
void assignVolumesSurface(const unsigned globalDofIdx, const std::array< Scalar, numPhases > &fip)
bool has(const Inplace::Phase phase) const
bool hasMicrobialMass() const
void assignWaterMass(const unsigned globalDofIdx, const std::array< Scalar, numPhases > &fip, const Scalar rhoW)
void assignCo2InGas(const unsigned globalDofIdx, const Co2InGasInput &v)
bool hasOxygenMass() const
void assignVolumesReservoir(const unsigned globalDofIdx, const Scalar saltConcentration, const std::array< Scalar, numPhases > &fipr)
void assignPoreVolume(const unsigned globalDofIdx, const Scalar value)
void assignOxygenMass(const unsigned globalDofIdx, const Scalar oxygenMass)
bool hasUreaMass() const
void assignOilGasDistribution(const unsigned globalDofIdx, const Scalar gasInPlaceLiquid, const Scalar oilInPlaceGas)
void assignBiofilmMass(const unsigned globalDofIdx, const Scalar biofilmMass)
bool hasWaterMass() const
bool hasCo2InWater() const
void assignUreaMass(const unsigned globalDofIdx, const Scalar ureaMass)
bool hasCalciteMass() const
bool hasBiofilmMass() const
const std::vector< Scalar > & get(const Inplace::Phase phase) const
void assignGasWater(const unsigned globalDofIdx, const std::array< Scalar, numPhases > &fip, const Scalar gasInPlaceWater, const Scalar waterInPlaceGas)
const std::vector< int > blockVelocity() const
Definition: FlowsContainer.hpp:103
Definition: GenericOutputBlackoilModule.hpp:78
std::map< std::pair< std::string, int >, double > blockData_
Definition: GenericOutputBlackoilModule.hpp:469
std::array< ScalarBuffer, numPhases > relativePermeability_
Definition: GenericOutputBlackoilModule.hpp:456
const Inplace * initialInplace() const
Definition: GenericOutputBlackoilModule.hpp:251
ScalarBuffer fluidPressure_
Definition: GenericOutputBlackoilModule.hpp:409
std::array< ScalarBuffer, numPhases > density_
Definition: GenericOutputBlackoilModule.hpp:454
ScalarBuffer saturatedOilFormationVolumeFactor_
Definition: GenericOutputBlackoilModule.hpp:441
ScalarBuffer overburdenPressure_
Definition: GenericOutputBlackoilModule.hpp:415
ScalarBuffer gasDissolutionFactorInWater_
Definition: GenericOutputBlackoilModule.hpp:435
const EclipseState & eclState_
Definition: GenericOutputBlackoilModule.hpp:367
ScalarBuffer swmin_
Definition: GenericOutputBlackoilModule.hpp:431
ScalarBuffer rockCompPorvMultiplier_
Definition: GenericOutputBlackoilModule.hpp:439
RFTContainer< GetPropType< TypeTag, Properties::FluidSystem > > rftC_
Definition: GenericOutputBlackoilModule.hpp:466
ScalarBuffer dewPointPressure_
Definition: GenericOutputBlackoilModule.hpp:438
LogOutputHelper< Scalar > logOutput_
Definition: GenericOutputBlackoilModule.hpp:374
GeochemistryContainer< Scalar > geochemC_
Definition: GenericOutputBlackoilModule.hpp:458
std::vector< int > failedCellsPb_
Definition: GenericOutputBlackoilModule.hpp:400
ScalarBuffer permFact_
Definition: GenericOutputBlackoilModule.hpp:424
ScalarBuffer rsw_
Definition: GenericOutputBlackoilModule.hpp:412
ScalarBuffer pcog_
Definition: GenericOutputBlackoilModule.hpp:447
std::optional< RegionPhasePoreVolAverage > regionAvgDensity_
Definition: GenericOutputBlackoilModule.hpp:477
std::array< ScalarBuffer, numPhases > invB_
Definition: GenericOutputBlackoilModule.hpp:453
ScalarBuffer pSalt_
Definition: GenericOutputBlackoilModule.hpp:423
ScalarBuffer cFoam_
Definition: GenericOutputBlackoilModule.hpp:421
ScalarBuffer bubblePointPressure_
Definition: GenericOutputBlackoilModule.hpp:437
ScalarBuffer temperature_
Definition: GenericOutputBlackoilModule.hpp:410
ScalarBuffer ppcw_
Definition: GenericOutputBlackoilModule.hpp:432
FIPContainer< GetPropType< TypeTag, Properties::FluidSystem > > fipC_
Definition: GenericOutputBlackoilModule.hpp:393
ScalarBuffer rockCompTransMultiplier_
Definition: GenericOutputBlackoilModule.hpp:442
MechContainer< Scalar > mech_
Definition: GenericOutputBlackoilModule.hpp:450
ScalarBuffer dynamicPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:407
ScalarBuffer minimumOilPressure_
Definition: GenericOutputBlackoilModule.hpp:440
ScalarBuffer gasFormationVolumeFactor_
Definition: GenericOutputBlackoilModule.hpp:403
std::array< ScalarBuffer, numPhases > residual_
Definition: GenericOutputBlackoilModule.hpp:462
void doAllocBuffers(unsigned bufferSize, unsigned reportStepNum, const bool substep, const bool log, const bool isRestart, const EclHysteresisConfig *hysteresisConfig, unsigned numOutputNnc=0, std::map< std::string, int > rstKeywords={})
ScalarBuffer shmax_
Definition: GenericOutputBlackoilModule.hpp:429
BioeffectsContainer< Scalar > bioeffectsC_
Definition: GenericOutputBlackoilModule.hpp:443
const Schedule & schedule_
Definition: GenericOutputBlackoilModule.hpp:368
FlowsContainer< GetPropType< TypeTag, Properties::FluidSystem > > flowsC_
Definition: GenericOutputBlackoilModule.hpp:464
ExtboContainer< Scalar > extboC_
Definition: GenericOutputBlackoilModule.hpp:425
void setupExtraBlockData(const std::size_t reportStepNum, std::function< bool(int)> isCartIdxOnThisRank)
ScalarBuffer oilSaturationPressure_
Definition: GenericOutputBlackoilModule.hpp:416
InterRegFlowMap interRegionFlows_
Definition: GenericOutputBlackoilModule.hpp:373
ScalarBuffer pcgw_
Definition: GenericOutputBlackoilModule.hpp:445
ScalarBuffer cPolymer_
Definition: GenericOutputBlackoilModule.hpp:420
void setupBlockData(std::function< bool(int)> isCartIdxOnThisRank)
ScalarBuffer rvw_
Definition: GenericOutputBlackoilModule.hpp:414
std::array< ScalarBuffer, numPhases > saturation_
Definition: GenericOutputBlackoilModule.hpp:452
std::unordered_map< std::string, std::vector< int > > regions_
Definition: GenericOutputBlackoilModule.hpp:394
ScalarBuffer rPorV_
Definition: GenericOutputBlackoilModule.hpp:408
ScalarBuffer oilVaporizationFactor_
Definition: GenericOutputBlackoilModule.hpp:434
std::vector< int > failedCellsPd_
Definition: GenericOutputBlackoilModule.hpp:401
ScalarBuffer rs_
Definition: GenericOutputBlackoilModule.hpp:411
ScalarBuffer drsdtcon_
Definition: GenericOutputBlackoilModule.hpp:417
ScalarBuffer sSol_
Definition: GenericOutputBlackoilModule.hpp:418
std::map< std::pair< std::string, int >, double > extraBlockData_
Definition: GenericOutputBlackoilModule.hpp:472
ScalarBuffer pressureTimesPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:405
ScalarBuffer gasDissolutionFactor_
Definition: GenericOutputBlackoilModule.hpp:433
std::array< ScalarBuffer, numPhases > viscosity_
Definition: GenericOutputBlackoilModule.hpp:455
bool forceDisableFipOutput_
Definition: GenericOutputBlackoilModule.hpp:389
ScalarBuffer soMax_
Definition: GenericOutputBlackoilModule.hpp:426
ScalarBuffer sgmax_
Definition: GenericOutputBlackoilModule.hpp:428
ScalarBuffer somin_
Definition: GenericOutputBlackoilModule.hpp:430
ScalarBuffer hydrocarbonPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:404
ScalarBuffer waterVaporizationFactor_
Definition: GenericOutputBlackoilModule.hpp:436
ScalarBuffer cSalt_
Definition: GenericOutputBlackoilModule.hpp:422
TracerContainer< GetPropType< TypeTag, Properties::FluidSystem > > tracerC_
Definition: GenericOutputBlackoilModule.hpp:460
ScalarBuffer rv_
Definition: GenericOutputBlackoilModule.hpp:413
ScalarBuffer pcow_
Definition: GenericOutputBlackoilModule.hpp:446
ScalarBuffer swMax_
Definition: GenericOutputBlackoilModule.hpp:427
CO2H2Container< Scalar > CO2H2C_
Definition: GenericOutputBlackoilModule.hpp:444
ScalarBuffer pressureTimesHydrocarbonVolume_
Definition: GenericOutputBlackoilModule.hpp:406
ScalarBuffer rswSol_
Definition: GenericOutputBlackoilModule.hpp:419
Inter-region flow accumulation maps for all region definition arrays.
Definition: InterRegFlows.hpp:179
void addConnection(const Cell &source, const Cell &destination, const data::InterRegFlowMap::FlowRates &rates)
void clear()
Clear all internal buffers, but preserve allocated capacity.
Output module for the results black oil model writing in ECL binary format.
Definition: OutputBlackoilModule.hpp:86
void processElement(const ElementContext &elemCtx)
Modify the internal buffers according to the intensive quanties relevant for an element.
Definition: OutputBlackoilModule.hpp:242
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows.
Definition: OutputBlackoilModule.hpp:486
void setupExtractors(const bool isSubStep, const int reportStepNum)
Setup list of active element-level data extractors.
Definition: OutputBlackoilModule.hpp:223
void allocBuffers(const unsigned bufferSize, const unsigned reportStepNum, const bool substep, const bool log, const bool isRestart)
Allocate memory for the scalar fields we would like to write to ECL output files.
Definition: OutputBlackoilModule.hpp:201
void processFluxes(const ElementContext &elemCtx, ActiveIndex &&activeIndex, CartesianIndex &&cartesianIndex)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputBlackoilModule.hpp:449
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputBlackoilModule.hpp:231
void outputFipAndResvLogToCSV(const std::size_t reportStepNum, const bool substep, const Parallel::Communication &comm)
Definition: OutputBlackoilModule.hpp:383
void assignToFluidState(FluidState &fs, unsigned elemIdx) const
Definition: OutputBlackoilModule.hpp:510
void initHysteresisParams(Simulator &simulator, unsigned elemIdx) const
Definition: OutputBlackoilModule.hpp:562
void updateFluidInPlace(const ElementContext &elemCtx)
Definition: OutputBlackoilModule.hpp:627
OutputBlackOilModule(const Simulator &simulator, const SummaryConfig &smryCfg, const CollectDataOnIORankType &collectOnIORank)
Definition: OutputBlackoilModule.hpp:134
void outputFipAndResvLog(const Inplace &inplace, const std::size_t reportStepNum, double elapsed, boost::posix_time::ptime currentDate, const bool substep, const Parallel::Communication &comm)
Definition: OutputBlackoilModule.hpp:332
const InterRegFlowMap & getInterRegFlows() const
Get read-only access to collection of inter-region flows.
Definition: OutputBlackoilModule.hpp:504
void processElementBlockData(const ElementContext &elemCtx)
Definition: OutputBlackoilModule.hpp:288
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputBlackoilModule.hpp:496
void updateFluidInPlace(const unsigned globalDofIdx, const IntensiveQuantities &intQuants, const double totVolume)
Definition: OutputBlackoilModule.hpp:634
Declare the properties used by the infrastructure code of the finite volume discretizations.
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
Phase
Phase indices for reservoir coupling, we currently only support black-oil phases (oil,...
Definition: ReservoirCoupling.hpp:156
Definition: blackoilbioeffectsmodules.hh:45
std::string moduleVersionName()
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
This file provides the infrastructure to retrieve run-time parameters.
The Opm property system, traits with inheritance.
Minimal characteristics of a cell from a simulation grid.
Definition: InterRegFlows.hpp:50
Context passed to element extractor functions.
Definition: OutputExtractor.hpp:205
Wrapping struct holding types used for block-level data extraction.
Definition: OutputExtractor.hpp:192
std::unordered_map< int, std::vector< Exec > > ExecMap
A map of extraction executors, keyed by cartesian cell index.
Definition: OutputExtractor.hpp:259
std::variant< ScalarEntry, PhaseEntry > Entry
Descriptor for extractors.
Definition: OutputExtractor.hpp:244
static ExecMap setupExecMap(std::map< std::pair< std::string, int >, double > &blockData, const std::array< Entry, size > &handlers)
Setup an extractor executor map from a map of evaluations to perform.
Definition: OutputExtractor.hpp:263
static void process(const std::vector< Exec > &blockExtractors, const Context &ectx)
Process a list of block extractors.
Definition: OutputExtractor.hpp:364
Context passed to extractor functions.
Definition: OutputExtractor.hpp:74
int episodeIndex
Current report step.
Definition: OutputExtractor.hpp:77
Struct holding hysteresis parameters.
Definition: OutputExtractor.hpp:63
Scalar somin
Min oil saturation.
Definition: OutputExtractor.hpp:69
Scalar swmin
Min water saturation.
Definition: OutputExtractor.hpp:66
Scalar swmax
Max water saturation.
Definition: OutputExtractor.hpp:65
Scalar shmax
Max something.
Definition: OutputExtractor.hpp:68
Scalar sgmax
Max gas saturation.
Definition: OutputExtractor.hpp:67
Scalar somax
Max oil saturation.
Definition: OutputExtractor.hpp:64
Wrapping struct holding types used for element-level data extraction.
Definition: OutputExtractor.hpp:54
static void process(const Context &ectx, const std::vector< Entry > &extractors)
Process the given extractor entries.
Definition: OutputExtractor.hpp:157
static std::vector< Entry > removeInactive(std::array< Entry, size > &input)
Obtain vector of active extractors from an array of extractors.
Definition: OutputExtractor.hpp:120