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