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 [&collectToIORank](const int idx)
106 { return collectToIORank.isCartIdxOnThisRank(idx); },
107 simulator.vanguard().grid().comm(),
108 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal,
109 getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::ConstantTemperature,
110 getPropValue<TypeTag, Properties::EnableMech>(),
111 getPropValue<TypeTag, Properties::EnableSolvent>(),
112 getPropValue<TypeTag, Properties::EnablePolymer>(),
113 getPropValue<TypeTag, Properties::EnableFoam>(),
114 getPropValue<TypeTag, Properties::EnableBrine>(),
115 getPropValue<TypeTag, Properties::EnableSaltPrecipitation>(),
116 getPropValue<TypeTag, Properties::EnableExtbo>(),
117 getPropValue<TypeTag, Properties::EnableBioeffects>(),
118 getPropValue<TypeTag, Properties::EnableGeochemistry>())
119 , simulator_(simulator)
120 {
121 for (auto& region_pair : this->regions_) {
122 this->createLocalRegion_(region_pair.second);
123 }
124
125 auto isCartIdxOnThisRank = [&collectToIORank](const int idx) {
126 return collectToIORank.isCartIdxOnThisRank(idx);
127 };
128
129 this->setupBlockData(isCartIdxOnThisRank);
130
131 if (! Parameters::Get<Parameters::OwnerCellsFirst>()) {
132 const std::string msg = "The output code does not support --owner-cells-first=false.";
133 if (collectToIORank.isIORank()) {
134 OpmLog::error(msg);
135 }
136 OPM_THROW_NOLOG(std::runtime_error, msg);
137 }
138
139 if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) {
140 auto rset = this->eclState_.fieldProps().fip_regions();
141 rset.push_back("PVTNUM");
142
143 // Note: We explicitly use decltype(auto) here because the
144 // default scheme (-> auto) will deduce an undesirable type. We
145 // need the "reference to vector" semantics in this instance.
147 .emplace(this->simulator_.gridView().comm(),
148 FluidSystem::numPhases, rset,
149 [fp = std::cref(this->eclState_.fieldProps())]
150 (const std::string& rsetName) -> decltype(auto)
151 { return fp.get().get_int(rsetName); });
152 }
153 }
154
159 void
160 allocBuffers(const unsigned bufferSize,
161 const unsigned reportStepNum,
162 const bool substep,
163 const bool log,
164 const bool isRestart)
165 {
166 if (! std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
167 return;
168 }
169
170 auto rstKeywords = this->schedule_.rst_keywords(reportStepNum);
171 this->compC_.allocate(bufferSize, rstKeywords);
172
173 this->doAllocBuffers(bufferSize, reportStepNum, substep, log, isRestart,
174 /* hysteresisConfig = */ nullptr,
175 /* numOutputNnc =*/ 0,
176 std::move(rstKeywords));
177 }
178
179 void assignToSolution(data::Solution& sol)
180 {
181 this->compC_.outputRestart(sol, this->saturation_[oilPhaseIdx]);
183 }
184
186 void setupExtractors(const bool /*isSubStep*/,
187 const std::size_t /*reportStepNum*/)
188 {
189 using Entry = typename Extractor::Entry;
190 using ExtractContext = typename Extractor::Context;
191 using ScalarEntry = typename Extractor::ScalarEntry;
192 using PhaseEntry = typename Extractor::PhaseEntry;
193
194 auto extractors = std::array{
195 Entry{PhaseEntry{&this->saturation_,
196 [](const unsigned phase, const ExtractContext& ectx)
197 { return getValue(ectx.fs.saturation(phase)); }}
198 },
199 Entry{ScalarEntry{&this->fluidPressure_,
200 [](const ExtractContext& ectx)
201 {
202 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
203 // Output oil pressure as default
204 return getValue(ectx.fs.pressure(oilPhaseIdx));
205 }
206 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
207 // Output gas if oil is not present
208 return getValue(ectx.fs.pressure(gasPhaseIdx));
209 }
210 else {
211 // Output water if neither oil nor gas is present
212 return getValue(ectx.fs.pressure(waterPhaseIdx));
213 }
214 }}
215 },
216 Entry{ScalarEntry{&this->temperature_,
217 [](const ExtractContext& ectx)
218 { return getValue(ectx.fs.temperature(oilPhaseIdx)); }}
219 },
220 Entry{[&compC = this->compC_](const ExtractContext& ectx)
221 {
222 compC.assignMoleFractions(ectx.globalDofIdx,
223 [&fs = ectx.fs](const unsigned compIdx)
224 { return getValue(fs.moleFraction(compIdx)); });
225
226 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
227 compC.assignGasFractions(ectx.globalDofIdx,
228 [&fs = ectx.fs](const unsigned compIdx)
229 { return getValue(fs.moleFraction(gasPhaseIdx, compIdx)); });
230 }
231
232 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
233 compC.assignOilFractions(ectx.globalDofIdx,
234 [&fs = ectx.fs](const unsigned compIdx)
235 { return getValue(fs.moleFraction(oilPhaseIdx, compIdx)); });
236 }
237 }, this->compC_.allocated()
238 },
239 };
240
241 this->extractors_ = Extractor::removeInactive(extractors);
242 }
243
246 { this->extractors_.clear(); }
247
252 void processElement(const ElementContext& elemCtx)
253 {
254 OPM_TIMEBLOCK_LOCAL(processElement, Subsystem::Output);
255 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
256 return;
257 }
258
259 typename Extractor::HysteresisParams hysterParams{};
260 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
261 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
262 const auto& fs = intQuants.fluidState();
263
264 const typename Extractor::Context ectx{
265 elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0),
266 0, // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(),
267 elemCtx.simulator().episodeIndex(),
268 fs,
269 intQuants,
270 hysterParams
271 };
272
273 Extractor::process(ectx, extractors_);
274 }
275 }
276
277 void processElementFlows(const ElementContext& /* elemCtx */)
278 {
279 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
280 if (!std::is_same_v<Discretization, EcfvDiscretization<TypeTag>>)
281 return;
282 }
283
284 void processElementBlockData(const ElementContext& /* elemCtx */)
285 {
286 OPM_TIMEBLOCK_LOCAL(processElementBlockData, Subsystem::Output);
287 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value)
288 return;
289 }
290
319 template <class ActiveIndex, class CartesianIndex>
320 void processFluxes(const ElementContext& /* elemCtx */,
321 ActiveIndex&& /* activeIndex*/,
322 CartesianIndex&& /* cartesianIndex */)
323 {
324 }
325
331 {
332 // Inter-region flow rates. Note: ".clear()" prepares to accumulate
333 // contributions per bulk connection between FIP regions.
334 this->interRegionFlows_.clear();
335 }
336
341 {
343 }
344
349 {
350 return this->interRegionFlows_;
351 }
352
353 void updateFluidInPlace(const unsigned /* globalDofIdx */,
354 const IntensiveQuantities& /* intQuants */,
355 const double /* totVolume */)
356 {
357 // this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
358 }
359
360private:
361 bool isDefunctParallelWell(const std::string& wname) const override
362 {
363 if (simulator_.gridView().comm().size() == 1)
364 return false;
365 const auto& parallelWells = simulator_.vanguard().parallelWells();
366 std::pair<std::string, bool> value {wname, true};
367 auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value);
368 return candidate == parallelWells.end() || *candidate != value;
369 }
370
371 bool isOwnedByCurrentRank(const std::string& wname) const override
372 {
373 // Note: This statement is not correct for distributed wells and
374 // will need additional logic once those are supported for
375 // compositional flows.
376 return ! this->isDefunctParallelWell(wname);
377 }
378
379 bool isOnCurrentRank(const std::string& wname) const override
380 {
381 // Note: This statement is not correct for distributed wells and
382 // will need additional logic once those are supported for
383 // compositional flows.
384 return ! this->isDefunctParallelWell(wname);
385 }
386
387 void createLocalRegion_(std::vector<int>& region)
388 {
389 std::size_t elemIdx = 0;
390 for (const auto& elem : elements(simulator_.gridView())) {
391 if (elem.partitionType() != Dune::InteriorEntity) {
392 region[elemIdx] = 0;
393 }
394
395 ++elemIdx;
396 }
397 }
398
399 const Simulator& simulator_;
400 CompositionalContainer<FluidSystem> compC_;
401 std::vector<typename Extractor::Entry> extractors_;
402};
403
404} // namespace Opm
405
406#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:78
ScalarBuffer fluidPressure_
Definition: GenericOutputBlackoilModule.hpp:409
const EclipseState & eclState_
Definition: GenericOutputBlackoilModule.hpp:367
std::optional< RegionPhasePoreVolAverage > regionAvgDensity_
Definition: GenericOutputBlackoilModule.hpp:477
ScalarBuffer temperature_
Definition: GenericOutputBlackoilModule.hpp:410
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:368
InterRegFlowMap interRegionFlows_
Definition: GenericOutputBlackoilModule.hpp:373
void setupBlockData(std::function< bool(int)> isCartIdxOnThisRank)
std::array< ScalarBuffer, numPhases > saturation_
Definition: GenericOutputBlackoilModule.hpp:452
std::unordered_map< std::string, std::vector< int > > regions_
Definition: GenericOutputBlackoilModule.hpp:394
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:277
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:245
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:330
void setupExtractors(const bool, const std::size_t)
Setup list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:186
void assignToSolution(data::Solution &sol)
Definition: OutputCompositionalModule.hpp:179
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputCompositionalModule.hpp:340
void processElement(const ElementContext &elemCtx)
Modify the internal buffers according to the intensive quanties relevant for an element.
Definition: OutputCompositionalModule.hpp:252
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:160
void processElementBlockData(const ElementContext &)
Definition: OutputCompositionalModule.hpp:284
void processFluxes(const ElementContext &, ActiveIndex &&, CartesianIndex &&)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:320
const InterRegFlowMap & getInterRegFlows() const
Get read-only access to collection of inter-region flows.
Definition: OutputCompositionalModule.hpp:348
void updateFluidInPlace(const unsigned, const IntensiveQuantities &, const double)
Definition: OutputCompositionalModule.hpp:353
Defines the common properties required by the porous medium multi-phase models.
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.
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:157
static std::vector< Entry > removeInactive(std::array< Entry, size > &input)
Obtain vector of active extractors from an array of extractors.
Definition: OutputExtractor.hpp:120