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
30
34
35#if HAVE_DUNE_FEM
36#include <dune/fem/misc/mpimanager.hh>
37#else
38#include <dune/common/parallel/mpihelper.hh>
39#endif
40
41#if HAVE_MPI
43#endif
44
45#if HAVE_CUDA
47#endif
48
49#if HAVE_DAMARIS
51#endif
52
53#include <cassert>
54#include <charconv>
55#include <cstdlib>
56#include <filesystem>
57#include <iostream>
58#include <memory>
59#include <stdexcept>
60#include <string>
61#include <string_view>
62#include <type_traits>
63#include <utility>
64
65namespace Opm::Properties {
66
67// this is a dummy type tag that is used to setup the parameters before the actual
68// simulator.
69namespace TTag {
71 using InheritsFrom = std::tuple<FlowProblem>;
72};
73}
74
75} // namespace Opm::Properties
76
77namespace Opm {
78
79namespace Action { class State; }
80class UDQState;
81class WellTestState;
82
83// ----------------- Main program -----------------
84template <class TypeTag>
85int flowMain(int argc, char** argv, bool outputCout, bool outputFiles)
86{
87 // we always want to use the default locale, and thus spare us the trouble
88 // with incorrect locale settings.
89 resetLocale();
90
91 FlowMain<TypeTag> mainfunc(argc, argv, outputCout, outputFiles);
92 return mainfunc.execute();
93}
94
95// ----------------- Main class -----------------
96// For now, we will either be instantiated from main() in flow.cpp,
97// or from a Python pybind11 module..
98// NOTE (March 2020): When used from a pybind11 module, we do not neccessarily
99// want to run the whole simulation by calling run(), it is also
100// useful to just run one report step at a time. According to these different
101// usage scenarios, we refactored the original run() in flow.cpp into this class.
102class Main
103{
104public:
105 Main(int argc, char** argv, bool ownMPI = true);
106
107 // This constructor can be called from Python
108 explicit Main(const std::string& filename, bool mpi_init = true, bool mpi_finalize = true);
109
110 // This constructor can be called from Python when Python has
111 // already parsed a deck
112 Main(const std::string& filename,
113 std::shared_ptr<EclipseState> eclipseState,
114 std::shared_ptr<Schedule> schedule,
115 std::shared_ptr<SummaryConfig> summaryConfig,
116 bool mpi_init = true,
117 bool mpi_finalize = true);
118
120
121 void setArgvArgc_(const std::string& filename);
124 void initMPI();
125
133 {
134 int exitCode = EXIT_SUCCESS;
135 if (initialize_<Properties::TTag::FlowEarlyBird>(exitCode)) {
137 if (isSimulationRank_) {
138 return this->dispatchDynamic_();
139 }
140 }
141
142 return exitCode;
143 }
144
152 template <class TypeTag>
154 {
155 int exitCode = EXIT_SUCCESS;
156 if (initialize_<TypeTag>(exitCode)) {
157 if (isSimulationRank_) {
158 return this->dispatchStatic_<TypeTag>();
159 }
160 }
161
162 return exitCode;
163 }
164
167 {
168 int exitCode = EXIT_SUCCESS;
169 initialize_<Properties::TTag::FlowEarlyBird>(exitCode);
170 return exitCode;
171 }
172
173protected:
181 template <class TypeTagEarlyBird>
182 bool initialize_(int& exitCode, bool keepKeywords = false)
183 {
184 Dune::Timer externalSetupTimer;
185 externalSetupTimer.start();
186
187 handleVersionCmdLine_(argc_, argv_, Opm::moduleVersionName());
188
189 // we always want to use the default locale, and thus spare us the trouble
190 // with incorrect locale settings.
191 resetLocale();
192
193 // this is a work-around for a catch 22: we do not know what code path to use without
194 // parsing the deck, but we don't know the deck without having access to the
195 // parameters and this requires to know the type tag to be used. To solve this, we
196 // use a type tag just for parsing the parameters before we instantiate the actual
197 // simulator object. (Which parses the parameters again, but since this is done in an
198 // identical manner it does not matter.)
199 typedef TypeTagEarlyBird PreTypeTag;
201
202 PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
203 int status = FlowMain<PreTypeTag>::setupParameters_(argc_, argv_, FlowGenericVanguard::comm());
204 if (status != 0) {
205 // if setupParameters_ returns a value smaller than 0, there was no error, but
206 // the program should abort. This is the case e.g. for the --help and the
207 // --print-properties parameters.
208#if HAVE_MPI
209 if (status >= 0)
210 MPI_Abort(MPI_COMM_WORLD, status);
211#endif
212 exitCode = (status > 0) ? status : EXIT_SUCCESS;
213 return false; // Whether to run the simulator
214 }
215
216 OpmLog::setDebugVerbosityLevel(Parameters::Get<Parameters::DebugVerbosityLevel>());
217
218 std::string deckFilename;
219 std::string outputDir;
220 if ( eclipseState_ ) {
221 deckFilename = eclipseState_->getIOConfig().fullBasePath();
222 outputDir = eclipseState_->getIOConfig().getOutputDir();
223 }
224 else {
225 deckFilename = Parameters::Get<Parameters::EclDeckFileName>();
226 outputDir = Parameters::Get<Parameters::OutputDir>();
227 }
228
229#if HAVE_DAMARIS
230 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
231
232 // Reset to false as we cannot use Damaris if there is only one rank.
233 if ((enableDamarisOutput_ == true) && (FlowGenericVanguard::comm().size() == 1)) {
234 std::string msg ;
235 msg = "\nUse of Damaris (command line argument --enable-damaris-output=true) has been disabled for run with only one rank.\n" ;
236 OpmLog::warning(msg);
237 enableDamarisOutput_ = false ;
238 }
239
240 if (enableDamarisOutput_) {
241 // Deal with empty (defaulted) output dir, should be deck dir
242 auto damarisOutputDir = outputDir;
243 if (outputDir.empty()) {
244 auto odir = std::filesystem::path{deckFilename}.parent_path();
245 if (odir.empty()) {
246 damarisOutputDir = ".";
247 } else {
248 damarisOutputDir = odir.generic_string();
249 }
250 }
251 // Damaris server ranks will block here until damaris_stop() is called by client ranks
252 this->setupDamaris(damarisOutputDir);
253 }
254#endif // HAVE_DAMARIS
255
256 // Guard for when the Damaris core(s) return from damaris_start()
257 // which happens when damaris_stop() is called in main simulation
258 if (!isSimulationRank_) {
259 exitCode = EXIT_SUCCESS;
260 return true;
261 }
262
263 int mpiRank = FlowGenericVanguard::comm().rank();
264 outputCout_ = false;
265 if (mpiRank == 0)
266 outputCout_ = Parameters::Get<Parameters::EnableTerminalOutput>();
267
268 if (deckFilename.empty()) {
269 if (mpiRank == 0) {
270 std::cerr << "No input case given. Try '--help' for a usage description.\n";
271 }
272 exitCode = EXIT_FAILURE;
273 return false;
274 }
275
277 try {
278 deckFilename = PreVanguard::canonicalDeckPath(deckFilename);
279 }
280 catch (const std::exception& e) {
281 if ( mpiRank == 0 ) {
282 std::cerr << "Exception received: " << e.what() << ". Try '--help' for a usage description.\n";
283 }
284#if HAVE_MPI
285 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
286#endif
287 exitCode = EXIT_FAILURE;
288 return false;
289 }
290
291 std::string cmdline_params;
292 if (outputCout_) {
294 getNumThreads(),
296 std::ostringstream str;
298 cmdline_params = str.str();
299 }
300
301 // Create Deck and EclipseState.
302 try {
303 this->readDeck(deckFilename,
304 outputDir,
305 Parameters::Get<Parameters::OutputMode>(),
306 !Parameters::Get<Parameters::SchedRestart>(),
307 Parameters::Get<Parameters::EnableLoggingFalloutWarning>(),
308 Parameters::Get<Parameters::ParsingStrictness>(),
309 Parameters::Get<Parameters::ActionParsingStrictness>(),
310 Parameters::Get<Parameters::InputSkipMode>(),
311 keepKeywords,
312 getNumThreads(),
313 Parameters::Get<Parameters::EclOutputInterval>(),
314 Parameters::Get<Parameters::Slave>(),
315 cmdline_params,
318 setupTime_ = externalSetupTimer.elapsed();
319 }
320 catch (const std::invalid_argument& e)
321 {
322 if (outputCout_) {
323 std::cerr << "Failed to create valid EclipseState object." << std::endl;
324 std::cerr << "Exception caught: " << e.what() << std::endl;
325 }
326#if HAVE_MPI
327 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
328#endif
329 exitCode = EXIT_FAILURE;
330 return false;
331 }
332
333#if HAVE_CUDA
335#endif
336
337 exitCode = EXIT_SUCCESS;
338 return true;
339 }
340
342
343private:
344 // This function is an extreme special case, if the program has been invoked
345 // *exactly* as:
346 //
347 // flow --version
348 //
349 // the call is intercepted by this function which will print "flow $version"
350 // on stdout and exit(0).
351 void handleVersionCmdLine_(int argc, char** argv,
352 std::string_view moduleVersionName);
353
354 // This function is a special case, if the program has been invoked
355 // with the argument "--test-split-communicator=true" as the FIRST
356 // argument, it will be removed from the argument list and we set the
357 // test_split_comm_ flag to true.
358 // Note: initializing the parameter system before MPI could make this
359 // use the parameter system instead.
360 void handleTestSplitCommunicatorCmdLine_();
361
367 int dispatchDynamic_();
368
377 template <class TypeTag>
378 int dispatchStatic_()
379 {
380 this->setupVanguard();
381 return flowMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
382 }
383
392 int runMICP(const Phases& phases);
393
402 int runTwoPhase(const Phases& phases);
403
412 int runPolymer(const Phases& phases);
413
419 int runFoam();
420
429 int runWaterOnly(const Phases& phases);
430
439 int runWaterOnlyEnergy(const Phases& phases);
440
449 int runBrine(const Phases& phases);
450
459 int runSolvent(const Phases& phases);
460
466 int runExtendedBlackOil();
467
476 int runThermal(const Phases& phases);
477
483 int runBlackOil();
484
485 void readDeck(const std::string& deckFilename,
486 const std::string& outputDir,
487 const std::string& outputMode,
488 const bool init_from_restart_file,
489 const bool allRanksDbgPrtLog,
490 const std::string& parsingStrictness,
491 const std::string& actionParsingStrictness,
492 const std::string& inputSkipMode,
493 const bool keepKeywords,
494 const std::size_t numThreads,
495 const int output_param,
496 const bool slaveMode,
497 const std::string& parameters,
498 std::string_view moduleVersion,
499 std::string_view compileTimestamp);
500
501 static int getNumThreads()
502 {
503#ifdef _OPENMP
504 return omp_get_max_threads();
505#else
506 return 1;
507#endif
508 }
509
510#if HAVE_DAMARIS
511 void setupDamaris(const std::string& outputDir);
512#endif
513
514protected:
515 int argc_{0};
516 char** argv_{nullptr};
517 bool outputCout_{false};
518 bool outputFiles_{false};
519
520private:
521 bool ownMPI_{true};
522 double setupTime_{0.0};
523 std::string deckFilename_{};
524 std::string flowProgName_{};
525 char *saveArgs_[3]{nullptr};
526 std::unique_ptr<UDQState> udqState_{};
527 std::unique_ptr<Action::State> actionState_{};
528 std::unique_ptr<WellTestState> wtestState_{};
529
530 // These variables may be owned by both Python and the simulator
531 std::shared_ptr<EclipseState> eclipseState_{};
532 std::shared_ptr<Schedule> schedule_{};
533 std::shared_ptr<SummaryConfig> summaryConfig_{};
534 bool mpi_init_{true};
535 bool mpi_finalize_{true};
536
537 // To demonstrate run with non_world_comm
538 bool test_split_comm_ = false;
539 bool isSimulationRank_ = true;
540#if HAVE_MPI
541 std::string reservoirCouplingSlaveOutputFilename_{};
542#endif
543#if HAVE_DAMARIS
544 bool enableDamarisOutput_ = false;
545#endif
546};
547
548} // namespace Opm
549
550#endif // OPM_MAIN_HEADER_INCLUDED
static Parallel::Communication & comm()
Obtain global communicator.
Definition: FlowGenericVanguard.hpp:332
Definition: Main.hpp:103
int argc_
Definition: Main.hpp:515
int justInitialize()
Used for test_outputdir.
Definition: Main.hpp:166
void maybeSaveReservoirCouplingSlaveLogFilename_()
bool initialize_(int &exitCode, bool keepKeywords=false)
Initialize.
Definition: Main.hpp:182
bool outputFiles_
Definition: Main.hpp:518
void maybeRedirectReservoirCouplingSlaveOutput_()
int runDynamic()
Definition: Main.hpp:132
Main(int argc, char **argv, bool ownMPI=true)
char ** argv_
Definition: Main.hpp:516
Main(const std::string &filename, bool mpi_init=true, bool mpi_finalize=true)
int runStatic()
Definition: Main.hpp:153
void setupVanguard()
void setArgvArgc_(const std::string &filename)
bool outputCout_
Definition: Main.hpp:517
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:79
void printDevice()
Definition: blackoilboundaryratevector.hh:39
std::string moduleVersionName()
int flowMain(int argc, char **argv, bool outputCout, bool outputFiles)
Definition: Main.hpp:85
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:71