opm-simulators
Loading...
Searching...
No Matches
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
32#include <opm/simulators/utils/moduleVersion.hpp>
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>
68
75template <class TypeTag>
76class OutputCompositionalModule : public GenericOutputBlackoilModule<GetPropType<TypeTag, Properties::FluidSystem>>
77{
84 using BaseType = GenericOutputBlackoilModule<FluidSystem>;
85 using Extractor = detail::Extractor<TypeTag>;
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,
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
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.
146 this->regionAvgDensity_
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 {
342 this->interRegionFlows_.compress();
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
Output module for the results black oil model writing in ECL binary format.
Helper class for grid instantiation of ECL file-format using problems.
Output module for the results black oil model writing in ECL binary format.
Output module for the results black oil model writing in ECL binary format.
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
void assignToSolution(data::Solution &sol)
Move all buffers to data::Solution.
Definition GenericOutputBlackoilModule.cpp:316
Inter-region flow accumulation maps for all region definition arrays.
Definition InterRegFlows.hpp:179
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 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
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 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
Defines the common properties required by the porous medium multi-phase models.
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilbioeffectsmodules.hh:45
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
std::string moduleVersionName()
Return the version name of the module, for example "2015.10" (for a release branch) or "2016....
Definition moduleVersion.cpp:34
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:240
This file provides the infrastructure to retrieve run-time parameters.
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition parametersystem.hpp:187
The Opm property system, traits with inheritance.
Context passed to extractor functions.
Definition OutputExtractor.hpp:74
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