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