My Project
Loading...
Searching...
No Matches
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 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
31#include <opm/simulators/flow/Banners.hpp>
32#include <opm/simulators/flow/FlowMain.hpp>
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
42#include <opm/simulators/utils/ParallelEclipseState.hpp>
43#endif
44
45#if HAVE_CUDA
46#include <opm/simulators/linalg/gpuistl/device_management.hpp>
47#endif
48
49#if HAVE_DAMARIS
50#include <opm/simulators/utils/DamarisKeywords.hpp>
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.
90
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
119 ~Main();
120
121 void setArgvArgc_(const std::string& filename);
122 void maybeSaveReservoirCouplingSlaveLogFilename_();
123 void maybeRedirectReservoirCouplingSlaveOutput_();
124 void initMPI();
125
133 {
136 Parameters::reset();
137 if (isSimulationRank_) {
138 return this->dispatchDynamic_();
139 }
140 }
141
142 return exitCode;
143 }
144
152 template <class TypeTag>
154 {
157 if (isSimulationRank_) {
158 return this->dispatchStatic_<TypeTag>();
159 }
160 }
161
162 return exitCode;
163 }
164
167 {
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.)
201
202 PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
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 std::string deckFilename;
217 std::string outputDir;
218 if ( eclipseState_ ) {
219 deckFilename = eclipseState_->getIOConfig().fullBasePath();
220 outputDir = eclipseState_->getIOConfig().getOutputDir();
221 }
222 else {
223 deckFilename = Parameters::Get<Parameters::EclDeckFileName>();
224 outputDir = Parameters::Get<Parameters::OutputDir>();
225 }
226
227#if HAVE_DAMARIS
228 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
229
230 // Reset to false as we cannot use Damaris if there is only one rank.
231 if ((enableDamarisOutput_ == true) && (FlowGenericVanguard::comm().size() == 1)) {
232 std::string msg ;
233 msg = "\nUse of Damaris (command line argument --enable-damaris-output=true) has been disabled for run with only one rank.\n" ;
234 OpmLog::warning(msg);
235 enableDamarisOutput_ = false ;
236 }
237
238 if (enableDamarisOutput_) {
239 // Deal with empty (defaulted) output dir, should be deck dir
240 auto damarisOutputDir = outputDir;
241 if (outputDir.empty()) {
242 auto odir = std::filesystem::path{deckFilename}.parent_path();
243 if (odir.empty()) {
244 damarisOutputDir = ".";
245 } else {
246 damarisOutputDir = odir.generic_string();
247 }
248 }
249 // Damaris server ranks will block here until damaris_stop() is called by client ranks
251 }
252#endif // HAVE_DAMARIS
253
254 // Guard for when the Damaris core(s) return from damaris_start()
255 // which happens when damaris_stop() is called in main simulation
256 if (!isSimulationRank_) {
258 return true;
259 }
260
261 int mpiRank = FlowGenericVanguard::comm().rank();
262 outputCout_ = false;
263 if (mpiRank == 0)
264 outputCout_ = Parameters::Get<Parameters::EnableTerminalOutput>();
265
266 if (deckFilename.empty()) {
267 if (mpiRank == 0) {
268 std::cerr << "No input case given. Try '--help' for a usage description.\n";
269 }
271 return false;
272 }
273
275 try {
276 deckFilename = PreVanguard::canonicalDeckPath(deckFilename);
277 }
278 catch (const std::exception& e) {
279 if ( mpiRank == 0 ) {
280 std::cerr << "Exception received: " << e.what() << ". Try '--help' for a usage description.\n";
281 }
282#if HAVE_MPI
284#endif
286 return false;
287 }
288
289 std::string cmdline_params;
290 if (outputCout_) {
291 printFlowBanner(FlowGenericVanguard::comm().size(),
292 getNumThreads(),
294 std::ostringstream str;
295 Parameters::printValues(str);
296 cmdline_params = str.str();
297 }
298
299 // Create Deck and EclipseState.
300 try {
301 this->readDeck(deckFilename,
302 outputDir,
303 Parameters::Get<Parameters::OutputMode>(),
304 !Parameters::Get<Parameters::SchedRestart>(),
305 Parameters::Get<Parameters::EnableLoggingFalloutWarning>(),
306 Parameters::Get<Parameters::ParsingStrictness>(),
307 Parameters::Get<Parameters::ActionParsingStrictness>(),
308 Parameters::Get<Parameters::InputSkipMode>(),
310 getNumThreads(),
311 Parameters::Get<Parameters::EclOutputInterval>(),
312 Parameters::Get<Parameters::Slave>(),
316 setupTime_ = externalSetupTimer.elapsed();
317 }
318 catch (const std::invalid_argument& e)
319 {
320 if (outputCout_) {
321 std::cerr << "Failed to create valid EclipseState object." << std::endl;
322 std::cerr << "Exception caught: " << e.what() << std::endl;
323 }
324#if HAVE_MPI
326#endif
328 return false;
329 }
330
331#if HAVE_CUDA
332 Opm::gpuistl::printDevice();
333#endif
334
336 return true;
337 }
338
339 void setupVanguard();
340
341private:
342 // This function is an extreme special case, if the program has been invoked
343 // *exactly* as:
344 //
345 // flow --version
346 //
347 // the call is intercepted by this function which will print "flow $version"
348 // on stdout and exit(0).
349 void handleVersionCmdLine_(int argc, char** argv,
350 std::string_view moduleVersionName);
351
352 // This function is a special case, if the program has been invoked
353 // with the argument "--test-split-communicator=true" as the FIRST
354 // argument, it will be removed from the argument list and we set the
355 // test_split_comm_ flag to true.
356 // Note: initializing the parameter system before MPI could make this
357 // use the parameter system instead.
358 void handleTestSplitCommunicatorCmdLine_();
359
365 int dispatchDynamic_();
366
375 template <class TypeTag>
376 int dispatchStatic_()
377 {
378 this->setupVanguard();
379 return flowMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
380 }
381
390 int runMICP(const Phases& phases);
391
400 int runTwoPhase(const Phases& phases);
401
410 int runPolymer(const Phases& phases);
411
417 int runFoam();
418
427 int runWaterOnly(const Phases& phases);
428
437 int runWaterOnlyEnergy(const Phases& phases);
438
447 int runBrine(const Phases& phases);
448
457 int runSolvent(const Phases& phases);
458
464 int runExtendedBlackOil();
465
474 int runThermal(const Phases& phases);
475
481 int runBlackOil();
482
483 void readDeck(const std::string& deckFilename,
484 const std::string& outputDir,
485 const std::string& outputMode,
486 const bool init_from_restart_file,
487 const bool allRanksDbgPrtLog,
488 const std::string& parsingStrictness,
489 const std::string& actionParsingStrictness,
490 const std::string& inputSkipMode,
491 const bool keepKeywords,
492 const std::size_t numThreads,
493 const int output_param,
494 const bool slaveMode,
495 const std::string& parameters,
496 std::string_view moduleVersion,
497 std::string_view compileTimestamp);
498
499 static int getNumThreads()
500 {
501#ifdef _OPENMP
502 return omp_get_max_threads();
503#else
504 return 1;
505#endif
506 }
507
508#if HAVE_DAMARIS
509 void setupDamaris(const std::string& outputDir);
510#endif
511
512protected:
513 int argc_{0};
514 char** argv_{nullptr};
515 bool outputCout_{false};
516 bool outputFiles_{false};
517
518private:
519 bool ownMPI_{true};
520 double setupTime_{0.0};
521 std::string deckFilename_{};
522 std::string flowProgName_{};
523 char *saveArgs_[3]{nullptr};
524 std::unique_ptr<UDQState> udqState_{};
525 std::unique_ptr<Action::State> actionState_{};
526 std::unique_ptr<WellTestState> wtestState_{};
527
528 // These variables may be owned by both Python and the simulator
529 std::shared_ptr<EclipseState> eclipseState_{};
530 std::shared_ptr<Schedule> schedule_{};
531 std::shared_ptr<SummaryConfig> summaryConfig_{};
532 bool mpi_init_{true};
533 bool mpi_finalize_{true};
534
535 // To demonstrate run with non_world_comm
536 bool test_split_comm_ = false;
537 bool isSimulationRank_ = true;
538#if HAVE_MPI
540#endif
541#if HAVE_DAMARIS
542 bool enableDamarisOutput_ = false;
543#endif
544};
545
546} // namespace Opm
547
548#endif // OPM_MAIN_HEADER_INCLUDED
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
static Parallel::Communication & comm()
Obtain global communicator.
Definition FlowGenericVanguard.hpp:332
Definition FlowMain.hpp:67
Definition Main.hpp:103
int justInitialize()
Used for test_outputdir.
Definition Main.hpp:166
bool initialize_(int &exitCode, bool keepKeywords=false)
Initialize.
Definition Main.hpp:182
int runDynamic()
Run simulation.
Definition Main.hpp:132
int runStatic()
Run simulation.
Definition Main.hpp:153
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilboundaryratevector.hh:37
std::string moduleVersionName()
Return the version name of the module, for example "2015.10" (for a release branch) or "2016....
Definition moduleVersion.cpp:34
std::string compileTimestamp()
Return a string "dd-mm-yyyy at HH::MM::SS hrs" which is the time the binary was compiled.
Definition moduleVersion.cpp:57
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:242
std::string moduleVersion()
Return a string containing both the name and hash, if N is the name and H is the hash it will be "N (...
Definition moduleVersion.cpp:50
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:235
This file provides the infrastructure to retrieve run-time parameters.
The Opm property system, traits with inheritance.