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