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