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 enum { enableEnergy = getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal };
118 enum { enableTemperature = getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::ConstantTemperature };
119
120 enum { enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>() };
121 enum { enableMICP = Indices::enableMICP };
122 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
123 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
124 enum { enableDissolvedGas = Indices::compositionSwitchIdx >= 0 };
125
126 template<class VectorType>
127 static Scalar value_or_zero(int idx, const VectorType& v)
128 {
129 if (idx == -1) {
130 return 0.0;
131 }
132 return v.empty() ? 0.0 : v[idx];
133 }
134
135public:
136 OutputBlackOilModule(const Simulator& simulator,
137 const SummaryConfig& smryCfg,
138 const CollectDataOnIORankType& collectOnIORank)
139 : BaseType(simulator.vanguard().eclState(),
140 simulator.vanguard().schedule(),
141 smryCfg,
142 simulator.vanguard().summaryState(),
144 [this](const int idx)
145 { return simulator_.problem().eclWriter().collectOnIORank().localIdxToGlobalIdx(idx); },
146 simulator.vanguard().grid().comm(),
147 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal,
148 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::ConstantTemperature,
149 getPropValue<TypeTag, Properties::EnableMech>(),
150 getPropValue<TypeTag, Properties::EnableSolvent>(),
151 getPropValue<TypeTag, Properties::EnablePolymer>(),
152 getPropValue<TypeTag, Properties::EnableFoam>(),
153 getPropValue<TypeTag, Properties::EnableBrine>(),
154 getPropValue<TypeTag, Properties::EnableSaltPrecipitation>(),
155 getPropValue<TypeTag, Properties::EnableExtbo>(),
156 getPropValue<TypeTag, Properties::EnableBioeffects>())
157 , simulator_(simulator)
158 , collectOnIORank_(collectOnIORank)
159 {
160 for (auto& region_pair : this->regions_) {
161 this->createLocalRegion_(region_pair.second);
162 }
163
164 auto isCartIdxOnThisRank = [&collectOnIORank](const int idx) {
165 return collectOnIORank.isCartIdxOnThisRank(idx);
166 };
167
168 this->setupBlockData(isCartIdxOnThisRank);
169
170 if (! Parameters::Get<Parameters::OwnerCellsFirst>()) {
171 const std::string msg = "The output code does not support --owner-cells-first=false.";
172 if (collectOnIORank.isIORank()) {
173 OpmLog::error(msg);
174 }
175 OPM_THROW_NOLOG(std::runtime_error, msg);
176 }
177
178 if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) {
179 auto rset = this->eclState_.fieldProps().fip_regions();
180 rset.push_back("PVTNUM");
181
182 // Note: We explicitly use decltype(auto) here because the
183 // default scheme (-> auto) will deduce an undesirable type. We
184 // need the "reference to vector" semantics in this instance.
186 .emplace(this->simulator_.gridView().comm(),
187 FluidSystem::numPhases, rset,
188 [fp = std::cref(this->eclState_.fieldProps())]
189 (const std::string& rsetName) -> decltype(auto)
190 { return fp.get().get_int(rsetName); });
191 }
192 }
193
198 void
199 allocBuffers(const unsigned bufferSize,
200 const unsigned reportStepNum,
201 const bool substep,
202 const bool log,
203 const bool isRestart)
204 {
205 if (! std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
206 return;
207 }
208
209 const auto& problem = this->simulator_.problem();
210
211 this->doAllocBuffers(bufferSize,
212 reportStepNum,
213 substep,
214 log,
215 isRestart,
216 &problem.materialLawManager()->hysteresisConfig(),
217 problem.eclWriter().getOutputNnc().size());
218 }
219
221 void setupExtractors(const bool isSubStep,
222 const int reportStepNum)
223 {
224 this->setupElementExtractors_();
225 this->setupBlockExtractors_(isSubStep, reportStepNum);
226 }
227
230 {
231 this->extractors_.clear();
232 this->blockExtractors_.clear();
233 this->extraBlockExtractors_.clear();
234 }
235
240 void processElement(const ElementContext& elemCtx)
241 {
242 OPM_TIMEBLOCK_LOCAL(processElement, Subsystem::Output);
243 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
244 return;
245 }
246
247 if (this->extractors_.empty()) {
248 assert(0);
249 }
250
251 const auto& matLawManager = simulator_.problem().materialLawManager();
252
253 typename Extractor::HysteresisParams hysterParams;
254 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
255 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
256 const auto& fs = intQuants.fluidState();
257
258 const typename Extractor::Context ectx{
259 elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0),
260 elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(),
261 elemCtx.simulator().episodeIndex(),
262 fs,
263 intQuants,
264 hysterParams
265 };
266
267 if (matLawManager->enableHysteresis()) {
268 if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx)) {
269 matLawManager->oilWaterHysteresisParams(hysterParams.somax,
270 hysterParams.swmax,
271 hysterParams.swmin,
272 ectx.globalDofIdx);
273 }
274 if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(gasPhaseIdx)) {
275 matLawManager->gasOilHysteresisParams(hysterParams.sgmax,
276 hysterParams.shmax,
277 hysterParams.somin,
278 ectx.globalDofIdx);
279 }
280 }
281
282 Extractor::process(ectx, extractors_);
283 }
284 }
285
286 void processElementBlockData(const ElementContext& elemCtx)
287 {
288 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
289 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
290 return;
291 }
292
293 if (this->blockExtractors_.empty() && this->extraBlockExtractors_.empty()) {
294 return;
295 }
296
297 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
298 // Adding block data
299 const auto globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
300 const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx);
301
302 const auto be_it = this->blockExtractors_.find(cartesianIdx);
303 const auto bee_it = this->extraBlockExtractors_.find(cartesianIdx);
304 if (be_it == this->blockExtractors_.end() &&
305 bee_it == this->extraBlockExtractors_.end())
306 {
307 continue;
308 }
309
310 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
311 const auto& fs = intQuants.fluidState();
312
313 const typename BlockExtractor::Context ectx{
314 globalDofIdx,
315 dofIdx,
316 fs,
317 intQuants,
318 elemCtx,
319 };
320
321 if (be_it != this->blockExtractors_.end()) {
322 BlockExtractor::process(be_it->second, ectx);
323 }
324 if (bee_it != this->extraBlockExtractors_.end()) {
325 BlockExtractor::process(bee_it->second, ectx);
326 }
327 }
328 }
329
330 void outputFipAndResvLog(const Inplace& inplace,
331 const std::size_t reportStepNum,
332 double elapsed,
333 boost::posix_time::ptime currentDate,
334 const bool substep,
335 const Parallel::Communication& comm)
336 {
337
338 if (comm.rank() != 0) {
339 return;
340 }
341
342 // For report step 0 we use the RPTSOL config, else derive from RPTSCHED
343 std::unique_ptr<FIPConfig> fipSched;
344 if (reportStepNum > 0) {
345 const auto& rpt = this->schedule_[reportStepNum-1].rpt_config.get();
346 fipSched = std::make_unique<FIPConfig>(rpt);
347 }
348 const FIPConfig& fipc = reportStepNum == 0 ? this->eclState_.getEclipseConfig().fip()
349 : *fipSched;
350
351 if (!substep && !this->forceDisableFipOutput_ && fipc.output(FIPConfig::OutputField::FIELD)) {
352
353 this->logOutput_.timeStamp("BALANCE", elapsed, reportStepNum, currentDate);
354
355 const auto& initial_inplace = this->initialInplace().value();
356 this->logOutput_.fip(inplace, initial_inplace, "");
357
358 if (fipc.output(FIPConfig::OutputField::FIPNUM)) {
359 this->logOutput_.fip(inplace, initial_inplace, "FIPNUM");
360
361 if (fipc.output(FIPConfig::OutputField::RESV))
362 this->logOutput_.fipResv(inplace, "FIPNUM");
363 }
364
365 if (fipc.output(FIPConfig::OutputField::FIP)) {
366 for (const auto& reg : this->regions_) {
367 if (reg.first != "FIPNUM") {
368 std::ostringstream ss;
369 ss << "BAL" << reg.first.substr(3);
370 this->logOutput_.timeStamp(ss.str(), elapsed, reportStepNum, currentDate);
371 this->logOutput_.fip(inplace, initial_inplace, reg.first);
372
373 if (fipc.output(FIPConfig::OutputField::RESV))
374 this->logOutput_.fipResv(inplace, reg.first);
375 }
376 }
377 }
378 }
379 }
380
381 void outputFipAndResvLogToCSV(const std::size_t reportStepNum,
382 const bool substep,
383 const Parallel::Communication& comm)
384 {
385 if (comm.rank() != 0) {
386 return;
387 }
388
389 if ((reportStepNum == 0) && (!substep) &&
390 (this->schedule_.initialReportConfiguration().has_value()) &&
391 (this->schedule_.initialReportConfiguration()->contains("CSVFIP"))) {
392
393 std::ostringstream csv_stream;
394
395 this->logOutput_.csv_header(csv_stream);
396
397 const auto& initial_inplace = this->initialInplace().value();
398
399 this->logOutput_.fip_csv(csv_stream, initial_inplace, "FIPNUM");
400
401 for (const auto& reg : this->regions_) {
402 if (reg.first != "FIPNUM") {
403 this->logOutput_.fip_csv(csv_stream, initial_inplace, reg.first);
404 }
405 }
406
407 const IOConfig& io = this->eclState_.getIOConfig();
408 auto csv_fname = io.getOutputDir() + "/" + io.getBaseName() + ".CSV";
409
410 std::ofstream outputFile(csv_fname);
411
412 outputFile << csv_stream.str();
413
414 outputFile.close();
415 }
416 }
417
446 template <class ActiveIndex, class CartesianIndex>
447 void processFluxes(const ElementContext& elemCtx,
448 ActiveIndex&& activeIndex,
449 CartesianIndex&& cartesianIndex)
450 {
451 OPM_TIMEBLOCK_LOCAL(processFluxes, Subsystem::Output);
452 const auto identifyCell = [&activeIndex, &cartesianIndex](const Element& elem)
454 {
455 const auto cellIndex = activeIndex(elem);
456
457 return {
458 static_cast<int>(cellIndex),
459 cartesianIndex(cellIndex),
460 elem.partitionType() == Dune::InteriorEntity
461 };
462 };
463
464 const auto timeIdx = 0u;
465 const auto& stencil = elemCtx.stencil(timeIdx);
466 const auto numInteriorFaces = elemCtx.numInteriorFaces(timeIdx);
467
468 for (auto scvfIdx = 0 * numInteriorFaces; scvfIdx < numInteriorFaces; ++scvfIdx) {
469 const auto& face = stencil.interiorFace(scvfIdx);
470 const auto left = identifyCell(stencil.element(face.interiorIndex()));
471 const auto right = identifyCell(stencil.element(face.exteriorIndex()));
472
473 const auto rates = this->
474 getComponentSurfaceRates(elemCtx, face.area(), scvfIdx, timeIdx);
475
476 this->interRegionFlows_.addConnection(left, right, rates);
477 }
478 }
479
485 {
486 // Inter-region flow rates. Note: ".clear()" prepares to accumulate
487 // contributions per bulk connection between FIP regions.
488 this->interRegionFlows_.clear();
489 }
490
495 {
497 }
498
503 {
504 return this->interRegionFlows_;
505 }
506
507 template <class FluidState>
508 void assignToFluidState(FluidState& fs, unsigned elemIdx) const
509 {
510 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
511 if (this->saturation_[phaseIdx].empty())
512 continue;
513
514 fs.setSaturation(phaseIdx, this->saturation_[phaseIdx][elemIdx]);
515 }
516
517 if (!this->fluidPressure_.empty()) {
518 // this assumes that capillary pressures only depend on the phase saturations
519 // and possibly on temperature. (this is always the case for ECL problems.)
520 std::array<Scalar, numPhases> pc = {0};
521 const MaterialLawParams& matParams = simulator_.problem().materialLawParams(elemIdx);
522 MaterialLaw::capillaryPressures(pc, matParams, fs);
523 Valgrind::CheckDefined(this->fluidPressure_[elemIdx]);
524 Valgrind::CheckDefined(pc);
525 const auto& pressure = this->fluidPressure_[elemIdx];
526 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
527 if (!FluidSystem::phaseIsActive(phaseIdx))
528 continue;
529
530 if (Indices::oilEnabled)
531 fs.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
532 else if (Indices::gasEnabled)
533 fs.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
534 else if (Indices::waterEnabled)
535 //single (water) phase
536 fs.setPressure(phaseIdx, pressure);
537 }
538 }
539
540 if constexpr (enableEnergy || enableTemperature) {
541 if (!this->temperature_.empty())
542 fs.setTemperature(this->temperature_[elemIdx]);
543 }
544 if constexpr (enableDissolvedGas) {
545 if (!this->rs_.empty())
546 fs.setRs(this->rs_[elemIdx]);
547 if (!this->rv_.empty())
548 fs.setRv(this->rv_[elemIdx]);
549 }
550 if constexpr (enableDisgasInWater) {
551 if (!this->rsw_.empty())
552 fs.setRsw(this->rsw_[elemIdx]);
553 }
554 if constexpr (enableVapwat) {
555 if (!this->rvw_.empty())
556 fs.setRvw(this->rvw_[elemIdx]);
557 }
558 }
559
560 void initHysteresisParams(Simulator& simulator, unsigned elemIdx) const
561 {
562 if (!this->soMax_.empty())
563 simulator.problem().setMaxOilSaturation(elemIdx, this->soMax_[elemIdx]);
564
565 if (simulator.problem().materialLawManager()->enableHysteresis()) {
566 auto matLawManager = simulator.problem().materialLawManager();
567
568 if (FluidSystem::phaseIsActive(oilPhaseIdx)
569 && FluidSystem::phaseIsActive(waterPhaseIdx)) {
570 Scalar somax = 2.0;
571 Scalar swmax = -2.0;
572 Scalar swmin = 2.0;
573
574 if (matLawManager->enableNonWettingHysteresis()) {
575 if (!this->soMax_.empty()) {
576 somax = this->soMax_[elemIdx];
577 }
578 }
579 if (matLawManager->enableWettingHysteresis()) {
580 if (!this->swMax_.empty()) {
581 swmax = this->swMax_[elemIdx];
582 }
583 }
584 if (matLawManager->enablePCHysteresis()) {
585 if (!this->swmin_.empty()) {
586 swmin = this->swmin_[elemIdx];
587 }
588 }
589 matLawManager->setOilWaterHysteresisParams(
590 somax, swmax, swmin, elemIdx);
591 }
592 if (FluidSystem::phaseIsActive(oilPhaseIdx)
593 && FluidSystem::phaseIsActive(gasPhaseIdx)) {
594 Scalar sgmax = 2.0;
595 Scalar shmax = -2.0;
596 Scalar somin = 2.0;
597
598 if (matLawManager->enableNonWettingHysteresis()) {
599 if (!this->sgmax_.empty()) {
600 sgmax = this->sgmax_[elemIdx];
601 }
602 }
603 if (matLawManager->enableWettingHysteresis()) {
604 if (!this->shmax_.empty()) {
605 shmax = this->shmax_[elemIdx];
606 }
607 }
608 if (matLawManager->enablePCHysteresis()) {
609 if (!this->somin_.empty()) {
610 somin = this->somin_[elemIdx];
611 }
612 }
613 matLawManager->setGasOilHysteresisParams(
614 sgmax, shmax, somin, elemIdx);
615 }
616
617 }
618
619 if (simulator_.vanguard().eclState().fieldProps().has_double("SWATINIT")) {
620 simulator.problem().materialLawManager()
621 ->applyRestartSwatInit(elemIdx, this->ppcw_[elemIdx]);
622 }
623 }
624
625 void updateFluidInPlace(const ElementContext& elemCtx)
626 {
627 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
628 updateFluidInPlace_(elemCtx, dofIdx);
629 }
630 }
631
632 void updateFluidInPlace(const unsigned globalDofIdx,
633 const IntensiveQuantities& intQuants,
634 const double totVolume)
635 {
636 this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
637 }
638
639private:
640 template <typename T>
641 using RemoveCVR = std::remove_cv_t<std::remove_reference_t<T>>;
642
643 template <typename, class = void>
644 struct HasGeoMech : public std::false_type {};
645
646 template <typename Problem>
647 struct HasGeoMech<
648 Problem, std::void_t<decltype(std::declval<Problem>().geoMechModel())>
649 > : public std::true_type {};
650
651 bool isDefunctParallelWell(const std::string& wname) const override
652 {
653 if (simulator_.gridView().comm().size() == 1)
654 return false;
655 const auto& parallelWells = simulator_.vanguard().parallelWells();
656 std::pair<std::string, bool> value {wname, true};
657 auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value);
658 return candidate == parallelWells.end() || *candidate != value;
659 }
660
661 bool isOwnedByCurrentRank(const std::string& wname) const override
662 {
663 return this->simulator_.problem().wellModel().isOwner(wname);
664 }
665
666 bool isOnCurrentRank(const std::string& wname) const override
667 {
668 return this->simulator_.problem().wellModel().hasLocalCells(wname);
669 }
670
671 void updateFluidInPlace_(const ElementContext& elemCtx, const unsigned dofIdx)
672 {
673 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
674 const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
675 const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx);
676
677 this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
678 }
679
680 void updateFluidInPlace_(const unsigned globalDofIdx,
681 const IntensiveQuantities& intQuants,
682 const double totVolume)
683 {
684 OPM_TIMEBLOCK_LOCAL(updateFluidInPlace, Subsystem::Output);
685
686 this->updateTotalVolumesAndPressures_(globalDofIdx, intQuants, totVolume);
687
688 if (this->computeFip_) {
689 this->updatePhaseInplaceVolumes_(globalDofIdx, intQuants, totVolume);
690 }
691 }
692
693 void createLocalRegion_(std::vector<int>& region)
694 {
695 // For CpGrid with LGRs, where level zero grid has been distributed,
696 // resize region is needed, since in this case the total amount of
697 // element - per process - in level zero grid and leaf grid do not
698 // coincide, in general.
699 region.resize(simulator_.gridView().size(0));
700 std::size_t elemIdx = 0;
701 for (const auto& elem : elements(simulator_.gridView())) {
702 if (elem.partitionType() != Dune::InteriorEntity) {
703 region[elemIdx] = 0;
704 }
705
706 ++elemIdx;
707 }
708 }
709
710 template <typename FluidState>
711 void aggregateAverageDensityContributions_(const FluidState& fs,
712 const unsigned int globalDofIdx,
713 const double porv)
714 {
715 auto pvCellValue = RegionPhasePoreVolAverage::CellValue{};
716 pvCellValue.porv = porv;
717
718 for (auto phaseIdx = 0*FluidSystem::numPhases;
719 phaseIdx < FluidSystem::numPhases; ++phaseIdx)
720 {
721 if (! FluidSystem::phaseIsActive(phaseIdx)) {
722 continue;
723 }
724
725 pvCellValue.value = getValue(fs.density(phaseIdx));
726 pvCellValue.sat = getValue(fs.saturation(phaseIdx));
727
729 ->addCell(globalDofIdx,
730 RegionPhasePoreVolAverage::Phase { phaseIdx },
731 pvCellValue);
732 }
733 }
734
750 data::InterRegFlowMap::FlowRates
751 getComponentSurfaceRates(const ElementContext& elemCtx,
752 const Scalar faceArea,
753 const std::size_t scvfIdx,
754 const std::size_t timeIdx) const
755 {
756 using Component = data::InterRegFlowMap::Component;
757
758 auto rates = data::InterRegFlowMap::FlowRates {};
759
760 const auto& extQuant = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
761
762 const auto alpha = getValue(extQuant.extrusionFactor()) * faceArea;
763
764 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
765 const auto& up = elemCtx
766 .intensiveQuantities(extQuant.upstreamIndex(oilPhaseIdx), timeIdx);
767
768 const auto pvtReg = up.pvtRegionIndex();
769
770 const auto bO = getValue(getInvB_<FluidSystem, FluidState, Scalar>
771 (up.fluidState(), oilPhaseIdx, pvtReg));
772
773 const auto qO = alpha * bO * getValue(extQuant.volumeFlux(oilPhaseIdx));
774
775 rates[Component::Oil] += qO;
776
777 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
778 const auto Rs = getValue(
779 BlackOil::getRs_<FluidSystem, FluidState, Scalar>
780 (up.fluidState(), pvtReg));
781
782 rates[Component::Gas] += qO * Rs;
783 rates[Component::Disgas] += qO * Rs;
784 }
785 }
786
787 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
788 const auto& up = elemCtx
789 .intensiveQuantities(extQuant.upstreamIndex(gasPhaseIdx), timeIdx);
790
791 const auto pvtReg = up.pvtRegionIndex();
792
793 const auto bG = getValue(getInvB_<FluidSystem, FluidState, Scalar>
794 (up.fluidState(), gasPhaseIdx, pvtReg));
795
796 const auto qG = alpha * bG * getValue(extQuant.volumeFlux(gasPhaseIdx));
797
798 rates[Component::Gas] += qG;
799
800 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
801 const auto Rv = getValue(
802 BlackOil::getRv_<FluidSystem, FluidState, Scalar>
803 (up.fluidState(), pvtReg));
804
805 rates[Component::Oil] += qG * Rv;
806 rates[Component::Vapoil] += qG * Rv;
807 }
808 }
809
810 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
811 const auto& up = elemCtx
812 .intensiveQuantities(extQuant.upstreamIndex(waterPhaseIdx), timeIdx);
813
814 const auto pvtReg = up.pvtRegionIndex();
815
816 const auto bW = getValue(getInvB_<FluidSystem, FluidState, Scalar>
817 (up.fluidState(), waterPhaseIdx, pvtReg));
818
819 rates[Component::Water] +=
820 alpha * bW * getValue(extQuant.volumeFlux(waterPhaseIdx));
821 }
822
823 return rates;
824 }
825
826 template <typename FluidState>
827 Scalar hydroCarbonFraction(const FluidState& fs) const
828 {
829 if (this->eclState_.runspec().co2Storage()) {
830 // CO2 storage: Hydrocarbon volume is full pore-volume.
831 return 1.0;
832 }
833
834 // Common case. Hydrocarbon volume is fraction occupied by actual
835 // hydrocarbons.
836 auto hydrocarbon = Scalar {0};
837 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
838 hydrocarbon += getValue(fs.saturation(oilPhaseIdx));
839 }
840
841 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
842 hydrocarbon += getValue(fs.saturation(gasPhaseIdx));
843 }
844
845 return hydrocarbon;
846 }
847
848 void updateTotalVolumesAndPressures_(const unsigned globalDofIdx,
849 const IntensiveQuantities& intQuants,
850 const double totVolume)
851 {
852 const auto& fs = intQuants.fluidState();
853
854 const double pv = totVolume * intQuants.porosity().value();
855 const auto hydrocarbon = this->hydroCarbonFraction(fs);
856
857 if (! this->hydrocarbonPoreVolume_.empty()) {
858 this->fipC_.assignPoreVolume(globalDofIdx,
859 totVolume * intQuants.referencePorosity());
860
861 this->dynamicPoreVolume_[globalDofIdx] = pv;
862 this->hydrocarbonPoreVolume_[globalDofIdx] = pv * hydrocarbon;
863 }
864
865 if (!this->pressureTimesHydrocarbonVolume_.empty() &&
866 !this->pressureTimesPoreVolume_.empty())
867 {
868 assert(this->hydrocarbonPoreVolume_.size() == this->pressureTimesHydrocarbonVolume_.size());
869 assert(this->fipC_.get(Inplace::Phase::PoreVolume).size() == this->pressureTimesPoreVolume_.size());
870
871 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
872 this->pressureTimesPoreVolume_[globalDofIdx] =
873 getValue(fs.pressure(oilPhaseIdx)) * pv;
874
875 this->pressureTimesHydrocarbonVolume_[globalDofIdx] =
876 this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon;
877 }
878 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
879 this->pressureTimesPoreVolume_[globalDofIdx] =
880 getValue(fs.pressure(gasPhaseIdx)) * pv;
881
882 this->pressureTimesHydrocarbonVolume_[globalDofIdx] =
883 this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon;
884 }
885 else if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
886 this->pressureTimesPoreVolume_[globalDofIdx] =
887 getValue(fs.pressure(waterPhaseIdx)) * pv;
888 }
889 }
890 }
891
892 void updatePhaseInplaceVolumes_(const unsigned globalDofIdx,
893 const IntensiveQuantities& intQuants,
894 const double totVolume)
895 {
896 std::array<Scalar, FluidSystem::numPhases> fip {};
897 std::array<Scalar, FluidSystem::numPhases> fipr{}; // at reservoir condition
898
899 const auto& fs = intQuants.fluidState();
900 const auto pv = totVolume * intQuants.porosity().value();
901
902 for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) {
903 if (!FluidSystem::phaseIsActive(phaseIdx)) {
904 continue;
905 }
906
907 const auto b = getValue(fs.invB(phaseIdx));
908 const auto s = getValue(fs.saturation(phaseIdx));
909
910 fipr[phaseIdx] = s * pv;
911 fip [phaseIdx] = b * fipr[phaseIdx];
912 }
913
914 this->fipC_.assignVolumesSurface(globalDofIdx, fip);
915 this->fipC_.assignVolumesReservoir(globalDofIdx,
916 fs.saltConcentration().value(),
917 fipr);
918
919 if (FluidSystem::phaseIsActive(oilPhaseIdx) &&
920 FluidSystem::phaseIsActive(gasPhaseIdx))
921 {
922 this->updateOilGasDistribution(globalDofIdx, fs, fip);
923 }
924
925 if (FluidSystem::phaseIsActive(waterPhaseIdx) &&
926 FluidSystem::phaseIsActive(gasPhaseIdx))
927 {
928 this->updateGasWaterDistribution(globalDofIdx, fs, fip);
929 }
930
931 if (FluidSystem::phaseIsActive(gasPhaseIdx) &&
932 this->fipC_.hasCo2InGas())
933 {
934 this->updateCO2InGas(globalDofIdx, pv, intQuants);
935 }
936
937 if (this->fipC_.hasCo2InWater() &&
938 (FluidSystem::phaseIsActive(waterPhaseIdx) ||
939 FluidSystem::phaseIsActive(oilPhaseIdx)))
940 {
941 this->updateCO2InWater(globalDofIdx, pv, fs);
942 }
943
944 if constexpr(enableBioeffects) {
945 const auto surfVolWat = pv * getValue(fs.saturation(waterPhaseIdx)) *
946 getValue(fs.invB(waterPhaseIdx));
947 if (this->fipC_.hasMicrobialMass()) {
948 this->updateMicrobialMass(globalDofIdx, intQuants, surfVolWat);
949 }
950 if (this->fipC_.hasBiofilmMass()) {
951 this->updateBiofilmMass(globalDofIdx, intQuants, totVolume);
952 }
953 if constexpr(enableMICP) {
954 if (this->fipC_.hasOxygenMass()) {
955 this->updateOxygenMass(globalDofIdx, intQuants, surfVolWat);
956 }
957 if (this->fipC_.hasUreaMass()) {
958 this->updateUreaMass(globalDofIdx, intQuants, surfVolWat);
959 }
960 if (this->fipC_.hasCalciteMass()) {
961 this->updateCalciteMass(globalDofIdx, intQuants, totVolume);
962 }
963 }
964 }
965
966 if (this->fipC_.hasWaterMass() && FluidSystem::phaseIsActive(waterPhaseIdx))
967 {
968 this->updateWaterMass(globalDofIdx, fs, fip);
969 }
970 }
971
972 template <typename FluidState, typename FIPArray>
973 void updateOilGasDistribution(const unsigned globalDofIdx,
974 const FluidState& fs,
975 const FIPArray& fip)
976 {
977 // Gas dissolved in oil and vaporized oil
978 const auto gasInPlaceLiquid = getValue(fs.Rs()) * fip[oilPhaseIdx];
979 const auto oilInPlaceGas = getValue(fs.Rv()) * fip[gasPhaseIdx];
980
981 this->fipC_.assignOilGasDistribution(globalDofIdx, gasInPlaceLiquid, oilInPlaceGas);
982 }
983
984 template <typename FluidState, typename FIPArray>
985 void updateGasWaterDistribution(const unsigned globalDofIdx,
986 const FluidState& fs,
987 const FIPArray& fip)
988 {
989 // Gas dissolved in water and vaporized water
990 const auto gasInPlaceWater = getValue(fs.Rsw()) * fip[waterPhaseIdx];
991 const auto waterInPlaceGas = getValue(fs.Rvw()) * fip[gasPhaseIdx];
992
993 this->fipC_.assignGasWater(globalDofIdx, fip, gasInPlaceWater, waterInPlaceGas);
994 }
995
996 template <typename IntensiveQuantities>
997 void updateCO2InGas(const unsigned globalDofIdx,
998 const double pv,
999 const IntensiveQuantities& intQuants)
1000 {
1001 const auto& scaledDrainageInfo = this->simulator_.problem().materialLawManager()
1002 ->oilWaterScaledEpsInfoDrainage(globalDofIdx);
1003
1004 const auto& fs = intQuants.fluidState();
1005 Scalar sgcr = scaledDrainageInfo.Sgcr;
1006 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1007 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1008 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/false);
1009 }
1010
1011 Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr;
1012 if (this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseMaximumTrapped) ||
1013 this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped))
1014 {
1015 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1016 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1017 // Get the maximum trapped gas saturation
1018 trappedGasSaturation = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/true);
1019 }
1020 }
1021
1022 const Scalar sg = getValue(fs.saturation(gasPhaseIdx));
1023 Scalar strandedGasSaturation = scaledDrainageInfo.Sgcr;
1024 if (this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped) ||
1025 this->fipC_.has(Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped))
1026 {
1027 if (this->simulator_.problem().materialLawManager()->enableHysteresis()) {
1028 const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx);
1029 const double krg = getValue(intQuants.relativePermeability(gasPhaseIdx));
1030 strandedGasSaturation = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
1031 }
1032 }
1033
1034 const typename FIPContainer<FluidSystem>::Co2InGasInput v{
1035 pv,
1036 sg,
1037 sgcr,
1038 getValue(fs.density(gasPhaseIdx)),
1039 FluidSystem::phaseIsActive(waterPhaseIdx)
1040 ? FluidSystem::convertRvwToXgW(getValue(fs.Rvw()), fs.pvtRegionIndex())
1041 : FluidSystem::convertRvToXgO(getValue(fs.Rv()), fs.pvtRegionIndex()),
1042 FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()),
1043 trappedGasSaturation,
1044 strandedGasSaturation,
1045 };
1046
1047 this->fipC_.assignCo2InGas(globalDofIdx, v);
1048 }
1049
1050 template <typename FluidState>
1051 void updateCO2InWater(const unsigned globalDofIdx,
1052 const double pv,
1053 const FluidState& fs)
1054 {
1055 const auto co2InWater = FluidSystem::phaseIsActive(oilPhaseIdx)
1056 ? this->co2InWaterFromOil(fs, pv)
1057 : this->co2InWaterFromWater(fs, pv);
1058
1059 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1060
1061 this->fipC_.assignCo2InWater(globalDofIdx, co2InWater, mM);
1062 }
1063
1064 template <typename FluidState>
1065 Scalar co2InWaterFromWater(const FluidState& fs, const double pv) const
1066 {
1067 const double rhow = getValue(fs.density(waterPhaseIdx));
1068 const double sw = getValue(fs.saturation(waterPhaseIdx));
1069 const double xwG = FluidSystem::convertRswToXwG(getValue(fs.Rsw()), fs.pvtRegionIndex());
1070
1071 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1072
1073 return xwG * pv * rhow * sw / mM;
1074 }
1075
1076 template <typename FluidState>
1077 Scalar co2InWaterFromOil(const FluidState& fs, const double pv) const
1078 {
1079 const double rhoo = getValue(fs.density(oilPhaseIdx));
1080 const double so = getValue(fs.saturation(oilPhaseIdx));
1081 const double xoG = FluidSystem::convertRsToXoG(getValue(fs.Rs()), fs.pvtRegionIndex());
1082
1083 const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex());
1084
1085 return xoG * pv * rhoo * so / mM;
1086 }
1087
1088 template <typename FluidState, typename FIPArray>
1089 void updateWaterMass(const unsigned globalDofIdx,
1090 const FluidState& fs,
1091 const FIPArray& fip
1092 )
1093 {
1094 const Scalar rhoW = FluidSystem::referenceDensity(waterPhaseIdx, fs.pvtRegionIndex());
1095
1096 this->fipC_.assignWaterMass(globalDofIdx, fip, rhoW);
1097 }
1098
1099 template <typename IntensiveQuantities>
1100 void updateMicrobialMass(const unsigned globalDofIdx,
1101 const IntensiveQuantities& intQuants,
1102 const double surfVolWat)
1103 {
1104 const Scalar mass = surfVolWat * intQuants.microbialConcentration().value();
1105
1106 this->fipC_.assignMicrobialMass(globalDofIdx, mass);
1107 }
1108
1109 template <typename IntensiveQuantities>
1110 void updateOxygenMass(const unsigned globalDofIdx,
1111 const IntensiveQuantities& intQuants,
1112 const double surfVolWat)
1113 {
1114 const Scalar mass = surfVolWat * intQuants.oxygenConcentration().value();
1115
1116 this->fipC_.assignOxygenMass(globalDofIdx, mass);
1117 }
1118
1119 template <typename IntensiveQuantities>
1120 void updateUreaMass(const unsigned globalDofIdx,
1121 const IntensiveQuantities& intQuants,
1122 const double surfVolWat)
1123 {
1124 const Scalar mass = surfVolWat * intQuants.ureaConcentration().value();
1125
1126 this->fipC_.assignUreaMass(globalDofIdx, mass);
1127 }
1128
1129 template <typename IntensiveQuantities>
1130 void updateBiofilmMass(const unsigned globalDofIdx,
1131 const IntensiveQuantities& intQuants,
1132 const double totVolume)
1133 {
1134 const Scalar mass = totVolume * intQuants.biofilmMass().value();
1135
1136 this->fipC_.assignBiofilmMass(globalDofIdx, mass);
1137 }
1138
1139 template <typename IntensiveQuantities>
1140 void updateCalciteMass(const unsigned globalDofIdx,
1141 const IntensiveQuantities& intQuants,
1142 const double totVolume)
1143 {
1144 const Scalar mass = totVolume * intQuants.calciteMass().value();
1145
1146 this->fipC_.assignCalciteMass(globalDofIdx, mass);
1147 }
1148
1150 void setupElementExtractors_()
1151 {
1152 using Entry = typename Extractor::Entry;
1153 using Context = typename Extractor::Context;
1154 using ScalarEntry = typename Extractor::ScalarEntry;
1155 using PhaseEntry = typename Extractor::PhaseEntry;
1156
1157 const bool hasResidual = simulator_.model().linearizer().residual().size() > 0;
1158 const auto& hysteresisConfig = simulator_.problem().materialLawManager()->hysteresisConfig();
1159
1160 auto extractors = std::array{
1161 Entry{PhaseEntry{&this->saturation_,
1162 [](const unsigned phase, const Context& ectx)
1163 { return getValue(ectx.fs.saturation(phase)); }
1164 }
1165 },
1166 Entry{PhaseEntry{&this->invB_,
1167 [](const unsigned phase, const Context& ectx)
1168 { return getValue(ectx.fs.invB(phase)); }
1169 }
1170 },
1171 Entry{PhaseEntry{&this->density_,
1172 [](const unsigned phase, const Context& ectx)
1173 { return getValue(ectx.fs.density(phase)); }
1174 }
1175 },
1176 Entry{PhaseEntry{&this->relativePermeability_,
1177 [](const unsigned phase, const Context& ectx)
1178 { return getValue(ectx.intQuants.relativePermeability(phase)); }
1179 }
1180 },
1181 Entry{PhaseEntry{&this->viscosity_,
1182 [this](const unsigned phaseIdx, const Context& ectx)
1183 {
1184 if (this->extboC_.allocated() && phaseIdx == oilPhaseIdx) {
1185 return getValue(ectx.intQuants.oilViscosity());
1186 }
1187 else if (this->extboC_.allocated() && phaseIdx == gasPhaseIdx) {
1188 return getValue(ectx.intQuants.gasViscosity());
1189 }
1190 else {
1191 return getValue(ectx.fs.viscosity(phaseIdx));
1192 }
1193 }
1194 }
1195 },
1196 Entry{PhaseEntry{&this->residual_,
1197 [&modelResid = this->simulator_.model().linearizer().residual()]
1198 (const unsigned phaseIdx, const Context& ectx)
1199 {
1200 const unsigned sIdx = FluidSystem::solventComponentIndex(phaseIdx);
1201 const unsigned activeCompIdx = FluidSystem::canonicalToActiveCompIdx(sIdx);
1202 return modelResid[ectx.globalDofIdx][activeCompIdx];
1203 }
1204 },
1205 hasResidual
1206 },
1207 Entry{ScalarEntry{&this->rockCompPorvMultiplier_,
1208 [&problem = this->simulator_.problem()](const Context& ectx)
1209 {
1210 return problem.template
1211 rockCompPoroMultiplier<Scalar>(ectx.intQuants,
1212 ectx.globalDofIdx);
1213 }
1214 }
1215 },
1216 Entry{ScalarEntry{&this->rockCompTransMultiplier_,
1217 [&problem = this->simulator_.problem()](const Context& ectx)
1218 {
1219 return problem.
1220 template rockCompTransMultiplier<Scalar>(ectx.intQuants,
1221 ectx.globalDofIdx);
1222 }}
1223 },
1224 Entry{ScalarEntry{&this->minimumOilPressure_,
1225 [&problem = this->simulator_.problem()](const Context& ectx)
1226 {
1227 return std::min(getValue(ectx.fs.pressure(oilPhaseIdx)),
1228 problem.minOilPressure(ectx.globalDofIdx));
1229 }
1230 }
1231 },
1232 Entry{ScalarEntry{&this->bubblePointPressure_,
1233 [&failedCells = this->failedCellsPb_,
1234 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1235 {
1236 try {
1237 return getValue(
1238 FluidSystem::bubblePointPressure(ectx.fs,
1239 ectx.intQuants.pvtRegionIndex())
1240 );
1241 } catch (const NumericalProblem&) {
1242 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1243 failedCells.push_back(cartesianIdx);
1244 return Scalar{0};
1245 }
1246 }
1247 }
1248 },
1249 Entry{ScalarEntry{&this->dewPointPressure_,
1250 [&failedCells = this->failedCellsPd_,
1251 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1252 {
1253 try {
1254 return getValue(
1255 FluidSystem::dewPointPressure(ectx.fs,
1256 ectx.intQuants.pvtRegionIndex())
1257 );
1258 } catch (const NumericalProblem&) {
1259 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1260 failedCells.push_back(cartesianIdx);
1261 return Scalar{0};
1262 }
1263 }
1264 }
1265 },
1266 Entry{ScalarEntry{&this->overburdenPressure_,
1267 [&problem = simulator_.problem()](const Context& ectx)
1268 { return problem.overburdenPressure(ectx.globalDofIdx); }
1269 }
1270 },
1271 Entry{ScalarEntry{&this->temperature_,
1272 [](const Context& ectx)
1273 { return getValue(ectx.fs.temperature(oilPhaseIdx)); }
1274 }
1275 },
1276 Entry{ScalarEntry{&this->sSol_,
1277 [](const Context& ectx)
1278 { return getValue(ectx.intQuants.solventSaturation()); }
1279 }
1280 },
1281 Entry{ScalarEntry{&this->rswSol_,
1282 [](const Context& ectx)
1283 { return getValue(ectx.intQuants.rsSolw()); }
1284 }
1285 },
1286 Entry{ScalarEntry{&this->cPolymer_,
1287 [](const Context& ectx)
1288 { return getValue(ectx.intQuants.polymerConcentration()); }
1289 }
1290 },
1291 Entry{ScalarEntry{&this->cFoam_,
1292 [](const Context& ectx)
1293 { return getValue(ectx.intQuants.foamConcentration()); }
1294 }
1295 },
1296 Entry{ScalarEntry{&this->cSalt_,
1297 [](const Context& ectx)
1298 { return getValue(ectx.fs.saltConcentration()); }
1299 }
1300 },
1301 Entry{ScalarEntry{&this->pSalt_,
1302 [](const Context& ectx)
1303 { return getValue(ectx.fs.saltSaturation()); }
1304 }
1305 },
1306 Entry{ScalarEntry{&this->permFact_,
1307 [](const Context& ectx)
1308 { return getValue(ectx.intQuants.permFactor()); }
1309 }
1310 },
1311 Entry{ScalarEntry{&this->rPorV_,
1312 [&model = this->simulator_.model()](const Context& ectx)
1313 {
1314 const auto totVolume = model.dofTotalVolume(ectx.globalDofIdx);
1315 return totVolume * getValue(ectx.intQuants.porosity());
1316 }
1317 }
1318 },
1319 Entry{ScalarEntry{&this->rs_,
1320 [](const Context& ectx)
1321 { return getValue(ectx.fs.Rs()); }
1322 }
1323 },
1324 Entry{ScalarEntry{&this->rv_,
1325 [](const Context& ectx)
1326 { return getValue(ectx.fs.Rv()); }
1327 }
1328 },
1329 Entry{ScalarEntry{&this->rsw_,
1330 [](const Context& ectx)
1331 { return getValue(ectx.fs.Rsw()); }
1332 }
1333 },
1334 Entry{ScalarEntry{&this->rvw_,
1335 [](const Context& ectx)
1336 { return getValue(ectx.fs.Rvw()); }
1337 }
1338 },
1339 Entry{ScalarEntry{&this->ppcw_,
1340 [&matLawManager = *this->simulator_.problem().materialLawManager()]
1341 (const Context& ectx)
1342 {
1343 return matLawManager.
1344 oilWaterScaledEpsInfoDrainage(ectx.globalDofIdx).maxPcow;
1345 }
1346 }
1347 },
1348 Entry{ScalarEntry{&this->drsdtcon_,
1349 [&problem = this->simulator_.problem()](const Context& ectx)
1350 {
1351 return problem.drsdtcon(ectx.globalDofIdx,
1352 ectx.episodeIndex);
1353 }
1354 }
1355 },
1356 Entry{ScalarEntry{&this->pcgw_,
1357 [](const Context& ectx)
1358 {
1359 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
1360 getValue(ectx.fs.pressure(waterPhaseIdx));
1361 }
1362 }
1363 },
1364 Entry{ScalarEntry{&this->pcow_,
1365 [](const Context& ectx)
1366 {
1367 return getValue(ectx.fs.pressure(oilPhaseIdx)) -
1368 getValue(ectx.fs.pressure(waterPhaseIdx));
1369 }
1370 }
1371 },
1372 Entry{ScalarEntry{&this->pcog_,
1373 [](const Context& ectx)
1374 {
1375 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
1376 getValue(ectx.fs.pressure(oilPhaseIdx));
1377 }
1378 }
1379 },
1380 Entry{ScalarEntry{&this->fluidPressure_,
1381 [](const Context& ectx)
1382 {
1383 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1384 // Output oil pressure as default
1385 return getValue(ectx.fs.pressure(oilPhaseIdx));
1386 }
1387 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1388 // Output gas if oil is not present
1389 return getValue(ectx.fs.pressure(gasPhaseIdx));
1390 }
1391 else {
1392 // Output water if neither oil nor gas is present
1393 return getValue(ectx.fs.pressure(waterPhaseIdx));
1394 }
1395 }
1396 }
1397 },
1398 Entry{ScalarEntry{&this->gasDissolutionFactor_,
1399 [&problem = this->simulator_.problem()](const Context& ectx)
1400 {
1401 const Scalar SoMax = problem.maxOilSaturation(ectx.globalDofIdx);
1402 return FluidSystem::template
1403 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1404 oilPhaseIdx,
1405 ectx.pvtRegionIdx,
1406 SoMax);
1407 }
1408 }
1409 },
1410 Entry{ScalarEntry{&this->oilVaporizationFactor_,
1411 [&problem = this->simulator_.problem()](const Context& ectx)
1412 {
1413 const Scalar SoMax = problem.maxOilSaturation(ectx.globalDofIdx);
1414 return FluidSystem::template
1415 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1416 gasPhaseIdx,
1417 ectx.pvtRegionIdx,
1418 SoMax);
1419 }
1420 }
1421 },
1422 Entry{ScalarEntry{&this->gasDissolutionFactorInWater_,
1423 [&problem = this->simulator_.problem()](const Context& ectx)
1424 {
1425 const Scalar SwMax = problem.maxWaterSaturation(ectx.globalDofIdx);
1426 return FluidSystem::template
1427 saturatedDissolutionFactor<FluidState, Scalar>(ectx.fs,
1428 waterPhaseIdx,
1429 ectx.pvtRegionIdx,
1430 SwMax);
1431 }
1432 }
1433 },
1434 Entry{ScalarEntry{&this->waterVaporizationFactor_,
1435 [](const Context& ectx)
1436 {
1437 return FluidSystem::template
1438 saturatedVaporizationFactor<FluidState, Scalar>(ectx.fs,
1439 gasPhaseIdx,
1440 ectx.pvtRegionIdx);
1441 }
1442 }
1443 },
1444 Entry{ScalarEntry{&this->gasFormationVolumeFactor_,
1445 [](const Context& ectx)
1446 {
1447 return 1.0 / FluidSystem::template
1448 inverseFormationVolumeFactor<FluidState, Scalar>(ectx.fs,
1449 gasPhaseIdx,
1450 ectx.pvtRegionIdx);
1451 }
1452 }
1453 },
1454 Entry{ScalarEntry{&this->saturatedOilFormationVolumeFactor_,
1455 [](const Context& ectx)
1456 {
1457 return 1.0 / FluidSystem::template
1458 saturatedInverseFormationVolumeFactor<FluidState, Scalar>(ectx.fs,
1459 oilPhaseIdx,
1460 ectx.pvtRegionIdx);
1461 }
1462 }
1463 },
1464 Entry{ScalarEntry{&this->oilSaturationPressure_,
1465 [](const Context& ectx)
1466 {
1467 return FluidSystem::template
1468 saturationPressure<FluidState, Scalar>(ectx.fs,
1469 oilPhaseIdx,
1470 ectx.pvtRegionIdx);
1471 }
1472 }
1473 },
1474 Entry{ScalarEntry{&this->soMax_,
1475 [&problem = this->simulator_.problem()](const Context& ectx)
1476 {
1477 return std::max(getValue(ectx.fs.saturation(oilPhaseIdx)),
1478 problem.maxOilSaturation(ectx.globalDofIdx));
1479 }
1480 },
1481 !hysteresisConfig.enableHysteresis()
1482 },
1483 Entry{ScalarEntry{&this->swMax_,
1484 [&problem = this->simulator_.problem()](const Context& ectx)
1485 {
1486 return std::max(getValue(ectx.fs.saturation(waterPhaseIdx)),
1487 problem.maxWaterSaturation(ectx.globalDofIdx));
1488 }
1489 },
1490 !hysteresisConfig.enableHysteresis()
1491 },
1492 Entry{ScalarEntry{&this->soMax_,
1493 [](const Context& ectx)
1494 { return ectx.hParams.somax; }
1495 },
1496 hysteresisConfig.enableHysteresis() &&
1497 hysteresisConfig.enableNonWettingHysteresis() &&
1498 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1499 FluidSystem::phaseIsActive(waterPhaseIdx)
1500 },
1501 Entry{ScalarEntry{&this->swMax_,
1502 [](const Context& ectx)
1503 { return ectx.hParams.swmax; }
1504 },
1505 hysteresisConfig.enableHysteresis() &&
1506 hysteresisConfig.enableWettingHysteresis() &&
1507 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1508 FluidSystem::phaseIsActive(waterPhaseIdx)
1509 },
1510 Entry{ScalarEntry{&this->swmin_,
1511 [](const Context& ectx)
1512 { return ectx.hParams.swmin; }
1513 },
1514 hysteresisConfig.enableHysteresis() &&
1515 hysteresisConfig.enablePCHysteresis() &&
1516 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1517 FluidSystem::phaseIsActive(waterPhaseIdx)
1518 },
1519 Entry{ScalarEntry{&this->sgmax_,
1520 [](const Context& ectx)
1521 { return ectx.hParams.sgmax; }
1522 },
1523 hysteresisConfig.enableHysteresis() &&
1524 hysteresisConfig.enableNonWettingHysteresis() &&
1525 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1526 FluidSystem::phaseIsActive(gasPhaseIdx)
1527 },
1528 Entry{ScalarEntry{&this->shmax_,
1529 [](const Context& ectx)
1530 { return ectx.hParams.shmax; }
1531 },
1532 hysteresisConfig.enableHysteresis() &&
1533 hysteresisConfig.enableWettingHysteresis() &&
1534 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1535 FluidSystem::phaseIsActive(gasPhaseIdx)
1536 },
1537 Entry{ScalarEntry{&this->somin_,
1538 [](const Context& ectx)
1539 { return ectx.hParams.somin; }
1540 },
1541 hysteresisConfig.enableHysteresis() &&
1542 hysteresisConfig.enablePCHysteresis() &&
1543 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1544 FluidSystem::phaseIsActive(gasPhaseIdx)
1545 },
1546 Entry{[&model = this->simulator_.model(), this](const Context& ectx)
1547 {
1548 // Note: We intentionally exclude effects of rock
1549 // compressibility by using referencePorosity() here.
1550 const auto porv = ectx.intQuants.referencePorosity()
1551 * model.dofTotalVolume(ectx.globalDofIdx);
1552
1553 this->aggregateAverageDensityContributions_(ectx.fs, ectx.globalDofIdx,
1554 static_cast<double>(porv));
1555 }, this->regionAvgDensity_.has_value()
1556 },
1557 Entry{[&extboC = this->extboC_](const Context& ectx)
1558 {
1559 extboC.assignVolumes(ectx.globalDofIdx,
1560 ectx.intQuants.xVolume().value(),
1561 ectx.intQuants.yVolume().value());
1562 extboC.assignZFraction(ectx.globalDofIdx,
1563 ectx.intQuants.zFraction().value());
1564
1565 const Scalar stdVolOil = getValue(ectx.fs.saturation(oilPhaseIdx)) *
1566 getValue(ectx.fs.invB(oilPhaseIdx)) +
1567 getValue(ectx.fs.saturation(gasPhaseIdx)) *
1568 getValue(ectx.fs.invB(gasPhaseIdx)) *
1569 getValue(ectx.fs.Rv());
1570 const Scalar stdVolGas = getValue(ectx.fs.saturation(gasPhaseIdx)) *
1571 getValue(ectx.fs.invB(gasPhaseIdx)) *
1572 (1.0 - ectx.intQuants.yVolume().value()) +
1573 getValue(ectx.fs.saturation(oilPhaseIdx)) *
1574 getValue(ectx.fs.invB(oilPhaseIdx)) *
1575 getValue(ectx.fs.Rs()) *
1576 (1.0 - ectx.intQuants.xVolume().value());
1577 const Scalar stdVolCo2 = getValue(ectx.fs.saturation(gasPhaseIdx)) *
1578 getValue(ectx.fs.invB(gasPhaseIdx)) *
1579 ectx.intQuants.yVolume().value() +
1580 getValue(ectx.fs.saturation(oilPhaseIdx)) *
1581 getValue(ectx.fs.invB(oilPhaseIdx)) *
1582 getValue(ectx.fs.Rs()) *
1583 ectx.intQuants.xVolume().value();
1584 const Scalar rhoO = FluidSystem::referenceDensity(gasPhaseIdx, ectx.pvtRegionIdx);
1585 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx, ectx.pvtRegionIdx);
1586 const Scalar rhoCO2 = ectx.intQuants.zRefDensity();
1587 const Scalar stdMassTotal = 1.0e-10 + stdVolOil * rhoO + stdVolGas * rhoG + stdVolCo2 * rhoCO2;
1588 extboC.assignMassFractions(ectx.globalDofIdx,
1589 stdVolGas * rhoG / stdMassTotal,
1590 stdVolOil * rhoO / stdMassTotal,
1591 stdVolCo2 * rhoCO2 / stdMassTotal);
1592 }, this->extboC_.allocated()
1593 },
1594 Entry{[&bioeffectsC = this->bioeffectsC_](const Context& ectx)
1595 {
1596 bioeffectsC.assign(ectx.globalDofIdx,
1597 ectx.intQuants.microbialConcentration().value(),
1598 ectx.intQuants.biofilmVolumeFraction().value());
1599 if (Indices::enableMICP) {
1600 bioeffectsC.assign(ectx.globalDofIdx,
1601 ectx.intQuants.oxygenConcentration().value(),
1602 ectx.intQuants.ureaConcentration().value(),
1603 ectx.intQuants.calciteVolumeFraction().value());
1604 }
1605 }, this->bioeffectsC_.allocated()
1606 },
1607 Entry{[&rftC = this->rftC_,
1608 &vanguard = this->simulator_.vanguard()](const Context& ectx)
1609 {
1610 const auto cartesianIdx = vanguard.cartesianIndex(ectx.globalDofIdx);
1611 rftC.assign(cartesianIdx,
1612 [&fs = ectx.fs]() { return getValue(fs.pressure(oilPhaseIdx)); },
1613 [&fs = ectx.fs]() { return getValue(fs.saturation(waterPhaseIdx)); },
1614 [&fs = ectx.fs]() { return getValue(fs.saturation(gasPhaseIdx)); });
1615 }
1616 },
1617 Entry{[&tC = this->tracerC_,
1618 &tM = this->simulator_.problem().tracerModel()](const Context& ectx)
1619 {
1620 tC.assignFreeConcentrations(ectx.globalDofIdx,
1621 [gIdx = ectx.globalDofIdx, &tM](const unsigned tracerIdx)
1622 { return tM.freeTracerConcentration(tracerIdx, gIdx); });
1623 tC.assignSolConcentrations(ectx.globalDofIdx,
1624 [gIdx = ectx.globalDofIdx, &tM](const unsigned tracerIdx)
1625 { return tM.solTracerConcentration(tracerIdx, gIdx); });
1626 }
1627 },
1628 Entry{[&flowsInf = this->simulator_.problem().model().linearizer().getFlowsInfo(),
1629 &flowsC = this->flowsC_](const Context& ectx)
1630 {
1631 const auto gas_idx = Indices::gasEnabled ?
1632 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(gasCompIdx) : -1;
1633 const auto oil_idx = Indices::oilEnabled ?
1634 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(oilCompIdx) : -1;
1635 const auto water_idx = Indices::waterEnabled ?
1636 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(waterCompIdx) : -1;
1637 const auto& flowsInfos = flowsInf[ectx.globalDofIdx];
1638 for (const auto& flowsInfo : flowsInfos) {
1639 flowsC.assignFlows(ectx.globalDofIdx,
1640 flowsInfo.faceId,
1641 flowsInfo.nncId,
1642 value_or_zero(gas_idx, flowsInfo.flow),
1643 value_or_zero(oil_idx, flowsInfo.flow),
1644 value_or_zero(water_idx, flowsInfo.flow));
1645 }
1646 }, !this->simulator_.problem().model().linearizer().getFlowsInfo().empty()
1647 },
1648 Entry{[&floresInf = this->simulator_.problem().model().linearizer().getFloresInfo(),
1649 &flowsC = this->flowsC_](const Context& ectx)
1650 {
1651 const auto gas_idx = Indices::gasEnabled ?
1652 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(gasCompIdx) : -1;
1653 const auto oil_idx = Indices::oilEnabled ?
1654 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(oilCompIdx) : -1;
1655 const auto water_idx = Indices::waterEnabled ?
1656 conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(waterCompIdx) : -1;
1657 const auto& floresInfos = floresInf[ectx.globalDofIdx];
1658 for (const auto& floresInfo : floresInfos) {
1659 flowsC.assignFlores(ectx.globalDofIdx,
1660 floresInfo.faceId,
1661 floresInfo.nncId,
1662 value_or_zero(gas_idx, floresInfo.flow),
1663 value_or_zero(oil_idx, floresInfo.flow),
1664 value_or_zero(water_idx, floresInfo.flow));
1665 }
1666 }, !this->simulator_.problem().model().linearizer().getFloresInfo().empty()
1667 },
1668 // hack to make the intial output of rs and rv Ecl compatible.
1669 // For cells with swat == 1 Ecl outputs; rs = rsSat and rv=rvSat, in all but the initial step
1670 // where it outputs rs and rv values calculated by the initialization. To be compatible we overwrite
1671 // rs and rv with the values computed in the initially.
1672 // Volume factors, densities and viscosities need to be recalculated with the updated rs and rv values.
1673 Entry{ScalarEntry{&this->rv_,
1674 [&problem = this->simulator_.problem()](const Context& ectx)
1675 { return problem.initialFluidState(ectx.globalDofIdx).Rv(); }
1676 },
1677 simulator_.episodeIndex() < 0 &&
1678 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1679 FluidSystem::phaseIsActive(gasPhaseIdx)
1680 },
1681 Entry{ScalarEntry{&this->rs_,
1682 [&problem = this->simulator_.problem()](const Context& ectx)
1683 { return problem.initialFluidState(ectx.globalDofIdx).Rs(); }
1684 },
1685 simulator_.episodeIndex() < 0 &&
1686 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1687 FluidSystem::phaseIsActive(gasPhaseIdx)
1688 },
1689 Entry{ScalarEntry{&this->rsw_,
1690 [&problem = this->simulator_.problem()](const Context& ectx)
1691 { return problem.initialFluidState(ectx.globalDofIdx).Rsw(); }
1692 },
1693 simulator_.episodeIndex() < 0 &&
1694 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1695 FluidSystem::phaseIsActive(gasPhaseIdx)
1696 },
1697 Entry{ScalarEntry{&this->rvw_,
1698 [&problem = this->simulator_.problem()](const Context& ectx)
1699 { return problem.initialFluidState(ectx.globalDofIdx).Rvw(); }
1700 },
1701 simulator_.episodeIndex() < 0 &&
1702 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1703 FluidSystem::phaseIsActive(gasPhaseIdx)
1704 },
1705 // re-compute the volume factors, viscosities and densities if asked for
1706 Entry{PhaseEntry{&this->density_,
1707 [&problem = this->simulator_.problem()](const unsigned phase,
1708 const Context& ectx)
1709 {
1710 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1711 return FluidSystem::density(fsInitial,
1712 phase,
1713 ectx.intQuants.pvtRegionIndex());
1714 }
1715 },
1716 simulator_.episodeIndex() < 0 &&
1717 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1718 FluidSystem::phaseIsActive(gasPhaseIdx)
1719 },
1720 Entry{PhaseEntry{&this->invB_,
1721 [&problem = this->simulator_.problem()](const unsigned phase,
1722 const Context& ectx)
1723 {
1724 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1725 return FluidSystem::inverseFormationVolumeFactor(fsInitial,
1726 phase,
1727 ectx.intQuants.pvtRegionIndex());
1728 }
1729 },
1730 simulator_.episodeIndex() < 0 &&
1731 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1732 FluidSystem::phaseIsActive(gasPhaseIdx)
1733 },
1734 Entry{PhaseEntry{&this->viscosity_,
1735 [&problem = this->simulator_.problem()](const unsigned phase,
1736 const Context& ectx)
1737 {
1738 const auto& fsInitial = problem.initialFluidState(ectx.globalDofIdx);
1739 return FluidSystem::viscosity(fsInitial,
1740 phase,
1741 ectx.intQuants.pvtRegionIndex());
1742 }
1743 },
1744 simulator_.episodeIndex() < 0 &&
1745 FluidSystem::phaseIsActive(oilPhaseIdx) &&
1746 FluidSystem::phaseIsActive(gasPhaseIdx)
1747 },
1748 };
1749
1750 // Setup active extractors
1751 this->extractors_ = Extractor::removeInactive(extractors);
1752
1753 if constexpr (getPropValue<TypeTag, Properties::EnableMech>()) {
1754 if (this->mech_.allocated()) {
1755 this->extractors_.push_back(
1756 Entry{[&mech = this->mech_,
1757 &model = simulator_.problem().geoMechModel()](const Context& ectx)
1758 {
1759 mech.assignDelStress(ectx.globalDofIdx,
1760 model.delstress(ectx.globalDofIdx));
1761
1762 mech.assignDisplacement(ectx.globalDofIdx,
1763 model.disp(ectx.globalDofIdx, /*include_fracture*/true));
1764
1765 // is the tresagii stress which make rock fracture
1766 mech.assignFracStress(ectx.globalDofIdx,
1767 model.fractureStress(ectx.globalDofIdx));
1768
1769 mech.assignLinStress(ectx.globalDofIdx,
1770 model.linstress(ectx.globalDofIdx));
1771
1772 mech.assignPotentialForces(ectx.globalDofIdx,
1773 model.mechPotentialForce(ectx.globalDofIdx),
1774 model.mechPotentialPressForce(ectx.globalDofIdx),
1775 model.mechPotentialTempForce(ectx.globalDofIdx));
1776
1777 mech.assignStrain(ectx.globalDofIdx,
1778 model.strain(ectx.globalDofIdx, /*include_fracture*/true));
1779
1780 // Total stress is not stored but calculated result is Voigt notation
1781 mech.assignStress(ectx.globalDofIdx,
1782 model.stress(ectx.globalDofIdx, /*include_fracture*/true));
1783 }
1784 }
1785 );
1786 }
1787 }
1788 }
1789
1791 void setupBlockExtractors_(const bool isSubStep,
1792 const int reportStepNum)
1793 {
1794 using Entry = typename BlockExtractor::Entry;
1795 using Context = typename BlockExtractor::Context;
1796 using PhaseEntry = typename BlockExtractor::PhaseEntry;
1797 using ScalarEntry = typename BlockExtractor::ScalarEntry;
1798
1799 using namespace std::string_view_literals;
1800
1801 const auto pressure_handler =
1802 Entry{ScalarEntry{std::vector{"BPR"sv, "BPRESSUR"sv},
1803 [](const Context& ectx)
1804 {
1805 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1806 return getValue(ectx.fs.pressure(oilPhaseIdx));
1807 }
1808 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1809 return getValue(ectx.fs.pressure(gasPhaseIdx));
1810 }
1811 else { //if (FluidSystem::phaseIsActive(waterPhaseIdx))
1812 return getValue(ectx.fs.pressure(waterPhaseIdx));
1813 }
1814 }
1815 }
1816 };
1817
1818 const auto handlers = std::array{
1819 pressure_handler,
1820 Entry{PhaseEntry{std::array{
1821 std::array{"BWSAT"sv, "BOSAT"sv, "BGSAT"sv},
1822 std::array{"BSWAT"sv, "BSOIL"sv, "BSGAS"sv}
1823 },
1824 [](const unsigned phaseIdx, const Context& ectx)
1825 {
1826 return getValue(ectx.fs.saturation(phaseIdx));
1827 }
1828 }
1829 },
1830 Entry{ScalarEntry{"BNSAT",
1831 [](const Context& ectx)
1832 {
1833 return ectx.intQuants.solventSaturation().value();
1834 }
1835 }
1836 },
1837 Entry{ScalarEntry{std::vector{"BTCNFHEA"sv, "BTEMP"sv},
1838 [](const Context& ectx)
1839 {
1840 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1841 return getValue(ectx.fs.temperature(oilPhaseIdx));
1842 }
1843 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
1844 return getValue(ectx.fs.temperature(gasPhaseIdx));
1845 }
1846 else { //if (FluidSystem::phaseIsActive(waterPhaseIdx))
1847 return getValue(ectx.fs.temperature(waterPhaseIdx));
1848 }
1849 }
1850 }
1851 },
1852 Entry{PhaseEntry{std::array{
1853 std::array{"BWKR"sv, "BOKR"sv, "BGKR"sv},
1854 std::array{"BKRW"sv, "BKRO"sv, "BKRG"sv}
1855 },
1856 [](const unsigned phaseIdx, const Context& ectx)
1857 {
1858 return getValue(ectx.intQuants.relativePermeability(phaseIdx));
1859 }
1860 }
1861 },
1862 Entry{ScalarEntry{"BKROG",
1863 [&problem = this->simulator_.problem()](const Context& ectx)
1864 {
1865 const auto& materialParams =
1866 problem.materialLawParams(ectx.elemCtx,
1867 ectx.dofIdx,
1868 /* timeIdx = */ 0);
1869 return getValue(MaterialLaw::template
1870 relpermOilInOilGasSystem<Evaluation>(materialParams,
1871 ectx.fs));
1872 }
1873 }
1874 },
1875 Entry{ScalarEntry{"BKROW",
1876 [&problem = this->simulator_.problem()](const Context& ectx)
1877 {
1878 const auto& materialParams = problem.materialLawParams(ectx.elemCtx,
1879 ectx.dofIdx,
1880 /* timeIdx = */ 0);
1881 return getValue(MaterialLaw::template
1882 relpermOilInOilWaterSystem<Evaluation>(materialParams,
1883 ectx.fs));
1884 }
1885 }
1886 },
1887 Entry{ScalarEntry{"BWPC",
1888 [](const Context& ectx)
1889 {
1890 return getValue(ectx.fs.pressure(oilPhaseIdx)) -
1891 getValue(ectx.fs.pressure(waterPhaseIdx));
1892 }
1893 }
1894 },
1895 Entry{ScalarEntry{"BGPC",
1896 [](const Context& ectx)
1897 {
1898 return getValue(ectx.fs.pressure(gasPhaseIdx)) -
1899 getValue(ectx.fs.pressure(oilPhaseIdx));
1900 }
1901 }
1902 },
1903 Entry{ScalarEntry{"BWPR",
1904 [](const Context& ectx)
1905 {
1906 return getValue(ectx.fs.pressure(waterPhaseIdx));
1907 }
1908 }
1909 },
1910 Entry{ScalarEntry{"BGPR",
1911 [](const Context& ectx)
1912 {
1913 return getValue(ectx.fs.pressure(gasPhaseIdx));
1914 }
1915 }
1916 },
1917 Entry{PhaseEntry{std::array{
1918 std::array{"BVWAT"sv, "BVOIL"sv, "BVGAS"sv},
1919 std::array{"BWVIS"sv, "BOVIS"sv, "BGVIS"sv}
1920 },
1921 [](const unsigned phaseIdx, const Context& ectx)
1922 {
1923 return getValue(ectx.fs.viscosity(phaseIdx));
1924 }
1925 }
1926 },
1927 Entry{PhaseEntry{std::array{
1928 std::array{"BWDEN"sv, "BODEN"sv, "BGDEN"sv},
1929 std::array{"BDENW"sv, "BDENO"sv, "BDENG"sv}
1930 },
1931 [](const unsigned phaseIdx, const Context& ectx)
1932 {
1933 return getValue(ectx.fs.density(phaseIdx));
1934 }
1935 }
1936 },
1937 Entry{ScalarEntry{"BFLOWI",
1938 [&flowsC = this->flowsC_](const Context& ectx)
1939 {
1940 return flowsC.getFlow(ectx.globalDofIdx, Dir::XPlus, waterCompIdx);
1941 }
1942 }
1943 },
1944 Entry{ScalarEntry{"BFLOWJ",
1945 [&flowsC = this->flowsC_](const Context& ectx)
1946 {
1947 return flowsC.getFlow(ectx.globalDofIdx, Dir::YPlus, waterCompIdx);
1948 }
1949 }
1950 },
1951 Entry{ScalarEntry{"BFLOWK",
1952 [&flowsC = this->flowsC_](const Context& ectx)
1953 {
1954 return flowsC.getFlow(ectx.globalDofIdx, Dir::ZPlus, waterCompIdx);
1955 }
1956 }
1957 },
1958 Entry{ScalarEntry{"BRPV",
1959 [&model = this->simulator_.model()](const Context& ectx)
1960 {
1961 return getValue(ectx.intQuants.porosity()) *
1962 model.dofTotalVolume(ectx.globalDofIdx);
1963 }
1964 }
1965 },
1966 Entry{PhaseEntry{std::array{"BWPV"sv, "BOPV"sv, "BGPV"sv},
1967 [&model = this->simulator_.model()](const unsigned phaseIdx,
1968 const Context& ectx)
1969 {
1970 return getValue(ectx.fs.saturation(phaseIdx)) *
1971 getValue(ectx.intQuants.porosity()) *
1972 model.dofTotalVolume(ectx.globalDofIdx);
1973 }
1974 }
1975 },
1976 Entry{ScalarEntry{"BRS",
1977 [](const Context& ectx)
1978 {
1979 return getValue(ectx.fs.Rs());
1980 }
1981 }
1982 },
1983 Entry{ScalarEntry{"BRV",
1984 [](const Context& ectx)
1985 {
1986 return getValue(ectx.fs.Rv());
1987 }
1988 }
1989 },
1990 Entry{ScalarEntry{"BOIP",
1991 [&model = this->simulator_.model()](const Context& ectx)
1992 {
1993 return (getValue(ectx.fs.invB(oilPhaseIdx)) *
1994 getValue(ectx.fs.saturation(oilPhaseIdx)) +
1995 getValue(ectx.fs.Rv()) *
1996 getValue(ectx.fs.invB(gasPhaseIdx)) *
1997 getValue(ectx.fs.saturation(gasPhaseIdx))) *
1998 model.dofTotalVolume(ectx.globalDofIdx) *
1999 getValue(ectx.intQuants.porosity());
2000 }
2001 }
2002 },
2003 Entry{ScalarEntry{"BGIP",
2004 [&model = this->simulator_.model()](const Context& ectx)
2005 {
2006 Scalar result = getValue(ectx.fs.invB(gasPhaseIdx)) *
2007 getValue(ectx.fs.saturation(gasPhaseIdx));
2008
2009 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2010 result += getValue(ectx.fs.Rs()) *
2011 getValue(ectx.fs.invB(oilPhaseIdx)) *
2012 getValue(ectx.fs.saturation(oilPhaseIdx));
2013 }
2014 else {
2015 result += getValue(ectx.fs.Rsw()) *
2016 getValue(ectx.fs.invB(waterPhaseIdx)) *
2017 getValue(ectx.fs.saturation(waterPhaseIdx));
2018 }
2019
2020 return result *
2021 model.dofTotalVolume(ectx.globalDofIdx) *
2022 getValue(ectx.intQuants.porosity());
2023 }
2024 }
2025 },
2026 Entry{ScalarEntry{"BWIP",
2027 [&model = this->simulator_.model()](const Context& ectx)
2028 {
2029 return getValue(ectx.fs.invB(waterPhaseIdx)) *
2030 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2031 model.dofTotalVolume(ectx.globalDofIdx) *
2032 getValue(ectx.intQuants.porosity());
2033 }
2034 }
2035 },
2036 Entry{ScalarEntry{"BOIPL",
2037 [&model = this->simulator_.model()](const Context& ectx)
2038 {
2039 return getValue(ectx.fs.invB(oilPhaseIdx)) *
2040 getValue(ectx.fs.saturation(oilPhaseIdx)) *
2041 model.dofTotalVolume(ectx.globalDofIdx) *
2042 getValue(ectx.intQuants.porosity());
2043 }
2044 }
2045 },
2046 Entry{ScalarEntry{"BGIPL",
2047 [&model = this->simulator_.model()](const Context& ectx)
2048 {
2049 Scalar result;
2050 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2051 result = getValue(ectx.fs.Rs()) *
2052 getValue(ectx.fs.invB(oilPhaseIdx)) *
2053 getValue(ectx.fs.saturation(oilPhaseIdx));
2054 }
2055 else {
2056 result = getValue(ectx.fs.Rsw()) *
2057 getValue(ectx.fs.invB(waterPhaseIdx)) *
2058 getValue(ectx.fs.saturation(waterPhaseIdx));
2059 }
2060 return result *
2061 model.dofTotalVolume(ectx.globalDofIdx) *
2062 getValue(ectx.intQuants.porosity());
2063 }
2064 }
2065 },
2066 Entry{ScalarEntry{"BGIPG",
2067 [&model = this->simulator_.model()](const Context& ectx)
2068 {
2069 return getValue(ectx.fs.invB(gasPhaseIdx)) *
2070 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2071 model.dofTotalVolume(ectx.globalDofIdx) *
2072 getValue(ectx.intQuants.porosity());
2073 }
2074 }
2075 },
2076 Entry{ScalarEntry{"BOIPG",
2077 [&model = this->simulator_.model()](const Context& ectx)
2078 {
2079 return getValue(ectx.fs.Rv()) *
2080 getValue(ectx.fs.invB(gasPhaseIdx)) *
2081 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2082 model.dofTotalVolume(ectx.globalDofIdx) *
2083 getValue(ectx.intQuants.porosity());
2084 }
2085 }
2086 },
2087 Entry{PhaseEntry{std::array{"BPPW"sv, "BPPO"sv, "BPPG"sv},
2088 [&simConfig = this->eclState_.getSimulationConfig(),
2089 &grav = this->simulator_.problem().gravity(),
2090 &regionAvgDensity = this->regionAvgDensity_,
2091 &problem = this->simulator_.problem(),
2092 &regions = this->regions_](const unsigned phaseIdx, const Context& ectx)
2093 {
2094 auto phase = RegionPhasePoreVolAverage::Phase{};
2095 phase.ix = phaseIdx;
2096
2097 // Note different region handling here. FIPNUM is
2098 // one-based, but we need zero-based lookup in
2099 // DatumDepth. On the other hand, pvtRegionIndex is
2100 // zero-based but we need one-based lookup in
2101 // RegionPhasePoreVolAverage.
2102
2103 // Subtract one to convert FIPNUM to region index.
2104 const auto datum = simConfig.datumDepths()(regions["FIPNUM"][ectx.dofIdx] - 1);
2105
2106 // Add one to convert region index to region ID.
2107 const auto region = RegionPhasePoreVolAverage::Region {
2108 ectx.elemCtx.primaryVars(ectx.dofIdx, /*timeIdx=*/0).pvtRegionIndex() + 1
2109 };
2110
2111 const auto density = regionAvgDensity->value("PVTNUM", phase, region);
2112
2113 const auto press = getValue(ectx.fs.pressure(phase.ix));
2114 const auto dz = problem.dofCenterDepth(ectx.globalDofIdx) - datum;
2115 return press - density*dz*grav[GridView::dimensionworld - 1];
2116 }
2117 }
2118 },
2119 Entry{ScalarEntry{"BAMIP",
2120 [&model = this->simulator_.model()](const Context& ectx)
2121 {
2122 const Scalar rhoW = FluidSystem::referenceDensity(waterPhaseIdx,
2123 ectx.intQuants.pvtRegionIndex());
2124 return getValue(ectx.fs.invB(waterPhaseIdx)) *
2125 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2126 rhoW *
2127 model.dofTotalVolume(ectx.globalDofIdx) *
2128 getValue(ectx.intQuants.porosity());
2129 }
2130 }
2131 },
2132 Entry{ScalarEntry{"BMMIP",
2133 [&model = this->simulator_.model()](const Context& ectx)
2134 {
2135 return getValue(ectx.intQuants.microbialConcentration()) *
2136 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2137 getValue(ectx.intQuants.porosity()) *
2138 model.dofTotalVolume(ectx.globalDofIdx);
2139 }
2140 }
2141 },
2142 Entry{ScalarEntry{"BMOIP",
2143 [&model = this->simulator_.model()](const Context& ectx)
2144 {
2145 return getValue(ectx.intQuants.oxygenConcentration()) *
2146 getValue(ectx.intQuants.porosity()) *
2147 model.dofTotalVolume(ectx.globalDofIdx);
2148 }
2149 }
2150 },
2151 Entry{ScalarEntry{"BMUIP",
2152 [&model = this->simulator_.model()](const Context& ectx)
2153 {
2154 return getValue(ectx.intQuants.ureaConcentration()) *
2155 getValue(ectx.intQuants.porosity()) *
2156 model.dofTotalVolume(ectx.globalDofIdx) * 1;
2157 }
2158 }
2159 },
2160 Entry{ScalarEntry{"BMBIP",
2161 [&model = this->simulator_.model()](const Context& ectx)
2162 {
2163 return model.dofTotalVolume(ectx.globalDofIdx) *
2164 getValue(ectx.intQuants.biofilmMass());
2165 }
2166 }
2167 },
2168 Entry{ScalarEntry{"BMCIP",
2169 [&model = this->simulator_.model()](const Context& ectx)
2170 {
2171 return model.dofTotalVolume(ectx.globalDofIdx) *
2172 getValue(ectx.intQuants.calciteMass());
2173 }
2174 }
2175 },
2176 Entry{ScalarEntry{"BGMIP",
2177 [&model = this->simulator_.model()](const Context& ectx)
2178 {
2179 Scalar result = getValue(ectx.fs.invB(gasPhaseIdx)) *
2180 getValue(ectx.fs.saturation(gasPhaseIdx));
2181
2182 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2183 result += getValue(ectx.fs.Rs()) *
2184 getValue(ectx.fs.invB(oilPhaseIdx)) *
2185 getValue(ectx.fs.saturation(oilPhaseIdx));
2186 }
2187 else {
2188 result += getValue(ectx.fs.Rsw()) *
2189 getValue(ectx.fs.invB(waterPhaseIdx)) *
2190 getValue(ectx.fs.saturation(waterPhaseIdx));
2191 }
2192 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2193 ectx.intQuants.pvtRegionIndex());
2194 return result *
2195 model.dofTotalVolume(ectx.globalDofIdx) *
2196 getValue(ectx.intQuants.porosity()) *
2197 rhoG;
2198 }
2199 }
2200 },
2201 Entry{ScalarEntry{"BGMGP",
2202 [&model = this->simulator_.model()](const Context& ectx)
2203 {
2204 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2205 ectx.intQuants.pvtRegionIndex());
2206 return getValue(ectx.fs.invB(gasPhaseIdx)) *
2207 getValue(ectx.fs.saturation(gasPhaseIdx)) *
2208 model.dofTotalVolume(ectx.globalDofIdx) *
2209 getValue(ectx.intQuants.porosity()) *
2210 rhoG;
2211 }
2212 }
2213 },
2214 Entry{ScalarEntry{"BGMDS",
2215 [&model = this->simulator_.model()](const Context& ectx)
2216 {
2217 Scalar result;
2218 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2219 result = getValue(ectx.fs.Rs()) *
2220 getValue(ectx.fs.invB(oilPhaseIdx)) *
2221 getValue(ectx.fs.saturation(oilPhaseIdx));
2222 }
2223 else {
2224 result = getValue(ectx.fs.Rsw()) *
2225 getValue(ectx.fs.invB(waterPhaseIdx)) *
2226 getValue(ectx.fs.saturation(waterPhaseIdx));
2227 }
2228 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2229 ectx.intQuants.pvtRegionIndex());
2230 return result *
2231 model.dofTotalVolume(ectx.globalDofIdx) *
2232 getValue(ectx.intQuants.porosity()) *
2233 rhoG;
2234 }
2235 }
2236 },
2237 Entry{ScalarEntry{"BGMST",
2238 [&model = this->simulator_.model(),
2239 &problem = this->simulator_.problem()](const Context& ectx)
2240 {
2241 const auto& scaledDrainageInfo = problem.materialLawManager()
2242 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2243 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2244 Scalar strandedGas = scaledDrainageInfo.Sgcr;
2245 if (problem.materialLawManager()->enableHysteresis()) {
2246 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2247 const Scalar krg = getValue(ectx.intQuants.relativePermeability(gasPhaseIdx));
2248 strandedGas = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
2249 }
2250 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2251 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2252 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2253 return (1.0 - xgW) *
2254 model.dofTotalVolume(ectx.globalDofIdx) *
2255 getValue(ectx.intQuants.porosity()) *
2256 getValue(ectx.fs.density(gasPhaseIdx)) *
2257 std::min(strandedGas, sg);
2258 }
2259 }
2260 },
2261 Entry{ScalarEntry{"BGMUS",
2262 [&model = this->simulator_.model(),
2263 &problem = this->simulator_.problem()](const Context& ectx)
2264 {
2265 const auto& scaledDrainageInfo = problem.materialLawManager()
2266 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2267 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2268 Scalar strandedGas = scaledDrainageInfo.Sgcr;
2269 if (problem.materialLawManager()->enableHysteresis()) {
2270 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2271 const Scalar krg = getValue(ectx.intQuants.relativePermeability(gasPhaseIdx));
2272 strandedGas = MaterialLaw::strandedGasSaturation(matParams, sg, krg);
2273 }
2274 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2275 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2276 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2277 return (1.0 - xgW) *
2278 model.dofTotalVolume(ectx.globalDofIdx) *
2279 getValue(ectx.intQuants.porosity()) *
2280 getValue(ectx.fs.density(gasPhaseIdx)) *
2281 std::max(Scalar{0.0}, sg - strandedGas);
2282 }
2283 }
2284 },
2285 Entry{ScalarEntry{"BGMTR",
2286 [&model = this->simulator_.model(),
2287 &problem = this->simulator_.problem()](const Context& ectx)
2288 {
2289 const auto& scaledDrainageInfo = problem.materialLawManager()
2290 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2291 Scalar trappedGas = scaledDrainageInfo.Sgcr;
2292 if (problem.materialLawManager()->enableHysteresis()) {
2293 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2294 trappedGas = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/true);
2295 }
2296 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2297 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2298 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2299 return (1.0 - xgW) *
2300 model.dofTotalVolume(ectx.globalDofIdx) *
2301 getValue(ectx.intQuants.porosity()) *
2302 getValue(ectx.fs.density(gasPhaseIdx)) *
2303 std::min(trappedGas, getValue(ectx.fs.saturation(gasPhaseIdx)));
2304 }
2305 }
2306 },
2307 Entry{ScalarEntry{"BGMMO",
2308 [&model = this->simulator_.model(),
2309 &problem = this->simulator_.problem()](const Context& ectx)
2310 {
2311 const auto& scaledDrainageInfo = problem.materialLawManager()
2312 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2313 Scalar trappedGas = scaledDrainageInfo.Sgcr;
2314 if (problem.materialLawManager()->enableHysteresis()) {
2315 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2316 trappedGas = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/true);
2317 }
2318 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2319 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2320 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2321 return (1.0 - xgW) *
2322 model.dofTotalVolume(ectx.globalDofIdx) *
2323 getValue(ectx.intQuants.porosity()) *
2324 getValue(ectx.fs.density(gasPhaseIdx)) *
2325 std::max(Scalar{0.0}, getValue(ectx.fs.saturation(gasPhaseIdx)) - trappedGas);
2326 }
2327 }
2328 },
2329 Entry{ScalarEntry{"BGKTR",
2330 [&model = this->simulator_.model(),
2331 &problem = this->simulator_.problem()](const Context& ectx)
2332 {
2333 const auto& scaledDrainageInfo = problem.materialLawManager()
2334 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2335 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2336 Scalar sgcr = scaledDrainageInfo.Sgcr;
2337 if (problem.materialLawManager()->enableHysteresis()) {
2338 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2339 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2340 }
2341 if (sg > sgcr) {
2342 return 0.0;
2343 }
2344 else {
2345 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2346 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2347 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2348 return (1.0 - xgW) *
2349 model.dofTotalVolume(ectx.globalDofIdx) *
2350 getValue(ectx.intQuants.porosity()) *
2351 getValue(ectx.fs.density(gasPhaseIdx)) *
2352 getValue(ectx.fs.saturation(gasPhaseIdx));
2353 }
2354 }
2355 }
2356 },
2357 Entry{ScalarEntry{"BGKMO",
2358 [&model = this->simulator_.model(),
2359 &problem = this->simulator_.problem()](const Context& ectx)
2360 {
2361 const auto& scaledDrainageInfo = problem.materialLawManager()
2362 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2363 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2364 Scalar sgcr = scaledDrainageInfo.Sgcr;
2365 if (problem.materialLawManager()->enableHysteresis()) {
2366 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2367 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2368 }
2369 if (sgcr >= sg) {
2370 return 0.0;
2371 }
2372 else {
2373 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2374 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2375 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2376 return (1.0 - xgW) *
2377 model.dofTotalVolume(ectx.globalDofIdx) *
2378 getValue(ectx.intQuants.porosity()) *
2379 getValue(ectx.fs.density(gasPhaseIdx)) *
2380 getValue(ectx.fs.saturation(gasPhaseIdx));
2381 }
2382 }
2383 }
2384 },
2385 Entry{ScalarEntry{"BGCDI",
2386 [&model = this->simulator_.model(),
2387 &problem = this->simulator_.problem()](const Context& ectx)
2388 {
2389 const auto& scaledDrainageInfo = problem.materialLawManager()
2390 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2391 Scalar sgcr = scaledDrainageInfo.Sgcr;
2392 if (problem.materialLawManager()->enableHysteresis()) {
2393 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2394 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2395 }
2396 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2397 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2398 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2399 return (1.0 - xgW) *
2400 model.dofTotalVolume(ectx.globalDofIdx) *
2401 getValue(ectx.intQuants.porosity()) *
2402 getValue(ectx.fs.density(gasPhaseIdx)) *
2403 std::min(sgcr, getValue(ectx.fs.saturation(gasPhaseIdx))) /
2404 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2405 }
2406 }
2407 },
2408 Entry{ScalarEntry{"BGCDM",
2409 [&model = this->simulator_.model(),
2410 &problem = this->simulator_.problem()](const Context& ectx)
2411 {
2412 const auto& scaledDrainageInfo = problem.materialLawManager()
2413 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2414 Scalar sgcr = scaledDrainageInfo.Sgcr;
2415 if (problem.materialLawManager()->enableHysteresis()) {
2416 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2417 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2418 }
2419 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2420 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2421 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2422 return (1.0 - xgW) *
2423 model.dofTotalVolume(ectx.globalDofIdx) *
2424 getValue(ectx.intQuants.porosity()) *
2425 getValue(ectx.fs.density(gasPhaseIdx)) *
2426 std::max(Scalar{0.0}, getValue(ectx.fs.saturation(gasPhaseIdx)) - sgcr) /
2427 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2428 }
2429 }
2430 },
2431 Entry{ScalarEntry{"BGKDI",
2432 [&model = this->simulator_.model(),
2433 &problem = this->simulator_.problem()](const Context& ectx)
2434 {
2435 const auto& scaledDrainageInfo = problem.materialLawManager()
2436 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2437 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2438 Scalar sgcr = scaledDrainageInfo.Sgcr;
2439 if (problem.materialLawManager()->enableHysteresis()) {
2440 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2441 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2442 }
2443 if (sg > sgcr) {
2444 return 0.0;
2445 }
2446 else {
2447 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2448 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2449 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2450 return (1.0 - xgW) *
2451 model.dofTotalVolume(ectx.globalDofIdx) *
2452 getValue(ectx.intQuants.porosity()) *
2453 getValue(ectx.fs.density(gasPhaseIdx)) *
2454 getValue(ectx.fs.saturation(gasPhaseIdx)) /
2455 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2456 }
2457 }
2458 }
2459 },
2460 Entry{ScalarEntry{"BGKDM",
2461 [&model = this->simulator_.model(),
2462 &problem = this->simulator_.problem()](const Context& ectx)
2463 {
2464 const auto& scaledDrainageInfo = problem.materialLawManager()
2465 ->oilWaterScaledEpsInfoDrainage(ectx.dofIdx);
2466 const Scalar sg = getValue(ectx.fs.saturation(gasPhaseIdx));
2467 Scalar sgcr = scaledDrainageInfo.Sgcr;
2468 if (problem.materialLawManager()->enableHysteresis()) {
2469 const auto& matParams = problem.materialLawParams(ectx.dofIdx);
2470 sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maxTrapping*/false);
2471 }
2472 if (sgcr >= sg) {
2473 return 0.0;
2474 }
2475 else {
2476 const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) ?
2477 FluidSystem::convertRvwToXgW(getValue(ectx.fs.Rvw()), ectx.intQuants.pvtRegionIndex())
2478 : FluidSystem::convertRvToXgO(getValue(ectx.fs.Rv()), ectx.intQuants.pvtRegionIndex());
2479 return (1.0 - xgW) *
2480 model.dofTotalVolume(ectx.globalDofIdx) *
2481 getValue(ectx.intQuants.porosity()) *
2482 getValue(ectx.fs.density(gasPhaseIdx)) *
2483 getValue(ectx.fs.saturation(gasPhaseIdx)) /
2484 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2485 }
2486 }
2487 }
2488 },
2489 Entry{ScalarEntry{"BWCD",
2490 [&model = this->simulator_.model()](const Context& ectx)
2491 {
2492 Scalar result;
2493 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
2494 result = getValue(ectx.fs.Rs()) *
2495 getValue(ectx.fs.invB(oilPhaseIdx)) *
2496 getValue(ectx.fs.saturation(oilPhaseIdx));
2497 }
2498 else {
2499 result = getValue(ectx.fs.Rsw()) *
2500 getValue(ectx.fs.invB(waterPhaseIdx)) *
2501 getValue(ectx.fs.saturation(waterPhaseIdx));
2502 }
2503 const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx,
2504 ectx.intQuants.pvtRegionIndex());
2505 return result *
2506 model.dofTotalVolume(ectx.globalDofIdx) *
2507 getValue(ectx.intQuants.porosity()) *
2508 rhoG /
2509 FluidSystem::molarMass(gasCompIdx, ectx.intQuants.pvtRegionIndex());
2510 }
2511 }
2512 },
2513 Entry{ScalarEntry{"BWIPG",
2514 [&model = this->simulator_.model()](const Context& ectx)
2515 {
2516 Scalar result = 0.0;
2517 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
2518 result = getValue(ectx.fs.Rvw()) *
2519 getValue(ectx.fs.invB(gasPhaseIdx)) *
2520 getValue(ectx.fs.saturation(gasPhaseIdx));
2521 }
2522 return result *
2523 model.dofTotalVolume(ectx.globalDofIdx) *
2524 getValue(ectx.intQuants.porosity());
2525 }
2526 }
2527 },
2528 Entry{ScalarEntry{"BWIPL",
2529 [&model = this->simulator_.model()](const Context& ectx)
2530 {
2531 return getValue(ectx.fs.invB(waterPhaseIdx)) *
2532 getValue(ectx.fs.saturation(waterPhaseIdx)) *
2533 model.dofTotalVolume(ectx.globalDofIdx) *
2534 getValue(ectx.intQuants.porosity());
2535 }
2536 }
2537 },
2538 };
2539
2540 this->blockExtractors_ = BlockExtractor::setupExecMap(this->blockData_, handlers);
2541
2542 this->extraBlockData_.clear();
2543 if (reportStepNum > 0 && !isSubStep) {
2544 // check we need extra block pressures for RPTSCHED
2545 const auto& rpt = this->schedule_[reportStepNum - 1].rpt_config.get();
2546 if (rpt.contains("WELLS") && rpt.at("WELLS") > 1) {
2547 this->setupExtraBlockData(reportStepNum,
2548 [&c = this->collectOnIORank_](const int idx)
2549 { return c.isCartIdxOnThisRank(idx); });
2550
2551 const auto extraHandlers = std::array{
2552 pressure_handler,
2553 };
2554
2555 this->extraBlockExtractors_ = BlockExtractor::setupExecMap(this->extraBlockData_, extraHandlers);
2556 }
2557 }
2558 }
2559
2560 const Simulator& simulator_;
2561 const CollectDataOnIORankType& collectOnIORank_;
2562 std::vector<typename Extractor::Entry> extractors_;
2563 typename BlockExtractor::ExecMap blockExtractors_;
2564 typename BlockExtractor::ExecMap extraBlockExtractors_;
2565};
2566
2567} // namespace Opm
2568
2569#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)
Definition: GenericOutputBlackoilModule.hpp:76
std::map< std::pair< std::string, int >, double > blockData_
Definition: GenericOutputBlackoilModule.hpp:456
std::array< ScalarBuffer, numPhases > relativePermeability_
Definition: GenericOutputBlackoilModule.hpp:445
ScalarBuffer fluidPressure_
Definition: GenericOutputBlackoilModule.hpp:399
std::array< ScalarBuffer, numPhases > density_
Definition: GenericOutputBlackoilModule.hpp:443
ScalarBuffer saturatedOilFormationVolumeFactor_
Definition: GenericOutputBlackoilModule.hpp:431
ScalarBuffer overburdenPressure_
Definition: GenericOutputBlackoilModule.hpp:405
ScalarBuffer gasDissolutionFactorInWater_
Definition: GenericOutputBlackoilModule.hpp:425
const EclipseState & eclState_
Definition: GenericOutputBlackoilModule.hpp:358
ScalarBuffer swmin_
Definition: GenericOutputBlackoilModule.hpp:421
ScalarBuffer rockCompPorvMultiplier_
Definition: GenericOutputBlackoilModule.hpp:429
RFTContainer< GetPropType< TypeTag, Properties::FluidSystem > > rftC_
Definition: GenericOutputBlackoilModule.hpp:453
ScalarBuffer dewPointPressure_
Definition: GenericOutputBlackoilModule.hpp:428
LogOutputHelper< Scalar > logOutput_
Definition: GenericOutputBlackoilModule.hpp:365
std::vector< int > failedCellsPb_
Definition: GenericOutputBlackoilModule.hpp:390
ScalarBuffer permFact_
Definition: GenericOutputBlackoilModule.hpp:414
ScalarBuffer rsw_
Definition: GenericOutputBlackoilModule.hpp:402
ScalarBuffer pcog_
Definition: GenericOutputBlackoilModule.hpp:436
std::optional< RegionPhasePoreVolAverage > regionAvgDensity_
Definition: GenericOutputBlackoilModule.hpp:464
std::array< ScalarBuffer, numPhases > invB_
Definition: GenericOutputBlackoilModule.hpp:442
ScalarBuffer pSalt_
Definition: GenericOutputBlackoilModule.hpp:413
ScalarBuffer cFoam_
Definition: GenericOutputBlackoilModule.hpp:411
ScalarBuffer bubblePointPressure_
Definition: GenericOutputBlackoilModule.hpp:427
ScalarBuffer temperature_
Definition: GenericOutputBlackoilModule.hpp:400
ScalarBuffer ppcw_
Definition: GenericOutputBlackoilModule.hpp:422
FIPContainer< GetPropType< TypeTag, Properties::FluidSystem > > fipC_
Definition: GenericOutputBlackoilModule.hpp:383
ScalarBuffer rockCompTransMultiplier_
Definition: GenericOutputBlackoilModule.hpp:432
MechContainer< Scalar > mech_
Definition: GenericOutputBlackoilModule.hpp:439
ScalarBuffer dynamicPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:397
ScalarBuffer minimumOilPressure_
Definition: GenericOutputBlackoilModule.hpp:430
ScalarBuffer gasFormationVolumeFactor_
Definition: GenericOutputBlackoilModule.hpp:393
std::array< ScalarBuffer, numPhases > residual_
Definition: GenericOutputBlackoilModule.hpp:449
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:419
BioeffectsContainer< Scalar > bioeffectsC_
Definition: GenericOutputBlackoilModule.hpp:433
const Schedule & schedule_
Definition: GenericOutputBlackoilModule.hpp:359
FlowsContainer< GetPropType< TypeTag, Properties::FluidSystem > > flowsC_
Definition: GenericOutputBlackoilModule.hpp:451
ExtboContainer< Scalar > extboC_
Definition: GenericOutputBlackoilModule.hpp:415
void setupExtraBlockData(const std::size_t reportStepNum, std::function< bool(int)> isCartIdxOnThisRank)
ScalarBuffer oilSaturationPressure_
Definition: GenericOutputBlackoilModule.hpp:406
InterRegFlowMap interRegionFlows_
Definition: GenericOutputBlackoilModule.hpp:364
ScalarBuffer pcgw_
Definition: GenericOutputBlackoilModule.hpp:434
ScalarBuffer cPolymer_
Definition: GenericOutputBlackoilModule.hpp:410
void setupBlockData(std::function< bool(int)> isCartIdxOnThisRank)
ScalarBuffer rvw_
Definition: GenericOutputBlackoilModule.hpp:404
std::array< ScalarBuffer, numPhases > saturation_
Definition: GenericOutputBlackoilModule.hpp:441
std::unordered_map< std::string, std::vector< int > > regions_
Definition: GenericOutputBlackoilModule.hpp:384
ScalarBuffer rPorV_
Definition: GenericOutputBlackoilModule.hpp:398
ScalarBuffer oilVaporizationFactor_
Definition: GenericOutputBlackoilModule.hpp:424
std::vector< int > failedCellsPd_
Definition: GenericOutputBlackoilModule.hpp:391
ScalarBuffer rs_
Definition: GenericOutputBlackoilModule.hpp:401
ScalarBuffer drsdtcon_
Definition: GenericOutputBlackoilModule.hpp:407
ScalarBuffer sSol_
Definition: GenericOutputBlackoilModule.hpp:408
std::map< std::pair< std::string, int >, double > extraBlockData_
Definition: GenericOutputBlackoilModule.hpp:459
ScalarBuffer pressureTimesPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:395
ScalarBuffer gasDissolutionFactor_
Definition: GenericOutputBlackoilModule.hpp:423
std::array< ScalarBuffer, numPhases > viscosity_
Definition: GenericOutputBlackoilModule.hpp:444
bool forceDisableFipOutput_
Definition: GenericOutputBlackoilModule.hpp:379
ScalarBuffer soMax_
Definition: GenericOutputBlackoilModule.hpp:416
ScalarBuffer sgmax_
Definition: GenericOutputBlackoilModule.hpp:418
ScalarBuffer somin_
Definition: GenericOutputBlackoilModule.hpp:420
ScalarBuffer hydrocarbonPoreVolume_
Definition: GenericOutputBlackoilModule.hpp:394
const std::optional< Inplace > & initialInplace() const
Definition: GenericOutputBlackoilModule.hpp:246
ScalarBuffer waterVaporizationFactor_
Definition: GenericOutputBlackoilModule.hpp:426
ScalarBuffer cSalt_
Definition: GenericOutputBlackoilModule.hpp:412
TracerContainer< GetPropType< TypeTag, Properties::FluidSystem > > tracerC_
Definition: GenericOutputBlackoilModule.hpp:447
ScalarBuffer rv_
Definition: GenericOutputBlackoilModule.hpp:403
ScalarBuffer pcow_
Definition: GenericOutputBlackoilModule.hpp:435
ScalarBuffer swMax_
Definition: GenericOutputBlackoilModule.hpp:417
ScalarBuffer pressureTimesHydrocarbonVolume_
Definition: GenericOutputBlackoilModule.hpp:396
ScalarBuffer rswSol_
Definition: GenericOutputBlackoilModule.hpp:409
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:240
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows.
Definition: OutputBlackoilModule.hpp:484
void setupExtractors(const bool isSubStep, const int reportStepNum)
Setup list of active element-level data extractors.
Definition: OutputBlackoilModule.hpp:221
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:199
void processFluxes(const ElementContext &elemCtx, ActiveIndex &&activeIndex, CartesianIndex &&cartesianIndex)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputBlackoilModule.hpp:447
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputBlackoilModule.hpp:229
void outputFipAndResvLogToCSV(const std::size_t reportStepNum, const bool substep, const Parallel::Communication &comm)
Definition: OutputBlackoilModule.hpp:381
void assignToFluidState(FluidState &fs, unsigned elemIdx) const
Definition: OutputBlackoilModule.hpp:508
void initHysteresisParams(Simulator &simulator, unsigned elemIdx) const
Definition: OutputBlackoilModule.hpp:560
void updateFluidInPlace(const ElementContext &elemCtx)
Definition: OutputBlackoilModule.hpp:625
OutputBlackOilModule(const Simulator &simulator, const SummaryConfig &smryCfg, const CollectDataOnIORankType &collectOnIORank)
Definition: OutputBlackoilModule.hpp:136
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:330
const InterRegFlowMap & getInterRegFlows() const
Get read-only access to collection of inter-region flows.
Definition: OutputBlackoilModule.hpp:502
void processElementBlockData(const ElementContext &elemCtx)
Definition: OutputBlackoilModule.hpp:286
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputBlackoilModule.hpp:494
void updateFluidInPlace(const unsigned globalDofIdx, const IntensiveQuantities &intQuants, const double totVolume)
Definition: OutputBlackoilModule.hpp:632
Declare the properties used by the infrastructure code of the finite volume discretizations.
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
Definition: blackoilbioeffectsmodules.hh:43
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:206
Wrapping struct holding types used for block-level data extraction.
Definition: OutputExtractor.hpp:193
std::unordered_map< int, std::vector< Exec > > ExecMap
A map of extraction executors, keyed by cartesian cell index.
Definition: OutputExtractor.hpp:260
std::variant< ScalarEntry, PhaseEntry > Entry
Descriptor for extractors.
Definition: OutputExtractor.hpp:245
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:264
static void process(const std::vector< Exec > &blockExtractors, const Context &ectx)
Process a list of block extractors.
Definition: OutputExtractor.hpp:367
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:158
static std::vector< Entry > removeInactive(std::array< Entry, size > &input)
Obtain vector of active extractors from an array of extractors.
Definition: OutputExtractor.hpp:120