My Project
Main.hpp
1 /*
2  Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics.
3  Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services
4  Copyright 2015 IRIS AS
5  Copyright 2014 STATOIL ASA.
6 
7  This file is part of the Open Porous Media project (OPM).
8 
9  OPM is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  OPM is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with OPM. If not, see <http://www.gnu.org/licenses/>.
21 */
22 #ifndef OPM_MAIN_HEADER_INCLUDED
23 #define OPM_MAIN_HEADER_INCLUDED
24 
25 #include <flow/flow_ebos_blackoil.hpp>
26 
27 #include <flow/flow_ebos_gasoil.hpp>
28 #include <flow/flow_ebos_gasoil_energy.hpp>
29 #include <flow/flow_ebos_oilwater.hpp>
30 #include <flow/flow_ebos_gaswater.hpp>
31 #include <flow/flow_ebos_solvent.hpp>
32 #include <flow/flow_ebos_polymer.hpp>
33 #include <flow/flow_ebos_extbo.hpp>
34 #include <flow/flow_ebos_foam.hpp>
35 #include <flow/flow_ebos_brine.hpp>
36 #include <flow/flow_ebos_brine_saltprecipitation.hpp>
37 #include <flow/flow_ebos_gaswater_saltprec_vapwat.hpp>
38 #include <flow/flow_ebos_onephase.hpp>
39 #include <flow/flow_ebos_onephase_energy.hpp>
40 #include <flow/flow_ebos_oilwater_brine.hpp>
41 #include <flow/flow_ebos_gaswater_brine.hpp>
42 #include <flow/flow_ebos_energy.hpp>
43 #include <flow/flow_ebos_oilwater_polymer.hpp>
44 #include <flow/flow_ebos_oilwater_polymer_injectivity.hpp>
45 #include <flow/flow_ebos_micp.hpp>
46 
47 #include <opm/input/eclipse/Deck/Deck.hpp>
48 #include <opm/input/eclipse/Parser/ErrorGuard.hpp>
49 #include <opm/input/eclipse/Parser/Parser.hpp>
50 #include <opm/input/eclipse/Parser/ParseContext.hpp>
51 #include <opm/input/eclipse/EclipseState/EclipseState.hpp>
52 #include <opm/input/eclipse/EclipseState/checkDeck.hpp>
53 #include <opm/input/eclipse/Schedule/ArrayDimChecker.hpp>
54 #include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
55 #include <opm/input/eclipse/Schedule/Action/State.hpp>
56 #include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
57 
58 #include <opm/models/utils/propertysystem.hh>
59 #include <opm/models/utils/parametersystem.hh>
60 
61 #include <opm/simulators/flow/FlowMainEbos.hpp>
62 #include <opm/simulators/utils/readDeck.hpp>
63 
64 #if HAVE_DUNE_FEM
65 #include <dune/fem/misc/mpimanager.hh>
66 #else
67 #include <dune/common/parallel/mpihelper.hh>
68 #endif
69 
70 #if HAVE_MPI
71 #include <opm/simulators/utils/ParallelEclipseState.hpp>
72 #endif
73 
74 #include <cassert>
75 #include <cstdlib>
76 #include <filesystem>
77 #include <iostream>
78 #include <memory>
79 #include <stdexcept>
80 #include <string>
81 #include <type_traits>
82 #include <utility>
83 
84 namespace Opm::Properties {
85 
86 // this is a dummy type tag that is used to setup the parameters before the actual
87 // simulator.
88 namespace TTag {
89 struct FlowEarlyBird {
90  using InheritsFrom = std::tuple<EclFlowProblem>;
91 };
92 }
93 
94 } // namespace Opm::Properties
95 
96 namespace Opm {
97 
98 template <class TypeTag>
99 void flowEbosSetDeck(std::shared_ptr<Deck> deck,
100  std::shared_ptr<EclipseState> eclState,
101  std::shared_ptr<Schedule> schedule,
102  std::shared_ptr<SummaryConfig> summaryConfig)
103 {
104  using Vanguard = GetPropType<TypeTag, Properties::Vanguard>;
105 
106  Vanguard::setExternalDeck(deck);
107  Vanguard::setExternalEclState(eclState);
108  Vanguard::setExternalSchedule(schedule);
109  Vanguard::setExternalSummaryConfig(summaryConfig);
110 }
111 
112 // ----------------- Main program -----------------
113 template <class TypeTag>
114 int flowEbosMain(int argc, char** argv, bool outputCout, bool outputFiles)
115 {
116  // we always want to use the default locale, and thus spare us the trouble
117  // with incorrect locale settings.
118  resetLocale();
119 
120  FlowMainEbos<TypeTag> mainfunc(argc, argv, outputCout, outputFiles);
121  return mainfunc.execute();
122 }
123 
124 // ----------------- Main class -----------------
125 // For now, we will either be instantiated from main() in flow.cpp,
126 // or from a Python pybind11 module..
127 // NOTE (March 2020): When used from a pybind11 module, we do not neccessarily
128 // want to run the whole simulation by calling run(), it is also
129 // useful to just run one report step at a time. According to these different
130 // usage scenarios, we refactored the original run() in flow.cpp into this class.
131 class Main
132 {
133 private:
135 
136 public:
137  Main(int argc, char** argv) : argc_(argc), argv_(argv) { initMPI(); }
138 
139  // This constructor can be called from Python
140  Main(const std::string& filename)
141  {
142  setArgvArgc_(filename);
143  initMPI();
144  }
145 
146  // This constructor can be called from Python when Python has
147  // already parsed a deck
148  Main(std::shared_ptr<Deck> deck,
149  std::shared_ptr<EclipseState> eclipseState,
150  std::shared_ptr<Schedule> schedule,
151  std::shared_ptr<SummaryConfig> summaryConfig)
152  : deck_{std::move(deck)}
153  , eclipseState_{std::move(eclipseState)}
154  , schedule_{std::move(schedule)}
155  , summaryConfig_{std::move(summaryConfig)}
156  {
157  setArgvArgc_(deck_->getDataFile());
158  initMPI();
159  }
160 
161 
162  ~Main()
163  {
164 #if HAVE_MPI
165  if (test_split_comm_) {
166  // Cannot use EclGenericVanguard::comm()
167  // to get world size here, as it may be
168  // a split communication at this point.
169  int world_size;
170  MPI_Comm_size(MPI_COMM_WORLD, &world_size);
171  if (world_size > 1) {
172  MPI_Comm new_comm = EclGenericVanguard::comm();
173  int result;
174  MPI_Comm_compare(MPI_COMM_WORLD, new_comm, &result);
175  assert(result == MPI_UNEQUAL);
176  MPI_Comm_free(&new_comm);
177  }
178  }
179 #endif // HAVE_MPI
180 
181  EclGenericVanguard::setCommunication(nullptr);
182 
183 #if HAVE_MPI && !HAVE_DUNE_FEM
184  MPI_Finalize();
185 #endif
186  }
187 
188  void setArgvArgc_(const std::string& filename)
189  {
190  this->deckFilename_ = filename;
191  this->flowProgName_ = "flow";
192 
193  this->argc_ = 2;
194  this->saveArgs_[0] = const_cast<char *>(this->flowProgName_.c_str());
195  this->saveArgs_[1] = const_cast<char *>(this->deckFilename_.c_str());
196 
197  // Note: argv[argc] must exist and be nullptr
198  assert ((sizeof this->saveArgs_) > (this->argc_ * sizeof this->saveArgs_[0]));
199  this->saveArgs_[this->argc_] = nullptr;
200 
201  this->argv_ = this->saveArgs_;
202  }
203 
204  void initMPI()
205  {
206 #if HAVE_DUNE_FEM
207  Dune::Fem::MPIManager::initialize(argc_, argv_);
208 #elif HAVE_MPI
209  MPI_Init(&argc_, &argv_);
210 #endif
211  EclGenericVanguard::setCommunication(std::make_unique<Parallel::Communication>());
212 
213  handleTestSplitCommunicatorCmdLine_();
214 
215 #if HAVE_MPI
216  if (test_split_comm_ && EclGenericVanguard::comm().size() > 1) {
217  int world_rank = EclGenericVanguard::comm().rank();
218  int color = (world_rank == 0);
219  MPI_Comm new_comm;
220  MPI_Comm_split(EclGenericVanguard::comm(), color, world_rank, &new_comm);
221  isSimulationRank_ = (world_rank > 0);
222  EclGenericVanguard::setCommunication(std::make_unique<Parallel::Communication>(new_comm));
223  }
224 #endif // HAVE_MPI
225  }
226 
227  int runDynamic()
228  {
229  int exitCode = EXIT_SUCCESS;
230  if (isSimulationRank_) {
231  if (initialize_<Properties::TTag::FlowEarlyBird>(exitCode)) {
232  return this->dispatchDynamic_();
233  }
234  }
235 
236  return exitCode;
237  }
238 
239  template <class TypeTag>
240  int runStatic()
241  {
242  int exitCode = EXIT_SUCCESS;
243  if (isSimulationRank_) {
244  if (initialize_<TypeTag>(exitCode)) {
245  return this->dispatchStatic_<TypeTag>();
246  }
247  }
248 
249  return exitCode;
250  }
251 
252  // To be called from the Python interface code. Only do the
253  // initialization and then return a pointer to the FlowEbosMain
254  // object that can later be accessed directly from the Python interface
255  // to e.g. advance the simulator one report step
256  std::unique_ptr<FlowMainEbosType> initFlowEbosBlackoil(int& exitCode)
257  {
258  exitCode = EXIT_SUCCESS;
259  if (initialize_<Properties::TTag::FlowEarlyBird>(exitCode)) {
260  // TODO: check that this deck really represents a blackoil
261  // case. E.g. check that number of phases == 3
262  flowEbosBlackoilSetDeck(
263  setupTime_,
264  deck_,
265  eclipseState_,
266  schedule_,
267  std::move(udqState_),
268  std::move(this->actionState_),
269  std::move(this->wtestState_),
270  summaryConfig_);
271  return flowEbosBlackoilMainInit(
272  argc_, argv_, outputCout_, outputFiles_);
273  } else {
274  //NOTE: exitCode was set by initialize_() above;
275  return std::unique_ptr<FlowMainEbosType>(); // nullptr
276  }
277  }
278 
279 private:
280  int dispatchDynamic_()
281  {
282  const auto& rspec = this->eclipseState_->runspec();
283  const auto& phases = rspec.phases();
284 
285  // run the actual simulator
286  //
287  // TODO: make sure that no illegal combinations like thermal and
288  // twophase are requested.
289 
290  // Single-phase case
291  if (rspec.micp()) {
292  return this->runMICP(phases);
293  }
294 
295  // water-only case
296  else if(phases.size() == 1 && phases.active(Phase::WATER) && !eclipseState_->getSimulationConfig().isThermal()) {
297  return this->runWaterOnly(phases);
298  }
299 
300  // water-only case with energy
301  else if(phases.size() == 2 && phases.active(Phase::WATER) && eclipseState_->getSimulationConfig().isThermal()) {
302  return this->runWaterOnlyEnergy(phases);
303  }
304 
305  // Twophase cases
306  else if (phases.size() == 2 && !eclipseState_->getSimulationConfig().isThermal()) {
307  return this->runTwoPhase(phases);
308  }
309 
310  // Polymer case
311  else if (phases.active(Phase::POLYMER)) {
312  return this->runPolymer(phases);
313  }
314 
315  // Foam case
316  else if (phases.active(Phase::FOAM)) {
317  return this->runFoam();
318  }
319 
320  // Brine case
321  else if (phases.active(Phase::BRINE)) {
322  return this->runBrine(phases);
323  }
324 
325  // Solvent case
326  else if (phases.active(Phase::SOLVENT)) {
327  return this->runSolvent();
328  }
329 
330  // Extended BO case
331  else if (phases.active(Phase::ZFRACTION)) {
332  return this->runExtendedBlackOil();
333  }
334 
335  // Energy case
336  else if (eclipseState_->getSimulationConfig().isThermal()) {
337  return this->runThermal(phases);
338  }
339 
340  // Blackoil case
341  else if (phases.size() == 3) {
342  return this->runBlackOil();
343  }
344 
345  else {
346  if (outputCout_) {
347  std::cerr << "No suitable configuration found, valid are "
348  << "Twophase, polymer, foam, brine, solvent, "
349  << "energy, and blackoil.\n";
350  }
351 
352  return EXIT_FAILURE;
353  }
354  }
355 
356  template <class TypeTag>
357  int dispatchStatic_()
358  {
359  flowEbosSetDeck<TypeTag>(
360  deck_, eclipseState_, schedule_, summaryConfig_);
361  return flowEbosMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
362  }
363 
370  template <class TypeTagEarlyBird>
371  bool initialize_(int& exitCode)
372  {
373  Dune::Timer externalSetupTimer;
374  externalSetupTimer.start();
375 
376  handleVersionCmdLine_(argc_, argv_);
377 #if HAVE_DUNE_FEM
378  int mpiRank = Dune::Fem::MPIManager::rank();
379 #else
380  int mpiRank = EclGenericVanguard::comm().rank();
381 #endif
382 
383  // we always want to use the default locale, and thus spare us the trouble
384  // with incorrect locale settings.
385  resetLocale();
386 
387  // this is a work-around for a catch 22: we do not know what code path to use without
388  // parsing the deck, but we don't know the deck without having access to the
389  // parameters and this requires to know the type tag to be used. To solve this, we
390  // use a type tag just for parsing the parameters before we instantiate the actual
391  // simulator object. (Which parses the parameters again, but since this is done in an
392  // identical manner it does not matter.)
393  typedef TypeTagEarlyBird PreTypeTag;
394  using PreProblem = GetPropType<PreTypeTag, Properties::Problem>;
395 
396  PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
397  int status = FlowMainEbos<PreTypeTag>::setupParameters_(argc_, argv_, EclGenericVanguard::comm());
398  if (status != 0) {
399  // if setupParameters_ returns a value smaller than 0, there was no error, but
400  // the program should abort. This is the case e.g. for the --help and the
401  // --print-properties parameters.
402 #if HAVE_MPI
403  if (status >= 0)
404  MPI_Abort(MPI_COMM_WORLD, status);
405 #endif
406  exitCode = (status > 0) ? status : EXIT_SUCCESS;
407  return false; // Whether to run the simulator
408  }
409 
411  outputCout_ = false;
412  if (mpiRank == 0)
413  outputCout_ = EWOMS_GET_PARAM(PreTypeTag, bool, EnableTerminalOutput);
414 
415  std::string deckFilename;
416  std::string outputDir;
417  if ( eclipseState_ ) {
418  deckFilename = eclipseState_->getIOConfig().fullBasePath();
419  outputDir = eclipseState_->getIOConfig().getOutputDir();
420  }
421  else {
422  deckFilename = EWOMS_GET_PARAM(PreTypeTag, std::string, EclDeckFileName);
423  }
424 
425  if (deckFilename.empty()) {
426  if (mpiRank == 0) {
427  std::cerr << "No input case given. Try '--help' for a usage description.\n";
428  }
429  exitCode = EXIT_FAILURE;
430  return false;
431  }
432 
433  using PreVanguard = GetPropType<PreTypeTag, Properties::Vanguard>;
434  try {
435  deckFilename = PreVanguard::canonicalDeckPath(deckFilename);
436  }
437  catch (const std::exception& e) {
438  if ( mpiRank == 0 ) {
439  std::cerr << "Exception received: " << e.what() << ". Try '--help' for a usage description.\n";
440  }
441 #if HAVE_MPI
442  MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
443 #endif
444  exitCode = EXIT_FAILURE;
445  return false;
446  }
447  if (outputCout_) {
448  FlowMainEbos<PreTypeTag>::printBanner(EclGenericVanguard::comm());
449  }
450  // Create Deck and EclipseState.
451  try {
452  auto python = std::make_shared<Python>();
453  const bool init_from_restart_file = !EWOMS_GET_PARAM(PreTypeTag, bool, SchedRestart);
454  if (outputDir.empty())
455  outputDir = EWOMS_GET_PARAM(PreTypeTag, std::string, OutputDir);
456 
457  const bool allRanksDbgPrtLog = EWOMS_GET_PARAM(PreTypeTag, bool,
458  EnableLoggingFalloutWarning);
459  outputMode = setupLogging(mpiRank,
460  deckFilename,
461  outputDir,
462  EWOMS_GET_PARAM(PreTypeTag, std::string, OutputMode),
463  outputCout_, "STDOUT_LOGGER", allRanksDbgPrtLog);
464  auto parseContext =
465  std::make_unique<ParseContext>(std::vector<std::pair<std::string , InputError::Action>>
466  {{ParseContext::PARSE_RANDOM_SLASH, InputError::IGNORE},
467  {ParseContext::PARSE_MISSING_DIMS_KEYWORD, InputError::WARN},
468  {ParseContext::SUMMARY_UNKNOWN_WELL, InputError::WARN},
469  {ParseContext::SUMMARY_UNKNOWN_GROUP, InputError::WARN}});
470  if (EWOMS_GET_PARAM(PreTypeTag, bool, EclStrictParsing))
471  parseContext->update(InputError::DELAYED_EXIT1);
472 
474 
475  if (outputCout_) {
476  OpmLog::info("Reading deck file '" + deckFilename + "'");
477  }
478 
479  std::optional<int> outputInterval;
480  int output_param = EWOMS_GET_PARAM(PreTypeTag, int, EclOutputInterval);
481  if (output_param >= 0)
482  outputInterval = output_param;
483 
484  readDeck(EclGenericVanguard::comm(), deckFilename, deck_, eclipseState_, schedule_, udqState_, actionState_, wtestState_,
485  summaryConfig_, nullptr, python, std::move(parseContext),
486  init_from_restart_file, outputCout_, outputInterval);
487 
488  verifyValidCellGeometry(EclGenericVanguard::comm(), *this->eclipseState_);
489 
490  setupTime_ = externalSetupTimer.elapsed();
491  outputFiles_ = (outputMode != FileOutputMode::OUTPUT_NONE);
492  }
493  catch (const std::invalid_argument& e)
494  {
495  if (outputCout_) {
496  std::cerr << "Failed to create valid EclipseState object." << std::endl;
497  std::cerr << "Exception caught: " << e.what() << std::endl;
498  }
499 #if HAVE_MPI
500  MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
501 #endif
502  exitCode = EXIT_FAILURE;
503  return false;
504  }
505 
506  exitCode = EXIT_SUCCESS;
507  return true;
508  }
509 
510  std::filesystem::path simulationCaseName_(const std::string& casename)
511  {
512  namespace fs = ::std::filesystem;
513 
514  auto exists = [](const fs::path& f)
515  {
516  return (fs::exists(f) && fs::is_regular_file(f))
517  || (fs::is_symlink(f) &&
518  fs::is_regular_file(fs::read_symlink(f)));
519  };
520 
521  auto simcase = fs::path { casename };
522 
523  if (exists(simcase)) {
524  return simcase;
525  }
526 
527  for (const auto& ext : { std::string("DATA"), std::string("data") }) {
528  if (exists(simcase.replace_extension(ext))) {
529  return simcase;
530  }
531  }
532 
533  throw std::invalid_argument {
534  "Cannot find input case '" + casename + '\''
535  };
536  }
537 
538  // This function is an extreme special case, if the program has been invoked
539  // *exactly* as:
540  //
541  // flow --version
542  //
543  // the call is intercepted by this function which will print "flow $version"
544  // on stdout and exit(0).
545  void handleVersionCmdLine_(int argc, char** argv)
546  {
547  auto pos = std::find_if(argv, argv + argc,
548  [](const char* arg)
549  {
550  return std::strcmp(arg, "--version") == 0;
551  });
552 
553  if (pos != argv + argc) {
554  std::cout << "flow " << moduleVersionName() << std::endl;
555  std::exit(EXIT_SUCCESS);
556  }
557  }
558 
559  // This function is a special case, if the program has been invoked
560  // with the argument "--test-split-communicator=true" as the FIRST
561  // argument, it will be removed from the argument list and we set the
562  // test_split_comm_ flag to true.
563  // Note: initializing the parameter system before MPI could make this
564  // use the parameter system instead.
565  void handleTestSplitCommunicatorCmdLine_()
566  {
567  if (argc_ >= 2 && std::strcmp(argv_[1], "--test-split-communicator=true") == 0) {
568  test_split_comm_ = true;
569  --argc_; // We have one less argument.
570  argv_[1] = argv_[0]; // What used to be the first proper argument now becomes the command argument.
571  ++argv_; // Pretend this is what it always was.
572  }
573  }
574 
575  int runMICP(const Phases& phases)
576  {
577  if (!phases.active(Phase::WATER) || (phases.size() > 2)) {
578  if (outputCout_) {
579  std::cerr << "No valid configuration is found for MICP simulation, "
580  << "the only valid option is water + MICP\n";
581  }
582 
583  return EXIT_FAILURE;
584  }
585 
586  flowEbosMICPSetDeck(this->setupTime_,
587  this->deck_,
588  this->eclipseState_,
589  this->schedule_,
590  this->summaryConfig_);
591 
592  return flowEbosMICPMain(this->argc_,
593  this->argv_,
594  this->outputCout_,
595  this->outputFiles_);
596  }
597 
598  int runTwoPhase(const Phases& phases)
599  {
600  // oil-gas
601  if (phases.active( Phase::OIL ) && phases.active( Phase::GAS )) {
602  flowEbosGasOilSetDeck(
603  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
604  return flowEbosGasOilMain(argc_, argv_, outputCout_, outputFiles_);
605  }
606 
607  // oil-water
608  else if ( phases.active( Phase::OIL ) && phases.active( Phase::WATER ) ) {
609  flowEbosOilWaterSetDeck(
610  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
611  return flowEbosOilWaterMain(argc_, argv_, outputCout_, outputFiles_);
612  }
613 
614  // gas-water
615  else if ( phases.active( Phase::GAS ) && phases.active( Phase::WATER ) ) {
616  flowEbosGasWaterSetDeck(
617  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
618  return flowEbosGasWaterMain(argc_, argv_, outputCout_, outputFiles_);
619  }
620  else {
621  if (outputCout_) {
622  std::cerr << "No suitable configuration found, valid are Twophase (oilwater, oilgas and gaswater), polymer, solvent, or blackoil" << std::endl;
623  }
624 
625  return EXIT_FAILURE;
626  }
627  }
628 
629  int runPolymer(const Phases& phases)
630  {
631  if (! phases.active(Phase::WATER)) {
632  if (outputCout_)
633  std::cerr << "No valid configuration is found for polymer simulation, valid options include "
634  << "oilwater + polymer and blackoil + polymer" << std::endl;
635 
636  return EXIT_FAILURE;
637  }
638 
639  // Need to track the polymer molecular weight
640  // for the injectivity study
641  if (phases.active(Phase::POLYMW)) {
642  // only oil water two phase for now
643  assert (phases.size() == 4);
644  return flowEbosOilWaterPolymerInjectivityMain(argc_, argv_, outputCout_, outputFiles_);
645  }
646 
647  if (phases.size() == 3) { // oil water polymer case
648  flowEbosOilWaterPolymerSetDeck(
649  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
650  return flowEbosOilWaterPolymerMain(argc_, argv_, outputCout_, outputFiles_);
651  }
652  else {
653  flowEbosPolymerSetDeck(
654  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
655  return flowEbosPolymerMain(argc_, argv_, outputCout_, outputFiles_);
656  }
657  }
658 
659  int runFoam()
660  {
661  flowEbosFoamSetDeck(
662  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
663 
664  return flowEbosFoamMain(argc_, argv_, outputCout_, outputFiles_);
665  }
666 
667  int runWaterOnly(const Phases& phases)
668  {
669  if (!phases.active(Phase::WATER) || phases.size() != 1) {
670  if (outputCout_)
671  std::cerr << "No valid configuration is found for water-only simulation, valid options include "
672  << "water, water + thermal" << std::endl;
673 
674  return EXIT_FAILURE;
675  }
676  flowEbosWaterOnlySetDeck(
677  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
678 
679  return flowEbosWaterOnlyMain(argc_, argv_, outputCout_, outputFiles_);
680  }
681 
682  int runWaterOnlyEnergy(const Phases& phases)
683  {
684  if (!phases.active(Phase::WATER) || phases.size() != 2) {
685  if (outputCout_)
686  std::cerr << "No valid configuration is found for water-only simulation, valid options include "
687  << "water, water + thermal" << std::endl;
688 
689  return EXIT_FAILURE;
690  }
691  flowEbosWaterOnlyEnergySetDeck(
692  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
693 
694  return flowEbosWaterOnlyEnergyMain(argc_, argv_, outputCout_, outputFiles_);
695  }
696 
697  int runBrine(const Phases& phases)
698  {
699  if (! phases.active(Phase::WATER) || phases.size() == 2) {
700  if (outputCout_)
701  std::cerr << "No valid configuration is found for brine simulation, valid options include "
702  << "oilwater + brine, gaswater + brine and blackoil + brine" << std::endl;
703 
704  return EXIT_FAILURE;
705  }
706 
707  if (phases.size() == 3) {
708 
709  if (phases.active(Phase::OIL)){ // oil water brine case
710  flowEbosOilWaterBrineSetDeck(
711  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
712  return flowEbosOilWaterBrineMain(argc_, argv_, outputCout_, outputFiles_);
713  }
714  if (phases.active(Phase::GAS)){ // gas water brine case
715  if (eclipseState_->getSimulationConfig().hasPRECSALT() &&
716  eclipseState_->getSimulationConfig().hasVAPWAT()) {
717  //case with water vaporization into gas phase and salt precipitation
718  flowEbosGasWaterSaltprecVapwatSetDeck(
719  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
720  return flowEbosGasWaterSaltprecVapwatMain(argc_, argv_, outputCout_, outputFiles_);
721  }
722  else {
723  flowEbosGasWaterBrineSetDeck(
724  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
725  return flowEbosGasWaterBrineMain(argc_, argv_, outputCout_, outputFiles_);
726  }
727  }
728  }
729  else if (eclipseState_->getSimulationConfig().hasPRECSALT()) {
730  flowEbosBrineSaltPrecipitationSetDeck(
731  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
732  return flowEbosBrineSaltPrecipitationMain(argc_, argv_, outputCout_, outputFiles_);
733  }
734  else {
735  flowEbosBrineSetDeck(
736  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
737  return flowEbosBrineMain(argc_, argv_, outputCout_, outputFiles_);
738  }
739 
740  return EXIT_FAILURE;
741  }
742 
743  int runSolvent()
744  {
745  flowEbosSolventSetDeck(
746  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
747 
748  return flowEbosSolventMain(argc_, argv_, outputCout_, outputFiles_);
749  }
750 
751  int runExtendedBlackOil()
752  {
753  flowEbosExtboSetDeck(
754  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
755 
756  return flowEbosExtboMain(argc_, argv_, outputCout_, outputFiles_);
757  }
758 
759  int runThermal(const Phases& phases)
760  {
761  // oil-gas-thermal
762  if (!phases.active( Phase::WATER ) && phases.active( Phase::OIL ) && phases.active( Phase::GAS )) {
763  flowEbosGasOilEnergySetDeck(
764  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
765  return flowEbosGasOilEnergyMain(argc_, argv_, outputCout_, outputFiles_);
766  }
767 
768  flowEbosEnergySetDeck(
769  setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
770 
771  return flowEbosEnergyMain(argc_, argv_, outputCout_, outputFiles_);
772  }
773 
774  int runBlackOil()
775  {
776  flowEbosBlackoilSetDeck(this->setupTime_,
777  this->deck_,
778  this->eclipseState_,
779  this->schedule_,
780  std::move(this->udqState_),
781  std::move(this->actionState_),
782  std::move(this->wtestState_),
783  this->summaryConfig_);
784 
785  return flowEbosBlackoilMain(argc_, argv_, outputCout_, outputFiles_);
786  }
787 
788  int argc_{0};
789  char** argv_{nullptr};
790  bool outputCout_{false};
791  bool outputFiles_{false};
792  double setupTime_{0.0};
793  std::string deckFilename_{};
794  std::string flowProgName_{};
795  char *saveArgs_[3]{nullptr};
796  std::unique_ptr<UDQState> udqState_{};
797  std::unique_ptr<Action::State> actionState_{};
798  std::unique_ptr<WellTestState> wtestState_{};
799 
800  // These variables may be owned by both Python and the simulator
801  std::shared_ptr<Deck> deck_{};
802  std::shared_ptr<EclipseState> eclipseState_{};
803  std::shared_ptr<Schedule> schedule_{};
804  std::shared_ptr<SummaryConfig> summaryConfig_{};
805 
806  // To demonstrate run with non_world_comm
807  bool test_split_comm_ = false;
808  bool isSimulationRank_ = true;
809 };
810 
811 } // namespace Opm
812 
813 #endif // OPM_MAIN_HEADER_INCLUDED
Definition: FlowMainEbos.hpp:88
Definition: Main.hpp:132
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: BlackoilPhases.hpp:27
std::string moduleVersionName()
Return the version name of the module, for example "2015.10" (for a release branch) or "2016....
Definition: moduleVersion.cpp:29
FileOutputMode
Definition: readDeck.hpp:49
@ OUTPUT_NONE
No file output.
void readDeck(Parallel::Communication comm, const std::string &deckFilename, std::shared_ptr< Deck > &deck, std::shared_ptr< EclipseState > &eclipseState, std::shared_ptr< Schedule > &schedule, std::unique_ptr< UDQState > &udqState, std::unique_ptr< Action::State > &actionState, std::unique_ptr< WellTestState > &wtestState, std::shared_ptr< SummaryConfig > &summaryConfig, std::unique_ptr< ErrorGuard > errorGuard, std::shared_ptr< Python > python, std::unique_ptr< ParseContext > parseContext, bool initFromRestart, bool checkDeck, const std::optional< int > &outputInterval)
Reads the deck and creates all necessary objects if needed.
Definition: readDeck.cpp:476