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 <flow/flow_ebos_blackoil.hpp>
27#include <flow/flow_ebos_blackoil_legacyassembly.hpp>
28
29#include <flow/flow_ebos_gasoil.hpp>
30#include <flow/flow_ebos_gasoildiffuse.hpp>
31#include <flow/flow_ebos_gasoil_energy.hpp>
32#include <flow/flow_ebos_oilwater.hpp>
33#include <flow/flow_ebos_gaswater.hpp>
34#include <flow/flow_ebos_gaswater_solvent.hpp>
35#include <flow/flow_ebos_solvent.hpp>
36#include <flow/flow_ebos_solvent_foam.hpp>
37#include <flow/flow_ebos_polymer.hpp>
38#include <flow/flow_ebos_extbo.hpp>
39#include <flow/flow_ebos_foam.hpp>
40#include <flow/flow_ebos_brine.hpp>
41#include <flow/flow_ebos_brine_saltprecipitation.hpp>
42#include <flow/flow_ebos_gaswater_saltprec_vapwat.hpp>
43#include <flow/flow_ebos_gaswater_saltprec_energy.hpp>
44#include <flow/flow_ebos_brine_precsalt_vapwat.hpp>
45#include <flow/flow_ebos_onephase.hpp>
46#include <flow/flow_ebos_onephase_energy.hpp>
47#include <flow/flow_ebos_oilwater_brine.hpp>
48#include <flow/flow_ebos_gaswater_brine.hpp>
49#include <flow/flow_ebos_gaswater_energy.hpp>
50#include <flow/flow_ebos_gaswater_dissolution.hpp>
51#include <flow/flow_ebos_gaswater_dissolution_diffuse.hpp>
52#include <flow/flow_ebos_energy.hpp>
53#include <flow/flow_ebos_oilwater_polymer.hpp>
54#include <flow/flow_ebos_oilwater_polymer_injectivity.hpp>
55#include <flow/flow_ebos_micp.hpp>
56
57#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
58
59#include <opm/models/utils/propertysystem.hh>
60#include <opm/models/utils/parametersystem.hh>
61
62#include <opm/simulators/flow/Banners.hpp>
63#include <opm/simulators/flow/FlowMainEbos.hpp>
64
65#if HAVE_DUNE_FEM
66#include <dune/fem/misc/mpimanager.hh>
67#else
68#include <dune/common/parallel/mpihelper.hh>
69#endif
70
71#if HAVE_MPI
72#include <opm/simulators/utils/ParallelEclipseState.hpp>
73#endif
74
75#include <cassert>
76#include <cstdlib>
77#include <iostream>
78#include <memory>
79#include <stdexcept>
80#include <string>
81#include <string_view>
82#include <type_traits>
83#include <utility>
84
85namespace Opm::Properties {
86
87// this is a dummy type tag that is used to setup the parameters before the actual
88// simulator.
89namespace TTag {
91 using InheritsFrom = std::tuple<EclFlowProblem>;
92};
93}
94
95} // namespace Opm::Properties
96
97namespace Opm {
98
99namespace Action { class State; }
100class UDQState;
101class WellTestState;
102
103// ----------------- Main program -----------------
104template <class TypeTag>
105int flowEbosMain(int argc, char** argv, bool outputCout, bool outputFiles)
106{
107 // we always want to use the default locale, and thus spare us the trouble
108 // with incorrect locale settings.
109 resetLocale();
110
111 FlowMainEbos<TypeTag> mainfunc(argc, argv, outputCout, outputFiles);
112 return mainfunc.execute();
113}
114
115// ----------------- Main class -----------------
116// For now, we will either be instantiated from main() in flow.cpp,
117// or from a Python pybind11 module..
118// NOTE (March 2020): When used from a pybind11 module, we do not neccessarily
119// want to run the whole simulation by calling run(), it is also
120// useful to just run one report step at a time. According to these different
121// usage scenarios, we refactored the original run() in flow.cpp into this class.
122class Main
123{
124public:
125 Main(int argc, char** argv);
126
127 // This constructor can be called from Python
128 Main(const std::string& filename);
129
130 // This constructor can be called from Python when Python has
131 // already parsed a deck
132 Main(const std::string& filename,
133 std::shared_ptr<EclipseState> eclipseState,
134 std::shared_ptr<Schedule> schedule,
135 std::shared_ptr<SummaryConfig> summaryConfig);
136
137 ~Main();
138
139 void setArgvArgc_(const std::string& filename);
140
141 void initMPI();
142
143 int runDynamic()
144 {
147 if (isSimulationRank_) {
148 return this->dispatchDynamic_();
149 }
150 }
151
152 return exitCode;
153 }
154
155 template <class TypeTag>
156 int runStatic()
157 {
160 if (isSimulationRank_) {
161 return this->dispatchStatic_<TypeTag>();
162 }
163 }
164
165 return exitCode;
166 }
167
169 // To be called from the Python interface code. Only do the
170 // initialization and then return a pointer to the FlowEbosMain
171 // object that can later be accessed directly from the Python interface
172 // to e.g. advance the simulator one report step
173 std::unique_ptr<FlowMainEbosType> initFlowEbosBlackoil(int& exitCode)
174 {
177 // TODO: check that this deck really represents a blackoil
178 // case. E.g. check that number of phases == 3
179 this->setupVanguard();
181 argc_, argv_, outputCout_, outputFiles_);
182 } else {
183 //NOTE: exitCode was set by initialize_() above;
184 return std::unique_ptr<FlowMainEbosType>(); // nullptr
185 }
186 }
187
188private:
189 int dispatchDynamic_()
190 {
191 const auto& rspec = this->eclipseState_->runspec();
192 const auto& phases = rspec.phases();
193
194 this->setupVanguard();
195
196 // run the actual simulator
197 //
198 // TODO: make sure that no illegal combinations like thermal and
199 // twophase are requested.
200 const bool thermal = eclipseState_->getSimulationConfig().isThermal();
201
202 // Single-phase case
203 if (rspec.micp()) {
204 return this->runMICP(phases);
205 }
206
207 // water-only case
208 else if (phases.size() == 1 && phases.active(Phase::WATER) && !thermal) {
209 return this->runWaterOnly(phases);
210 }
211
212 // water-only case with energy
213 else if (phases.size() == 2 && phases.active(Phase::WATER) && thermal) {
214 return this->runWaterOnlyEnergy(phases);
215 }
216
217 // Twophase cases
218 else if (phases.size() == 2 && !thermal) {
219 return this->runTwoPhase(phases);
220 }
221
222 // Polymer case
223 else if (phases.active(Phase::POLYMER)) {
224 return this->runPolymer(phases);
225 }
226
227 // Foam case
228 else if (phases.active(Phase::FOAM) && !phases.active(Phase::SOLVENT)) {
229 return this->runFoam();
230 }
231
232 // Solvent case
233 else if (phases.active(Phase::SOLVENT)) {
234 return this->runSolvent(phases);
235 }
236
237 // Brine case
238 else if (phases.active(Phase::BRINE) && !thermal) {
239 return this->runBrine(phases);
240 }
241
242 // Extended BO case
243 else if (phases.active(Phase::ZFRACTION)) {
244 return this->runExtendedBlackOil();
245 }
246
247 // Energy case
248 else if (thermal) {
249 return this->runThermal(phases);
250 }
251
252 // Blackoil case
253 else if (phases.size() == 3) {
254 return this->runBlackOil();
255 }
256
257 else {
258 if (outputCout_) {
259 std::cerr << "No suitable configuration found, valid are "
260 << "Twophase, polymer, foam, brine, solvent, "
261 << "energy, and blackoil.\n";
262 }
263
264 return EXIT_FAILURE;
265 }
266 }
267
268 template <class TypeTag>
269 int dispatchStatic_()
270 {
271 this->setupVanguard();
272 return flowEbosMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
273 }
274
281 template <class TypeTagEarlyBird>
282 bool initialize_(int& exitCode)
283 {
284 Dune::Timer externalSetupTimer;
285 externalSetupTimer.start();
286
287 handleVersionCmdLine_(argc_, argv_, Opm::moduleVersionName());
288
289 // we always want to use the default locale, and thus spare us the trouble
290 // with incorrect locale settings.
291 resetLocale();
292
293 // this is a work-around for a catch 22: we do not know what code path to use without
294 // parsing the deck, but we don't know the deck without having access to the
295 // parameters and this requires to know the type tag to be used. To solve this, we
296 // use a type tag just for parsing the parameters before we instantiate the actual
297 // simulator object. (Which parses the parameters again, but since this is done in an
298 // identical manner it does not matter.)
301
302 PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project.");
303 int status = FlowMainEbos<PreTypeTag>::setupParameters_(argc_, argv_, EclGenericVanguard::comm());
304 if (status != 0) {
305 // if setupParameters_ returns a value smaller than 0, there was no error, but
306 // the program should abort. This is the case e.g. for the --help and the
307 // --print-properties parameters.
308#if HAVE_MPI
309 if (status >= 0)
310 MPI_Abort(MPI_COMM_WORLD, status);
311#endif
312 exitCode = (status > 0) ? status : EXIT_SUCCESS;
313 return false; // Whether to run the simulator
314 }
315
316 std::string deckFilename;
317 std::string outputDir;
318 if ( eclipseState_ ) {
319 deckFilename = eclipseState_->getIOConfig().fullBasePath();
320 outputDir = eclipseState_->getIOConfig().getOutputDir();
321 }
322 else {
323 deckFilename = EWOMS_GET_PARAM(PreTypeTag, std::string, EclDeckFileName);
325 }
326
327#if HAVE_DAMARIS
329 // Reset to false as we cannot use Damaris if there is only one rank.
330 if ((enableDamarisOutput_ == true) && (EclGenericVanguard::comm().size() == 1)) {
331 std::string msg ;
332 msg = "\nUse of Damaris (command line argument --enable-damaris-output=true) has been disabled for run with only one rank.\n" ;
333 OpmLog::warning(msg);
335 }
336
340 }
341#endif // HAVE_DAMARIS
342
343 // Guard for when the Damaris core(s) return from damaris_start()
344 // which happens when damaris_stop() is called in main simulation
345 if (!isSimulationRank_) {
347 return true;
348 }
349
350 int mpiRank = EclGenericVanguard::comm().rank();
351 outputCout_ = false;
352 if (mpiRank == 0)
353 outputCout_ = EWOMS_GET_PARAM(PreTypeTag, bool, EnableTerminalOutput);
354
355 if (deckFilename.empty()) {
356 if (mpiRank == 0) {
357 std::cerr << "No input case given. Try '--help' for a usage description.\n";
358 }
360 return false;
361 }
362
364 try {
365 deckFilename = PreVanguard::canonicalDeckPath(deckFilename);
366 }
367 catch (const std::exception& e) {
368 if ( mpiRank == 0 ) {
369 std::cerr << "Exception received: " << e.what() << ". Try '--help' for a usage description.\n";
370 }
371#if HAVE_MPI
373#endif
375 return false;
376 }
377
378 std::string cmdline_params;
379 if (outputCout_) {
380 printFlowBanner(EclGenericVanguard::comm().size(),
383 std::ostringstream str;
384 Parameters::printValues<PreTypeTag>(str);
385 cmdline_params = str.str();
386 }
387
388 // Create Deck and EclipseState.
389 try {
390 this->readDeck(deckFilename,
391 outputDir,
394 EWOMS_GET_PARAM(PreTypeTag, bool, EnableLoggingFalloutWarning),
396 mpiRank,
401 setupTime_ = externalSetupTimer.elapsed();
402 }
403 catch (const std::invalid_argument& e)
404 {
405 if (outputCout_) {
406 std::cerr << "Failed to create valid EclipseState object." << std::endl;
407 std::cerr << "Exception caught: " << e.what() << std::endl;
408 }
409#if HAVE_MPI
411#endif
413 return false;
414 }
415
417 return true;
418 }
419
420 // This function is an extreme special case, if the program has been invoked
421 // *exactly* as:
422 //
423 // flow --version
424 //
425 // the call is intercepted by this function which will print "flow $version"
426 // on stdout and exit(0).
427 void handleVersionCmdLine_(int argc, char** argv,
428 std::string_view moduleVersionName);
429
430 // This function is a special case, if the program has been invoked
431 // with the argument "--test-split-communicator=true" as the FIRST
432 // argument, it will be removed from the argument list and we set the
433 // test_split_comm_ flag to true.
434 // Note: initializing the parameter system before MPI could make this
435 // use the parameter system instead.
436 void handleTestSplitCommunicatorCmdLine_();
437
438 int runMICP(const Phases& phases)
439 {
440 if (!phases.active(Phase::WATER) || (phases.size() > 2)) {
441 if (outputCout_) {
442 std::cerr << "No valid configuration is found for MICP simulation, "
443 << "the only valid option is water + MICP\n";
444 }
445
446 return EXIT_FAILURE;
447 }
448
449 return flowEbosMICPMain(this->argc_,
450 this->argv_,
451 this->outputCout_,
452 this->outputFiles_);
453 }
454
455 int runTwoPhase(const Phases& phases)
456 {
457 const bool diffusive = eclipseState_->getSimulationConfig().isDiffusive();
458 const bool disgasw = eclipseState_->getSimulationConfig().hasDISGASW();
459 const bool vapwat = eclipseState_->getSimulationConfig().hasVAPWAT();
460
461 // oil-gas
462 if (phases.active( Phase::OIL ) && phases.active( Phase::GAS )) {
463 if (diffusive) {
464 return flowEbosGasOilDiffuseMain(argc_, argv_, outputCout_, outputFiles_);
465 } else {
466 return flowEbosGasOilMain(argc_, argv_, outputCout_, outputFiles_);
467 }
468 }
469
470 // oil-water
471 else if ( phases.active( Phase::OIL ) && phases.active( Phase::WATER ) ) {
472 if (diffusive) {
473 if (outputCout_) {
474 std::cerr << "The DIFFUSE option is not available for the two-phase water/oil model." << std::endl;
475 }
476 return EXIT_FAILURE;
477 }
478 return flowEbosOilWaterMain(argc_, argv_, outputCout_, outputFiles_);
479 }
480
481 // gas-water
482 else if ( phases.active( Phase::GAS ) && phases.active( Phase::WATER ) ) {
483 if (disgasw || vapwat) {
484 if (diffusive) {
485 return flowEbosGasWaterDissolutionDiffuseMain(argc_, argv_, outputCout_, outputFiles_);
486 }
487 return flowEbosGasWaterDissolutionMain(argc_, argv_, outputCout_, outputFiles_);
488 }
489 if (diffusive) {
490 if (outputCout_) {
491 std::cerr << "The DIFFUSE option is not available for the two-phase gas/water model without disgasw or vapwat." << std::endl;
492 }
493 return EXIT_FAILURE;
494 }
495
496 return flowEbosGasWaterMain(argc_, argv_, outputCout_, outputFiles_);
497 }
498 else {
499 if (outputCout_) {
500 std::cerr << "No suitable configuration found, valid are Twophase (oilwater, oilgas and gaswater), polymer, solvent, or blackoil" << std::endl;
501 }
502
503 return EXIT_FAILURE;
504 }
505 }
506
507 int runPolymer(const Phases& phases)
508 {
509 if (! phases.active(Phase::WATER)) {
510 if (outputCout_)
511 std::cerr << "No valid configuration is found for polymer simulation, valid options include "
512 << "oilwater + polymer and blackoil + polymer" << std::endl;
513
514 return EXIT_FAILURE;
515 }
516
517 // Need to track the polymer molecular weight
518 // for the injectivity study
519 if (phases.active(Phase::POLYMW)) {
520 // only oil water two phase for now
521 assert (phases.size() == 4);
522 return flowEbosOilWaterPolymerInjectivityMain(argc_, argv_, outputCout_, outputFiles_);
523 }
524
525 if (phases.size() == 3) { // oil water polymer case
526 return flowEbosOilWaterPolymerMain(argc_, argv_, outputCout_, outputFiles_);
527 }
528 else {
529 return flowEbosPolymerMain(argc_, argv_, outputCout_, outputFiles_);
530 }
531 }
532
533 int runFoam()
534 {
535 return flowEbosFoamMain(argc_, argv_, outputCout_, outputFiles_);
536 }
537
538 int runWaterOnly(const Phases& phases)
539 {
540 if (!phases.active(Phase::WATER) || phases.size() != 1) {
541 if (outputCout_)
542 std::cerr << "No valid configuration is found for water-only simulation, valid options include "
543 << "water, water + thermal" << std::endl;
544
545 return EXIT_FAILURE;
546 }
547
548 return flowEbosWaterOnlyMain(argc_, argv_, outputCout_, outputFiles_);
549 }
550
551 int runWaterOnlyEnergy(const Phases& phases)
552 {
553 if (!phases.active(Phase::WATER) || phases.size() != 2) {
554 if (outputCout_)
555 std::cerr << "No valid configuration is found for water-only simulation, valid options include "
556 << "water, water + thermal" << std::endl;
557
558 return EXIT_FAILURE;
559 }
560
561 return flowEbosWaterOnlyEnergyMain(argc_, argv_, outputCout_, outputFiles_);
562 }
563
564 int runBrine(const Phases& phases)
565 {
566 if (! phases.active(Phase::WATER) || phases.size() == 2) {
567 if (outputCout_)
568 std::cerr << "No valid configuration is found for brine simulation, valid options include "
569 << "oilwater + brine, gaswater + brine and blackoil + brine" << std::endl;
570
571 return EXIT_FAILURE;
572 }
573
574 if (phases.size() == 3) {
575
576 if (phases.active(Phase::OIL)){ // oil water brine case
577 return flowEbosOilWaterBrineMain(argc_, argv_, outputCout_, outputFiles_);
578 }
579 if (phases.active(Phase::GAS)){ // gas water brine case
580 if (eclipseState_->getSimulationConfig().hasPRECSALT() &&
581 eclipseState_->getSimulationConfig().hasVAPWAT()) {
582 //case with water vaporization into gas phase and salt precipitation
583 return flowEbosGasWaterSaltprecVapwatMain(argc_, argv_, outputCout_, outputFiles_);
584 }
585 else {
586 return flowEbosGasWaterBrineMain(argc_, argv_, outputCout_, outputFiles_);
587 }
588 }
589 }
590 else if (eclipseState_->getSimulationConfig().hasPRECSALT()) {
591 if (eclipseState_->getSimulationConfig().hasVAPWAT()) {
592 //case with water vaporization into gas phase and salt precipitation
593 return flowEbosBrinePrecsaltVapwatMain(argc_, argv_, outputCout_, outputFiles_);
594 }
595 else {
596 return flowEbosBrineSaltPrecipitationMain(argc_, argv_, outputCout_, outputFiles_);
597 }
598 }
599 else {
600 return flowEbosBrineMain(argc_, argv_, outputCout_, outputFiles_);
601 }
602
603 return EXIT_FAILURE;
604 }
605
606 int runSolvent(const Phases& phases)
607 {
608 if (phases.active(Phase::FOAM)) {
609 return flowEbosSolventFoamMain(argc_, argv_, outputCout_, outputFiles_);
610 }
611 // solvent + gas + water
612 if (!phases.active( Phase::OIL ) && phases.active( Phase::WATER ) && phases.active( Phase::GAS )) {
613 return flowEbosGasWaterSolventMain(argc_, argv_, outputCout_, outputFiles_);
614 }
615
616 // solvent + gas + water + oil
617 if (phases.active( Phase::OIL ) && phases.active( Phase::WATER ) && phases.active( Phase::GAS )) {
618 return flowEbosSolventMain(argc_, argv_, outputCout_, outputFiles_);
619 }
620
621 if (outputCout_)
622 std::cerr << "No valid configuration is found for solvent simulation, valid options include "
623 << "gas + water + solvent and gas + oil + water + solvent" << std::endl;
624
625 return EXIT_FAILURE;
626 }
627
628 int runExtendedBlackOil()
629 {
630 return flowEbosExtboMain(argc_, argv_, outputCout_, outputFiles_);
631 }
632
633 int runThermal(const Phases& phases)
634 {
635 // oil-gas-thermal
636 if (!phases.active( Phase::WATER ) && phases.active( Phase::OIL ) && phases.active( Phase::GAS )) {
637 return flowEbosGasOilEnergyMain(argc_, argv_, outputCout_, outputFiles_);
638 }
639
640 // water-gas-thermal
641 if (!phases.active( Phase::OIL ) && phases.active( Phase::WATER ) && phases.active( Phase::GAS )) {
642
643 if (phases.active(Phase::BRINE)){
644 return flowEbosGasWaterSaltprecEnergyMain(argc_, argv_, outputCout_, outputFiles_);
645 }
646 return flowEbosGasWaterEnergyMain(argc_, argv_, outputCout_, outputFiles_);
647 }
648
649 return flowEbosEnergyMain(argc_, argv_, outputCout_, outputFiles_);
650 }
651
652 int runBlackOil()
653 {
654 const bool diffusive = eclipseState_->getSimulationConfig().isDiffusive();
655 if (diffusive) {
656 // Use the traditional linearizer, as the TpfaLinearizer does not
657 // support the diffusion module yet.
658 return flowEbosBlackoilMain(argc_, argv_, outputCout_, outputFiles_);
659 } else {
660 return flowEbosBlackoilTpfaMain(argc_, argv_, outputCout_, outputFiles_);
661 }
662 }
663
664 void readDeck(const std::string& deckFilename,
665 const std::string& outputDir,
666 const std::string& outputMode,
667 const bool init_from_restart_file,
668 const bool allRanksDbgPrtLog,
669 const std::string& parsingStrictness,
670 const int mpiRank,
671 const int output_param,
672 const std::string& parameters,
673 std::string_view moduleVersion,
674 std::string_view compileTimestamp);
675
676 void setupVanguard();
677
678 template<class TypeTag>
679 static int getNumThreads()
680 {
681
682 int threads;
683
684#ifdef _OPENMP
685 // This function is called before the parallel OpenMP stuff gets initialized.
686 // That initialization happends after the deck is read and we want this message.
687 // Hence we duplicate the code of setupParallelism to get the number of threads.
688 if (std::getenv("OMP_NUM_THREADS")) {
690 }
691 else {
692 threads = 2;
693
694 const int input_threads = EWOMS_GET_PARAM(TypeTag, int, ThreadsPerProcess);
695
696 if (input_threads > 0)
698 }
699#else
700 threads = 1;
701#endif
702
703 return threads;
704 }
705
706#if HAVE_DAMARIS
707 void setupDamaris(const std::string& outputDir,
709#endif
710
711 int argc_{0};
712 char** argv_{nullptr};
713 bool outputCout_{false};
714 bool outputFiles_{false};
715 double setupTime_{0.0};
716 std::string deckFilename_{};
717 std::string flowProgName_{};
718 char *saveArgs_[3]{nullptr};
719 std::unique_ptr<UDQState> udqState_{};
720 std::unique_ptr<Action::State> actionState_{};
721 std::unique_ptr<WellTestState> wtestState_{};
722
723 // These variables may be owned by both Python and the simulator
724 std::shared_ptr<EclipseState> eclipseState_{};
725 std::shared_ptr<Schedule> schedule_{};
726 std::shared_ptr<SummaryConfig> summaryConfig_{};
727
728 // To demonstrate run with non_world_comm
729 bool test_split_comm_ = false;
730 bool isSimulationRank_ = true;
731#if HAVE_DAMARIS
732 bool enableDamarisOutput_ = false;
733#endif
734};
735
736} // namespace Opm
737
738#endif // OPM_MAIN_HEADER_INCLUDED
Definition AquiferInterface.hpp:35
Definition FlowMainEbos.hpp:98
Definition Main.hpp:123
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
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
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