OutputCompositionalModule.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_COMPOSITIONAL_MODULE_HPP
28#define OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP
29
30#include <dune/grid/common/gridenums.hh>
31
33
34#include <opm/common/Exceptions.hpp>
35#include <opm/common/ErrorMacros.hpp>
36#include <opm/common/TimingMacros.hpp>
37#include <opm/common/OpmLog/OpmLog.hpp>
38
39#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
40
41#include <opm/material/common/Valgrind.hpp>
42
48
53
54#include <algorithm>
55#include <cstddef>
56#include <stdexcept>
57#include <string>
58#include <type_traits>
59#include <utility>
60#include <vector>
61
62
63namespace Opm {
64
65// forward declaration
66template <class TypeTag>
67class EcfvDiscretization;
68
75template <class TypeTag>
76class OutputCompositionalModule : public GenericOutputBlackoilModule<GetPropType<TypeTag, Properties::FluidSystem>>
77{
86
87 enum { numPhases = FluidSystem::numPhases };
88 enum { numComponents = FluidSystem::numComponents };
89 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
90 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
91 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
92
93public:
94 template <class CollectDataToIORankType>
95 OutputCompositionalModule(const Simulator& simulator,
96 const SummaryConfig& smryCfg,
97 const CollectDataToIORankType& collectToIORank)
98 : BaseType(simulator.vanguard().eclState(),
99 simulator.vanguard().schedule(),
100 smryCfg,
101 simulator.vanguard().summaryState(),
103 [this](const int idx)
104 { return simulator_.problem().eclWriter().collectOnIORank().localIdxToGlobalIdx(idx); },
105 simulator.vanguard().grid().comm(),
106 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal,
107 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::ConstantTemperature,
108 getPropValue<TypeTag, Properties::EnableMech>(),
109 getPropValue<TypeTag, Properties::EnableSolvent>(),
110 getPropValue<TypeTag, Properties::EnablePolymer>(),
111 getPropValue<TypeTag, Properties::EnableFoam>(),
112 getPropValue<TypeTag, Properties::EnableBrine>(),
113 getPropValue<TypeTag, Properties::EnableSaltPrecipitation>(),
114 getPropValue<TypeTag, Properties::EnableExtbo>(),
115 getPropValue<TypeTag, Properties::EnableBioeffects>())
116 , simulator_(simulator)
117 {
118 for (auto& region_pair : this->regions_) {
119 this->createLocalRegion_(region_pair.second);
120 }
121
122 auto isCartIdxOnThisRank = [&collectToIORank](const int idx) {
123 return collectToIORank.isCartIdxOnThisRank(idx);
124 };
125
126 this->setupBlockData(isCartIdxOnThisRank);
127
128 if (! Parameters::Get<Parameters::OwnerCellsFirst>()) {
129 const std::string msg = "The output code does not support --owner-cells-first=false.";
130 if (collectToIORank.isIORank()) {
131 OpmLog::error(msg);
132 }
133 OPM_THROW_NOLOG(std::runtime_error, msg);
134 }
135
136 if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) {
137 auto rset = this->eclState_.fieldProps().fip_regions();
138 rset.push_back("PVTNUM");
139
140 // Note: We explicitly use decltype(auto) here because the
141 // default scheme (-> auto) will deduce an undesirable type. We
142 // need the "reference to vector" semantics in this instance.
144 .emplace(this->simulator_.gridView().comm(),
145 FluidSystem::numPhases, rset,
146 [fp = std::cref(this->eclState_.fieldProps())]
147 (const std::string& rsetName) -> decltype(auto)
148 { return fp.get().get_int(rsetName); });
149 }
150 }
151
156 void
157 allocBuffers(const unsigned bufferSize,
158 const unsigned reportStepNum,
159 const bool substep,
160 const bool log,
161 const bool isRestart)
162 {
163 if (! std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
164 return;
165 }
166
167 auto rstKeywords = this->schedule_.rst_keywords(reportStepNum);
168 this->compC_.allocate(bufferSize, rstKeywords);
169
170 this->doAllocBuffers(bufferSize, reportStepNum, substep, log, isRestart,
171 /* hysteresisConfig = */ nullptr,
172 /* numOutputNnc =*/ 0,
173 std::move(rstKeywords));
174 }
175
176 void assignToSolution(data::Solution& sol)
177 {
178 this->compC_.outputRestart(sol, this->saturation_[oilPhaseIdx]);
180 }
181
183 void setupExtractors(const bool /*isSubStep*/,
184 const std::size_t /*reportStepNum*/)
185 {
186 using Entry = typename Extractor::Entry;
187 using ExtractContext = typename Extractor::Context;
188 using ScalarEntry = typename Extractor::ScalarEntry;
189 using PhaseEntry = typename Extractor::PhaseEntry;
190
191 auto extractors = std::array{
192 Entry{PhaseEntry{&this->saturation_,
193 [](const unsigned phase, const ExtractContext& ectx)
194 { return getValue(ectx.fs.saturation(phase)); }}
195 },
196 Entry{ScalarEntry{&this->fluidPressure_,
197 [](const ExtractContext& ectx)
198 {
199 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
200 // Output oil pressure as default
201 return getValue(ectx.fs.pressure(oilPhaseIdx));
202 }
203 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
204 // Output gas if oil is not present
205 return getValue(ectx.fs.pressure(gasPhaseIdx));
206 }
207 else {
208 // Output water if neither oil nor gas is present
209 return getValue(ectx.fs.pressure(waterPhaseIdx));
210 }
211 }}
212 },
213 Entry{ScalarEntry{&this->temperature_,
214 [](const ExtractContext& ectx)
215 { return getValue(ectx.fs.temperature(oilPhaseIdx)); }}
216 },
217 Entry{[&compC = this->compC_](const ExtractContext& ectx)
218 {
219 compC.assignMoleFractions(ectx.globalDofIdx,
220 [&fs = ectx.fs](const unsigned compIdx)
221 { return getValue(fs.moleFraction(compIdx)); });
222
223 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
224 compC.assignGasFractions(ectx.globalDofIdx,
225 [&fs = ectx.fs](const unsigned compIdx)
226 { return getValue(fs.moleFraction(gasPhaseIdx, compIdx)); });
227 }
228
229 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
230 compC.assignOilFractions(ectx.globalDofIdx,
231 [&fs = ectx.fs](const unsigned compIdx)
232 { return getValue(fs.moleFraction(oilPhaseIdx, compIdx)); });
233 }
234 }, this->compC_.allocated()
235 },
236 };
237
238 this->extractors_ = Extractor::removeInactive(extractors);
239 }
240
243 { this->extractors_.clear(); }
244
249 void processElement(const ElementContext& elemCtx)
250 {
251 OPM_TIMEBLOCK_LOCAL(processElement, Subsystem::Output);
252 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
253 return;
254 }
255
256 typename Extractor::HysteresisParams hysterParams{};
257 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
258 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
259 const auto& fs = intQuants.fluidState();
260
261 const typename Extractor::Context ectx{
262 elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0),
263 0, // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(),
264 elemCtx.simulator().episodeIndex(),
265 fs,
266 intQuants,
267 hysterParams
268 };
269
270 Extractor::process(ectx, extractors_);
271 }
272 }
273
274 void processElementFlows(const ElementContext& /* elemCtx */)
275 {
276 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
277 if (!std::is_same_v<Discretization, EcfvDiscretization<TypeTag>>)
278 return;
279 }
280
281 void processElementBlockData(const ElementContext& /* elemCtx */)
282 {
283 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
284 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value)
285 return;
286 }
287
316 template <class ActiveIndex, class CartesianIndex>
317 void processFluxes(const ElementContext& /* elemCtx */,
318 ActiveIndex&& /* activeIndex*/,
319 CartesianIndex&& /* cartesianIndex */)
320 {
321 }
322
328 {
329 // Inter-region flow rates. Note: ".clear()" prepares to accumulate
330 // contributions per bulk connection between FIP regions.
331 this->interRegionFlows_.clear();
332 }
333
338 {
340 }
341
346 {
347 return this->interRegionFlows_;
348 }
349
350 void updateFluidInPlace(const unsigned /* globalDofIdx */,
351 const IntensiveQuantities& /* intQuants */,
352 const double /* totVolume */)
353 {
354 // this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
355 }
356
357private:
358 bool isDefunctParallelWell(const std::string& wname) const override
359 {
360 if (simulator_.gridView().comm().size() == 1)
361 return false;
362 const auto& parallelWells = simulator_.vanguard().parallelWells();
363 std::pair<std::string, bool> value {wname, true};
364 auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value);
365 return candidate == parallelWells.end() || *candidate != value;
366 }
367
368 bool isOwnedByCurrentRank(const std::string& wname) const override
369 {
370 // Note: This statement is not correct for distributed wells and
371 // will need additional logic once those are supported for
372 // compositional flows.
373 return ! this->isDefunctParallelWell(wname);
374 }
375
376 bool isOnCurrentRank(const std::string& wname) const override
377 {
378 // Note: This statement is not correct for distributed wells and
379 // will need additional logic once those are supported for
380 // compositional flows.
381 return ! this->isDefunctParallelWell(wname);
382 }
383
384 void createLocalRegion_(std::vector<int>& region)
385 {
386 std::size_t elemIdx = 0;
387 for (const auto& elem : elements(simulator_.gridView())) {
388 if (elem.partitionType() != Dune::InteriorEntity) {
389 region[elemIdx] = 0;
390 }
391
392 ++elemIdx;
393 }
394 }
395
396 const Simulator& simulator_;
397 CompositionalContainer<FluidSystem> compC_;
398 std::vector<typename Extractor::Entry> extractors_;
399};
400
401} // namespace Opm
402
403#endif // OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP
Contains the classes required to extend the black-oil model by energy.
Declares the properties required by the black oil model.
The base class for the element-centered finite-volume discretization scheme.
Definition: ecfvdiscretization.hh:160
Definition: GenericOutputBlackoilModule.hpp:76
ScalarBuffer fluidPressure_
Definition: GenericOutputBlackoilModule.hpp:399
const EclipseState & eclState_
Definition: GenericOutputBlackoilModule.hpp:358
std::optional< RegionPhasePoreVolAverage > regionAvgDensity_
Definition: GenericOutputBlackoilModule.hpp:464
ScalarBuffer temperature_
Definition: GenericOutputBlackoilModule.hpp:400
void doAllocBuffers(unsigned bufferSize, unsigned reportStepNum, const bool substep, const bool log, const bool isRestart, const EclHysteresisConfig *hysteresisConfig, unsigned numOutputNnc=0, std::map< std::string, int > rstKeywords={})
const Schedule & schedule_
Definition: GenericOutputBlackoilModule.hpp:359
InterRegFlowMap interRegionFlows_
Definition: GenericOutputBlackoilModule.hpp:364
void setupBlockData(std::function< bool(int)> isCartIdxOnThisRank)
std::array< ScalarBuffer, numPhases > saturation_
Definition: GenericOutputBlackoilModule.hpp:441
std::unordered_map< std::string, std::vector< int > > regions_
Definition: GenericOutputBlackoilModule.hpp:384
void assignToSolution(data::Solution &sol)
Move all buffers to data::Solution.
Inter-region flow accumulation maps for all region definition arrays.
Definition: InterRegFlows.hpp:179
void clear()
Clear all internal buffers, but preserve allocated capacity.
Output module for the results black oil model writing in ECL binary format.
Definition: OutputCompositionalModule.hpp:77
void processElementFlows(const ElementContext &)
Definition: OutputCompositionalModule.hpp:274
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:242
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:327
void setupExtractors(const bool, const std::size_t)
Setup list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:183
void assignToSolution(data::Solution &sol)
Definition: OutputCompositionalModule.hpp:176
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputCompositionalModule.hpp:337
void processElement(const ElementContext &elemCtx)
Modify the internal buffers according to the intensive quanties relevant for an element.
Definition: OutputCompositionalModule.hpp:249
OutputCompositionalModule(const Simulator &simulator, const SummaryConfig &smryCfg, const CollectDataToIORankType &collectToIORank)
Definition: OutputCompositionalModule.hpp:95
void allocBuffers(const unsigned bufferSize, const unsigned reportStepNum, const bool substep, const bool log, const bool isRestart)
Allocate memory for the scalar fields we would like to write to ECL output files.
Definition: OutputCompositionalModule.hpp:157
void processElementBlockData(const ElementContext &)
Definition: OutputCompositionalModule.hpp:281
void processFluxes(const ElementContext &, ActiveIndex &&, CartesianIndex &&)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:317
const InterRegFlowMap & getInterRegFlows() const
Get read-only access to collection of inter-region flows.
Definition: OutputCompositionalModule.hpp:345
void updateFluidInPlace(const unsigned, const IntensiveQuantities &, const double)
Definition: OutputCompositionalModule.hpp:350
Defines the common properties required by the porous medium multi-phase models.
Definition: blackoilbioeffectsmodules.hh:43
std::string moduleVersionName()
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
This file provides the infrastructure to retrieve run-time parameters.
The Opm property system, traits with inheritance.
Context passed to extractor functions.
Definition: OutputExtractor.hpp:74
int episodeIndex
Current report step.
Definition: OutputExtractor.hpp:77
Descriptor for extractors.
Definition: OutputExtractor.hpp:113
Struct holding hysteresis parameters.
Definition: OutputExtractor.hpp:63
A phase buffer extractor descriptor.
Definition: OutputExtractor.hpp:106
A scalar extractor descriptor.
Definition: OutputExtractor.hpp:99
Wrapping struct holding types used for element-level data extraction.
Definition: OutputExtractor.hpp:54
static void process(const Context &ectx, const std::vector< Entry > &extractors)
Process the given extractor entries.
Definition: OutputExtractor.hpp:158
static std::vector< Entry > removeInactive(std::array< Entry, size > &input)
Obtain vector of active extractors from an array of extractors.
Definition: OutputExtractor.hpp:120