Main.hpp
Go to the documentation of this file.
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 Copyright 2023 Inria
7
8 This file is part of the Open Porous Media project (OPM).
9
10 OPM is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 OPM is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with OPM. If not, see <http://www.gnu.org/licenses/>.
22*/
23#ifndef OPM_MAIN_HEADER_INCLUDED
24#define OPM_MAIN_HEADER_INCLUDED
25
26#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
27#include <opm/input/eclipse/Schedule/Action/State.hpp>
28#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
29
32
36
37#if HAVE_DUNE_FEM
38#include <dune/fem/misc/mpimanager.hh>
39#else
40#include <dune/common/parallel/mpihelper.hh>
41#endif
42
43#if HAVE_MPI
45#endif
46
47#if HAVE_CUDA
49#endif
50
51#if HAVE_DAMARIS
53#endif
54
55#include <cassert>
56#include <charconv>
57#include <cstdlib>
58#include <filesystem>
59#include <iostream>
60#include <memory>
61#include <stdexcept>
62#include <string>
63#include <string_view>
64#include <type_traits>
65#include <utility>
66
67namespace Opm::Properties {
68
69// this is a dummy type tag that is used to setup the parameters before the actual
70// simulator.
71namespace TTag {
73 using InheritsFrom = std::tuple<FlowProblem>;
74};
75}
76
77} // namespace Opm::Properties
78
79namespace Opm {
80
81namespace Action { class State; }
82class UDQState;
83class WellTestState;
84
85// ----------------- Main program -----------------
86template <class TypeTag>
87int flowMain(int argc, char** argv, bool outputCout, bool outputFiles)
88{
89 // we always want to use the default locale, and thus spare us the trouble
90 // with incorrect locale settings.
91 resetLocale();
92
93 FlowMain<TypeTag> mainfunc(argc, argv, outputCout, outputFiles);
94 return mainfunc.execute();
95}
96
97// ----------------- Main class -----------------
98// For now, we will either be instantiated from main() in flow.cpp,
99// or from a Python pybind11 module..
100// NOTE (March 2020): When used from a pybind11 module, we do not neccessarily
101// want to run the whole simulation by calling run(), it is also
102// useful to just run one report step at a time. According to these different
103// usage scenarios, we refactored the original run() in flow.cpp into this class.
104class Main
105{
106public:
107 Main(int argc, char** argv, bool ownMPI = true);
108
109 // This constructor can be called from Python
110 explicit Main(const std::string& filename, bool mpi_init = true, bool mpi_finalize = true);
111
112 // This constructor can be called from Python when Python has
113 // already parsed a deck
114 Main(const std::string& filename,
115 std::shared_ptr<EclipseState> eclipseState,
116 std::shared_ptr<Schedule> schedule,
117 std::shared_ptr<SummaryConfig> summaryConfig,
118 bool mpi_init = true,
119 bool mpi_finalize = true);
120
122
123 void setArgvArgc_(const std::string& filename);
126 void initMPI();
127
135 {
136 int exitCode = EXIT_SUCCESS;
137 if (initialize_<Properties::TTag::FlowEarlyBird>(exitCode)) {
139 if (isSimulationRank_) {
140 return this->dispatchDynamic_();
141 }
142 }
143
144 return exitCode;
145 }
146
154 template <class TypeTag>
156 {
157 int exitCode = EXIT_SUCCESS;
158 if (initialize_<TypeTag>(exitCode)) {
159 if (isSimulationRank_) {
160 return this->dispatchStatic_<TypeTag>();
161 }
162 }
163
164 return exitCode;
165 }
166
169 {
170 int exitCode = EXIT_SUCCESS;
171 initialize_<Properties::TTag::FlowEarlyBird>(exitCode);
172 return exitCode;
173 }
174
175protected:
183 template <class TypeTagEarlyBird>
184 bool initialize_(int& exitCode, bool keepKeywords = false)
185 {
186 Dune::Timer externalSetupTimer;
187 externalSetupTimer.start();
188
189 handleVersionCmdLine_(argc_, argv_, Opm::moduleVersionName());
190
191 // we always want to use the default locale, and thus spare us the trouble
192 // with incorrect locale settings.
193 resetLocale();
194
195 // this is a work-around for a catch 22: we do not know what code path to use without
196 // parsing the deck, but we don't know the deck without having access to the
197 // parameters and this requires to know the type tag to be used. To solve this, we
198 // use a type tag just for parsing the parameters before we instantiate the actual
199 // simulator object. (Which parses the parameters again, but since this is done in an
200 // identical manner it does not matter.)
201 typedef TypeTagEarlyBird PreTypeTag;
203
204 PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
205 int status = FlowMain<PreTypeTag>::setupParameters_(argc_, argv_, FlowGenericVanguard::comm());
206 if (status != 0) {
207 // if setupParameters_ returns a value smaller than 0, there was no error, but
208 // the program should abort. This is the case e.g. for the --help and the
209 // --print-properties parameters.
210#if HAVE_MPI
211 if (status >= 0)
212 MPI_Abort(MPI_COMM_WORLD, status);
213#endif
214 exitCode = (status > 0) ? status : EXIT_SUCCESS;
215 return false; // Whether to run the simulator
216 }
217
218 OpmLog::setDebugVerbosityLevel(Parameters::Get<Parameters::DebugVerbosityLevel>());
219
220 std::string deckFilename;
221 std::string outputDir;
222 if ( eclipseState_ ) {
223 deckFilename = eclipseState_->getIOConfig().fullBasePath();
224 outputDir = eclipseState_->getIOConfig().getOutputDir();
225 }
226 else {
227 deckFilename = Parameters::Get<Parameters::EclDeckFileName>();
228 outputDir = Parameters::Get<Parameters::OutputDir>();
229 }
230
231#if HAVE_DAMARIS
232 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
233
234 // Reset to false as we cannot use Damaris if there is only one rank.
235 if ((enableDamarisOutput_ == true) && (FlowGenericVanguard::comm().size() == 1)) {
236 std::string msg ;
237 msg = "\nUse of Damaris (command line argument --enable-damaris-output=true) has been disabled for run with only one rank.\n" ;
238 OpmLog::warning(msg);
239 enableDamarisOutput_ = false ;
240 }
241
242 if (enableDamarisOutput_) {
243 // Deal with empty (defaulted) output dir, should be deck dir
244 auto damarisOutputDir = outputDir;
245 if (outputDir.empty()) {
246 auto odir = std::filesystem::path{deckFilename}.parent_path();
247 if (odir.empty()) {
248 damarisOutputDir = ".";
249 } else {
250 damarisOutputDir = odir.generic_string();
251 }
252 }
253 // Damaris server ranks will block here until damaris_stop() is called by client ranks
254 this->setupDamaris(damarisOutputDir);
255 }
256#endif // HAVE_DAMARIS
257
258 // Guard for when the Damaris core(s) return from damaris_start()
259 // which happens when damaris_stop() is called in main simulation
260 if (!isSimulationRank_) {
261 exitCode = EXIT_SUCCESS;
262 return true;
263 }
264
265 int mpiRank = FlowGenericVanguard::comm().rank();
266 outputCout_ = false;
267 if (mpiRank == 0)
268 outputCout_ = Parameters::Get<Parameters::EnableTerminalOutput>();
269
270 if (deckFilename.empty()) {
271 if (mpiRank == 0) {
272 std::cerr << "No input case given. Try '--help' for a usage description.\n";
273 }
274 exitCode = EXIT_FAILURE;
275 return false;
276 }
277
279 try {
280 deckFilename = PreVanguard::canonicalDeckPath(deckFilename);
281 }
282 catch (const std::exception& e) {
283 if ( mpiRank == 0 ) {
284 std::cerr << "Exception received: " << e.what() << ". Try '--help' for a usage description.\n";
285 }
286#if HAVE_MPI
287 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
288#endif
289 exitCode = EXIT_FAILURE;
290 return false;
291 }
292
293 std::string cmdline_params;
294 if (outputCout_) {
296 getNumThreads(),
298 std::ostringstream str;
300 cmdline_params = str.str();
301 }
302
303 // Create Deck and EclipseState.
304 try {
305 this->readDeck(deckFilename,
306 outputDir,
307 Parameters::Get<Parameters::OutputMode>(),
308 !Parameters::Get<Parameters::SchedRestart>(),
309 Parameters::Get<Parameters::EnableLoggingFalloutWarning>(),
310 Parameters::Get<Parameters::ParsingStrictness>(),
311 Parameters::Get<Parameters::ActionParsingStrictness>(),
312 Parameters::Get<Parameters::InputSkipMode>(),
313 keepKeywords,
314 getNumThreads(),
315 Parameters::Get<Parameters::EclOutputInterval>(),
316 Parameters::Get<Parameters::Slave>(),
317 cmdline_params,
320 setupTime_ = externalSetupTimer.elapsed();
321 }
322 catch (const std::invalid_argument& e)
323 {
324 if (outputCout_) {
325 std::cerr << "Failed to create valid EclipseState object." << std::endl;
326 std::cerr << "Exception caught: " << e.what() << std::endl;
327 }
328#if HAVE_MPI
329 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
330#endif
331 exitCode = EXIT_FAILURE;
332 return false;
333 }
334
335#if HAVE_CUDA
337#endif
338
339 exitCode = EXIT_SUCCESS;
340 return true;
341 }
342
344
345private:
346 // This function is an extreme special case, if the program has been invoked
347 // *exactly* as:
348 //
349 // flow --version
350 //
351 // the call is intercepted by this function which will print "flow $version"
352 // on stdout and exit(0).
353 void handleVersionCmdLine_(int argc, char** argv,
354 std::string_view moduleVersionName);
355
356 // This function is a special case, if the program has been invoked
357 // with the argument "--test-split-communicator=true" as the FIRST
358 // argument, it will be removed from the argument list and we set the
359 // test_split_comm_ flag to true.
360 // Note: initializing the parameter system before MPI could make this
361 // use the parameter system instead.
362 void handleTestSplitCommunicatorCmdLine_();
363
369 int dispatchDynamic_();
370
379 template <class TypeTag>
380 int dispatchStatic_()
381 {
382 this->setupVanguard();
383 return flowMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
384 }
385
394 int runMICP(const Phases& phases);
395
404 int runTwoPhase(const Phases& phases);
405
414 int runBiofilm(const Phases& phases);
415
424 int runPolymer(const Phases& phases);
425
431 int runFoam();
432
441 int runWaterOnly(const Phases& phases);
442
451 int runWaterOnlyEnergy(const Phases& phases);
452
461 int runBrine(const Phases& phases);
462
471 int runSolvent(const Phases& phases);
472
478 int runExtendedBlackOil();
479
488 int runThermal(const Phases& phases);
489
496 int runBlackOilTemp();
497
503 int runBlackOil();
504
505
506
507 void readDeck(const std::string& deckFilename,
508 const std::string& outputDir,
509 const std::string& outputMode,
510 const bool init_from_restart_file,
511 const bool allRanksDbgPrtLog,
512 const std::string& parsingStrictness,
513 const std::string& actionParsingStrictness,
514 const std::string& inputSkipMode,
515 const bool keepKeywords,
516 const std::size_t numThreads,
517 const int output_param,
518 const bool slaveMode,
519 const std::string& parameters,
520 std::string_view moduleVersion,
521 std::string_view compileTimestamp);
522
523 static int getNumThreads()
524 {
525#ifdef _OPENMP
526 return omp_get_max_threads();
527#else
528 return 1;
529#endif
530 }
531
532#if HAVE_DAMARIS
533 void setupDamaris(const std::string& outputDir);
534#endif
535
536protected:
537 int argc_{0};
538 char** argv_{nullptr};
539 bool outputCout_{false};
540 bool outputFiles_{false};
541
542private:
543 bool ownMPI_{true};
544 double setupTime_{0.0};
545 std::string deckFilename_{};
546 std::string flowProgName_{};
547 char *saveArgs_[3]{nullptr};
548 std::unique_ptr<UDQState> udqState_{};
549 std::unique_ptr<Action::State> actionState_{};
550 std::unique_ptr<WellTestState> wtestState_{};
551
552 // These variables may be owned by both Python and the simulator
553 std::shared_ptr<EclipseState> eclipseState_{};
554 std::shared_ptr<Schedule> schedule_{};
555 std::shared_ptr<SummaryConfig> summaryConfig_{};
556 bool mpi_init_{true};
557 bool mpi_finalize_{true};
558
559 // To demonstrate run with non_world_comm
560 bool test_split_comm_ = false;
561 bool isSimulationRank_ = true;
562#if HAVE_MPI
563 std::string reservoirCouplingSlaveOutputFilename_{};
564#endif
565#if HAVE_DAMARIS
566 bool enableDamarisOutput_ = false;
567#endif
568};
569
570} // namespace Opm
571
572#endif // OPM_MAIN_HEADER_INCLUDED
static Parallel::Communication & comm()
Obtain global communicator.
Definition: FlowGenericVanguard.hpp:336
Definition: Main.hpp:105
int argc_
Definition: Main.hpp:537
int justInitialize()
Used for test_outputdir.
Definition: Main.hpp:168
void maybeSaveReservoirCouplingSlaveLogFilename_()
bool initialize_(int &exitCode, bool keepKeywords=false)
Initialize.
Definition: Main.hpp:184
bool outputFiles_
Definition: Main.hpp:540
void maybeRedirectReservoirCouplingSlaveOutput_()
int runDynamic()
Definition: Main.hpp:134
Main(int argc, char **argv, bool ownMPI=true)
char ** argv_
Definition: Main.hpp:538
Main(const std::string &filename, bool mpi_init=true, bool mpi_finalize=true)
int runStatic()
Definition: Main.hpp:155
void setupVanguard()
void setArgvArgc_(const std::string &filename)
bool outputCout_
Definition: Main.hpp:539
void initMPI()
Main(const std::string &filename, std::shared_ptr< EclipseState > eclipseState, std::shared_ptr< Schedule > schedule, std::shared_ptr< SummaryConfig > summaryConfig, bool mpi_init=true, bool mpi_finalize=true)
void printValues(std::ostream &os)
Print values of the run-time parameters.
void reset()
Reset parameter system.
Definition: blackoilmodel.hh:80
void printDevice()
Definition: blackoilbioeffectsmodules.hh:43
std::string moduleVersionName()
int flowMain(int argc, char **argv, bool outputCout, bool outputFiles)
Definition: Main.hpp:87
std::string compileTimestamp()
void printFlowBanner(int nprocs, int threads, std::string_view moduleVersionName)
std::string moduleVersion()
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
This file provides the infrastructure to retrieve run-time parameters.
The Opm property system, traits with inheritance.
std::tuple< FlowProblem > InheritsFrom
Definition: Main.hpp:73