opm-simulators
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 
63 namespace Opm {
64 
65 // forward declaration
66 template <class TypeTag>
67 class EcfvDiscretization;
68 
75 template <class TypeTag>
76 class 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 
93 public:
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.
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 
360 private:
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.
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
void finalizeFluxData()
Finalize capturing connection fluxes.
Definition: OutputCompositionalModule.hpp:340
Descriptor for extractors.
Definition: OutputExtractor.hpp:112
The base class for the element-centered finite-volume discretization scheme.
Definition: fvbasegradientcalculator.hh:42
std::string moduleVersionName()
Return the version name of the module, for example "2015.10" (for a release branch) or "2016...
Definition: moduleVersion.cpp:34
Helper class for grid instantiation of ECL file-format using problems.
This file provides the infrastructure to retrieve run-time parameters.
Wrapping struct holding types used for element-level data extraction.
Definition: OutputExtractor.hpp:53
Output module for the results black oil model writing in ECL binary format.
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.
void clearExtractors()
Clear list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:245
void compress()
Form CSR adjacency matrix representation of input graph from connections established in previous call...
Definition: InterRegFlows.cpp:164
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Struct holding hysteresis parameters.
Definition: OutputExtractor.hpp:62
Declares the properties required by the black oil model.
Definition: GenericOutputBlackoilModule.hpp:78
Inter-region flow accumulation maps for all region definition arrays.
Definition: InterRegFlows.hpp:178
Output module for the results black oil model writing in ECL binary format.
void setupExtractors(const bool, const std::size_t)
Setup list of active element-level data extractors.
Definition: OutputCompositionalModule.hpp:186
A scalar extractor descriptor.
Definition: OutputExtractor.hpp:98
static void process(const Context &ectx, const std::vector< Entry > &extractors)
Process the given extractor entries.
Definition: OutputExtractor.hpp:157
void clear()
Clear all internal buffers, but preserve allocated capacity.
Definition: InterRegFlows.cpp:171
void initializeFluxData()
Prepare for capturing connection fluxes, particularly to account for inter-region flows...
Definition: OutputCompositionalModule.hpp:330
void processElement(const ElementContext &elemCtx)
Modify the internal buffers according to the intensive quanties relevant for an element.
Definition: OutputCompositionalModule.hpp:252
Output module for the results black oil model writing in ECL binary format.
Definition: OutputCompositionalModule.hpp:76
The Opm property system, traits with inheritance.
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
static std::vector< Entry > removeInactive(std::array< Entry, size > &input)
Obtain vector of active extractors from an array of extractors.
Definition: OutputExtractor.hpp:120
void processFluxes(const ElementContext &, ActiveIndex &&, CartesianIndex &&)
Capture connection fluxes, particularly to account for inter-region flows.
Definition: OutputCompositionalModule.hpp:320
Context passed to extractor functions.
Definition: OutputExtractor.hpp:73
void assignToSolution(data::Solution &sol)
Move all buffers to data::Solution.
Definition: GenericOutputBlackoilModule.cpp:316
Contains the classes required to extend the black-oil model by energy.
int episodeIndex
Current report step.
Definition: OutputExtractor.hpp:77
A phase buffer extractor descriptor.
Definition: OutputExtractor.hpp:105