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