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