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
47
52
53#include <algorithm>
54#include <cstddef>
55#include <stdexcept>
56#include <string>
57#include <type_traits>
58#include <utility>
59#include <vector>
60
61
62namespace Opm {
63
64// forward declaration
65template <class TypeTag>
66class EcfvDiscretization;
67
74template <class TypeTag>
75class OutputCompositionalModule : public GenericOutputBlackoilModule<GetPropType<TypeTag, Properties::FluidSystem>>
76{
85
86 enum { numPhases = FluidSystem::numPhases };
87 enum { numComponents = FluidSystem::numComponents };
88 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
89 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
90 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
91
92public:
93 template <class CollectDataToIORankType>
94 OutputCompositionalModule(const Simulator& simulator,
95 const SummaryConfig& smryCfg,
96 const CollectDataToIORankType& collectToIORank)
97 : BaseType(simulator.vanguard().eclState(),
98 simulator.vanguard().schedule(),
99 smryCfg,
100 simulator.vanguard().summaryState(),
102 [this](const int idx)
103 { return simulator_.problem().eclWriter().collectOnIORank().localIdxToGlobalIdx(idx); },
104 simulator.vanguard().grid().comm(),
105 getPropValue<TypeTag, Properties::EnableEnergy>(),
106 getPropValue<TypeTag, Properties::EnableTemperature>(),
107 getPropValue<TypeTag, Properties::EnableMech>(),
108 getPropValue<TypeTag, Properties::EnableSolvent>(),
109 getPropValue<TypeTag, Properties::EnablePolymer>(),
110 getPropValue<TypeTag, Properties::EnableFoam>(),
111 getPropValue<TypeTag, Properties::EnableBrine>(),
112 getPropValue<TypeTag, Properties::EnableSaltPrecipitation>(),
113 getPropValue<TypeTag, Properties::EnableExtbo>(),
114 getPropValue<TypeTag, Properties::EnableMICP>())
115 , simulator_(simulator)
116 {
117 for (auto& region_pair : this->regions_) {
118 this->createLocalRegion_(region_pair.second);
119 }
120
121 auto isCartIdxOnThisRank = [&collectToIORank](const int idx) {
122 return collectToIORank.isCartIdxOnThisRank(idx);
123 };
124
125 this->setupBlockData(isCartIdxOnThisRank);
126
127 if (! Parameters::Get<Parameters::OwnerCellsFirst>()) {
128 const std::string msg = "The output code does not support --owner-cells-first=false.";
129 if (collectToIORank.isIORank()) {
130 OpmLog::error(msg);
131 }
132 OPM_THROW_NOLOG(std::runtime_error, msg);
133 }
134
135 if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) {
136 auto rset = this->eclState_.fieldProps().fip_regions();
137 rset.push_back("PVTNUM");
138
139 // Note: We explicitly use decltype(auto) here because the
140 // default scheme (-> auto) will deduce an undesirable type. We
141 // need the "reference to vector" semantics in this instance.
143 .emplace(this->simulator_.gridView().comm(),
144 FluidSystem::numPhases, rset,
145 [fp = std::cref(this->eclState_.fieldProps())]
146 (const std::string& rsetName) -> decltype(auto)
147 { return fp.get().get_int(rsetName); });
148 }
149 }
150
155 void
156 allocBuffers(const unsigned bufferSize,
157 const unsigned reportStepNum,
158 const bool substep,
159 const bool log,
160 const bool isRestart)
161 {
162 if (! std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
163 return;
164 }
165
166 auto rstKeywords = this->schedule_.rst_keywords(reportStepNum);
167 this->compC_.allocate(bufferSize, rstKeywords);
168
169 this->doAllocBuffers(bufferSize, reportStepNum, substep, log, isRestart,
170 /* hysteresisConfig = */ nullptr,
171 /* numOutputNnc =*/ 0,
172 std::move(rstKeywords));
173 }
174
175 void assignToSolution(data::Solution& sol)
176 {
177 this->compC_.outputRestart(sol, this->saturation_[oilPhaseIdx]);
179 }
180
182 void setupExtractors(const bool /*isSubStep*/,
183 const std::size_t /*reportStepNum*/)
184 {
185 using Entry = typename Extractor::Entry;
186 using ExtractContext = typename Extractor::Context;
187 using ScalarEntry = typename Extractor::ScalarEntry;
188 using PhaseEntry = typename Extractor::PhaseEntry;
189
190 auto extractors = std::array{
191 Entry{PhaseEntry{&this->saturation_,
192 [](const unsigned phase, const ExtractContext& ectx)
193 { return getValue(ectx.fs.saturation(phase)); }}
194 },
195 Entry{ScalarEntry{&this->fluidPressure_,
196 [](const ExtractContext& ectx)
197 {
198 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
199 // Output oil pressure as default
200 return getValue(ectx.fs.pressure(oilPhaseIdx));
201 }
202 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
203 // Output gas if oil is not present
204 return getValue(ectx.fs.pressure(gasPhaseIdx));
205 }
206 else {
207 // Output water if neither oil nor gas is present
208 return getValue(ectx.fs.pressure(waterPhaseIdx));
209 }
210 }}
211 },
212 Entry{ScalarEntry{&this->temperature_,
213 [](const ExtractContext& ectx)
214 { return getValue(ectx.fs.temperature(oilPhaseIdx)); }}
215 },
216 Entry{[&compC = this->compC_](const ExtractContext& ectx)
217 {
218 compC.assignMoleFractions(ectx.globalDofIdx,
219 [&fs = ectx.fs](const unsigned compIdx)
220 { return getValue(fs.moleFraction(compIdx)); });
221
222 if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
223 compC.assignGasFractions(ectx.globalDofIdx,
224 [&fs = ectx.fs](const unsigned compIdx)
225 { return getValue(fs.moleFraction(gasPhaseIdx, compIdx)); });
226 }
227
228 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
229 compC.assignOilFractions(ectx.globalDofIdx,
230 [&fs = ectx.fs](const unsigned compIdx)
231 { return getValue(fs.moleFraction(oilPhaseIdx, compIdx)); });
232 }
233 }, this->compC_.allocated()
234 },
235 };
236
237 this->extractors_ = Extractor::removeInactive(extractors);
238 }
239
242 { this->extractors_.clear(); }
243
248 void processElement(const ElementContext& elemCtx)
249 {
250 OPM_TIMEBLOCK_LOCAL(processElement);
251 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value) {
252 return;
253 }
254
255 typename Extractor::HysteresisParams hysterParams{};
256 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
257 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
258 const auto& fs = intQuants.fluidState();
259
260 const typename Extractor::Context ectx{
261 elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0),
262 0, // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(),
263 elemCtx.simulator().episodeIndex(),
264 fs,
265 intQuants,
266 hysterParams
267 };
268
269 Extractor::process(ectx, extractors_);
270 }
271 }
272
273 void processElementFlows(const ElementContext& /* elemCtx */)
274 {
275 OPM_TIMEBLOCK_LOCAL(processElementBlockData);
276 if (!std::is_same_v<Discretization, EcfvDiscretization<TypeTag>>)
277 return;
278 }
279
280 void processElementBlockData(const ElementContext& /* elemCtx */)
281 {
282 OPM_TIMEBLOCK_LOCAL(processElementBlockData);
283 if (!std::is_same<Discretization, EcfvDiscretization<TypeTag>>::value)
284 return;
285 }
286
315 template <class ActiveIndex, class CartesianIndex>
316 void processFluxes(const ElementContext& /* elemCtx */,
317 ActiveIndex&& /* activeIndex*/,
318 CartesianIndex&& /* cartesianIndex */)
319 {
320 }
321
327 {
328 // Inter-region flow rates. Note: ".clear()" prepares to accumulate
329 // contributions per bulk connection between FIP regions.
330 this->interRegionFlows_.clear();
331 }
332
337 {
339 }
340
345 {
346 return this->interRegionFlows_;
347 }
348
349 void updateFluidInPlace(const unsigned /* globalDofIdx */,
350 const IntensiveQuantities& /* intQuants */,
351 const double /* totVolume */)
352 {
353 // this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume);
354 }
355
356private:
357 bool isDefunctParallelWell(const std::string& wname) const override
358 {
359 if (simulator_.gridView().comm().size() == 1)
360 return false;
361 const auto& parallelWells = simulator_.vanguard().parallelWells();
362 std::pair<std::string, bool> value {wname, true};
363 auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value);
364 return candidate == parallelWells.end() || *candidate != value;
365 }
366
367 bool isOwnedByCurrentRank(const std::string& wname) const override
368 {
369 // Note: This statement is not correct for distributed wells and
370 // will need additional logic once those are supported for
371 // compositional flows.
372 return ! this->isDefunctParallelWell(wname);
373 }
374
375 void createLocalRegion_(std::vector<int>& region)
376 {
377 std::size_t elemIdx = 0;
378 for (const auto& elem : elements(simulator_.gridView())) {
379 if (elem.partitionType() != Dune::InteriorEntity) {
380 region[elemIdx] = 0;
381 }
382
383 ++elemIdx;
384 }
385 }
386
387 const Simulator& simulator_;
388 CompositionalContainer<FluidSystem> compC_;
389 std::vector<typename Extractor::Entry> extractors_;
390};
391
392} // namespace Opm
393
394#endif // OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP
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:377
const EclipseState & eclState_
Definition: GenericOutputBlackoilModule.hpp:336
std::optional< RegionPhasePoreVolAverage > regionAvgDensity_
Definition: GenericOutputBlackoilModule.hpp:442
ScalarBuffer temperature_
Definition: GenericOutputBlackoilModule.hpp:378
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:337
InterRegFlowMap interRegionFlows_
Definition: GenericOutputBlackoilModule.hpp:342
void setupBlockData(std::function< bool(int)> isCartIdxOnThisRank)
std::array< ScalarBuffer, numPhases > saturation_
Definition: GenericOutputBlackoilModule.hpp:419
std::unordered_map< std::string, std::vector< int > > regions_
Definition: GenericOutputBlackoilModule.hpp:362
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:76
void processElementFlows(const ElementContext &)
Definition: OutputCompositionalModule.hpp:273
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:241
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:326
void setupExtractors(const bool, const std::size_t)
Setup list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:182
void assignToSolution(data::Solution &sol)
Definition: OutputCompositionalModule.hpp:175
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputCompositionalModule.hpp:336
void processElement(const ElementContext &elemCtx)
Modify the internal buffers according to the intensive quanties relevant for an element.
Definition: OutputCompositionalModule.hpp:248
OutputCompositionalModule(const Simulator &simulator, const SummaryConfig &smryCfg, const CollectDataToIORankType &collectToIORank)
Definition: OutputCompositionalModule.hpp:94
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:156
void processElementBlockData(const ElementContext &)
Definition: OutputCompositionalModule.hpp:280
void processFluxes(const ElementContext &, ActiveIndex &&, CartesianIndex &&)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:316
const InterRegFlowMap & getInterRegFlows() const
Get read-only access to collection of inter-region flows.
Definition: OutputCompositionalModule.hpp:344
void updateFluidInPlace(const unsigned, const IntensiveQuantities &, const double)
Definition: OutputCompositionalModule.hpp:349
Defines the common properties required by the porous medium multi-phase models.
Definition: blackoilboundaryratevector.hh:39
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