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