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
91namespace Opm::Properties {
92
93// this is a dummy type tag that is used to setup the parameters before the actual
94// simulator.
95namespace TTag {
97 using InheritsFrom = std::tuple<EclFlowProblem>;
98};
99}
100
101} // namespace Opm::Properties
102
103namespace Opm {
104
105// ----------------- Main program -----------------
106template <class TypeTag>
107int 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.
124class Main
125{
126public:
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
286private:
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