From 7270aa30135993bbc70270570b436b714b26d9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atgeirr=20Fl=C3=B8=20Rasmussen?= Date: Thu, 10 Oct 2019 16:11:56 +0200 Subject: [PATCH] Update flow_tag.hpp to match current flow.cpp. The flow_tag.hpp file is used for simple construction of simulators for particular models or other compile-time choices. This updates it to get identical behaviour as that of mainline (multi-model) Flow. --- flow/flow_blackoil_dunecpr.cpp | 4 +- flow/flow_tag.hpp | 235 +++++++++++++++++++++++++++++---- 2 files changed, 213 insertions(+), 26 deletions(-) diff --git a/flow/flow_blackoil_dunecpr.cpp b/flow/flow_blackoil_dunecpr.cpp index f6f08f472..ffa90f28f 100644 --- a/flow/flow_blackoil_dunecpr.cpp +++ b/flow/flow_blackoil_dunecpr.cpp @@ -99,7 +99,5 @@ namespace Opm { int main(int argc, char** argv) { typedef TTAG(EclFlowProblemSimple) TypeTag; - bool outputCout = true; - bool outputFiles = true; - return mainFlow(argc, argv, outputCout, outputFiles); + return mainFlow(argc, argv); } diff --git a/flow/flow_tag.hpp b/flow/flow_tag.hpp index ccc2ea16d..a568eaad6 100644 --- a/flow/flow_tag.hpp +++ b/flow/flow_tag.hpp @@ -29,10 +29,15 @@ #include #include +#include +#include +#include + #include #include #include #include +#include //#include //#include @@ -118,13 +123,162 @@ namespace detail throw std::invalid_argument( "Cannot find input case " + casename ); } + + + // This function is an extreme special case, if the program has been invoked + // *exactly* as: + // + // flow --version + // + // the call is intercepted by this function which will print "flow $version" + // on stdout and exit(0). + void handleVersionCmdLine(int argc, char** argv) { + for ( int i = 1; i < argc; ++i ) + { + if (std::strcmp(argv[i], "--version") == 0) { + std::cout << "flow " << Opm::moduleVersionName() << std::endl; + std::exit(EXIT_SUCCESS); + } + } + } + +} + + + +enum class FileOutputMode { + //! \brief No output to files. + OUTPUT_NONE = 0, + //! \brief Output only to log files, no eclipse output. + OUTPUT_LOG_ONLY = 1, + //! \brief Output to all files. + OUTPUT_ALL = 3 +}; + + + +void ensureOutputDirExists(const std::string& cmdline_output_dir) +{ + if (!boost::filesystem::is_directory(cmdline_output_dir)) { + try { + boost::filesystem::create_directories(cmdline_output_dir); + } + catch (...) { + throw std::runtime_error("Creation of output directory '" + cmdline_output_dir + "' failed\n"); + } + } +} + + +// Setup the OpmLog backends +FileOutputMode setupLogging(int mpi_rank_, const std::string& deck_filename, const std::string& cmdline_output_dir, const std::string& cmdline_output, bool output_cout_, const std::string& stdout_log_id) { + + if (!cmdline_output_dir.empty()) { + ensureOutputDirExists(cmdline_output_dir); + } + + // create logFile + using boost::filesystem::path; + path fpath(deck_filename); + std::string baseName; + std::ostringstream debugFileStream; + std::ostringstream logFileStream; + + // Strip extension "." or ".DATA" + std::string extension = boost::to_upper_copy(fpath.extension().string()); + if (extension == ".DATA" || extension == ".") { + baseName = boost::to_upper_copy(fpath.stem().string()); + } else { + baseName = boost::to_upper_copy(fpath.filename().string()); + } + + std::string output_dir = cmdline_output_dir; + if (output_dir.empty()) { + output_dir = absolute(path(baseName).parent_path()).string(); + } + + logFileStream << output_dir << "/" << baseName; + debugFileStream << output_dir << "/" << baseName; + + if (mpi_rank_ != 0) { + // Added rank to log file for non-zero ranks. + // This prevents message loss. + debugFileStream << "." << mpi_rank_; + // If the following file appears then there is a bug. + logFileStream << "." << mpi_rank_; + } + logFileStream << ".PRT"; + debugFileStream << ".DBG"; + + FileOutputMode output; + { + static std::map stringToOutputMode = + { {"none", FileOutputMode::OUTPUT_NONE }, + {"false", FileOutputMode::OUTPUT_LOG_ONLY }, + {"log", FileOutputMode::OUTPUT_LOG_ONLY }, + {"all" , FileOutputMode::OUTPUT_ALL }, + {"true" , FileOutputMode::OUTPUT_ALL }}; + auto outputModeIt = stringToOutputMode.find(cmdline_output); + if (outputModeIt != stringToOutputMode.end()) { + output = outputModeIt->second; + } + else { + output = FileOutputMode::OUTPUT_ALL; + std::cerr << "Value " << cmdline_output << + " is not a recognized output mode. Using \"all\" instead." + << std::endl; + } + } + + if (output > FileOutputMode::OUTPUT_NONE) { + std::shared_ptr prtLog = std::make_shared(logFileStream.str(), Opm::Log::NoDebugMessageTypes, false, output_cout_); + Opm::OpmLog::addBackend("ECLIPSEPRTLOG", prtLog); + prtLog->setMessageLimiter(std::make_shared()); + prtLog->setMessageFormatter(std::make_shared(false)); + } + + if (output >= FileOutputMode::OUTPUT_LOG_ONLY) { + std::string debugFile = debugFileStream.str(); + std::shared_ptr debugLog = std::make_shared(debugFileStream.str(), Opm::Log::DefaultMessageTypes, false, output_cout_); + Opm::OpmLog::addBackend("DEBUGLOG", debugLog); + } + + std::shared_ptr streamLog = std::make_shared(std::cout, Opm::Log::StdoutMessageTypes); + Opm::OpmLog::addBackend(stdout_log_id, streamLog); + streamLog->setMessageFormatter(std::make_shared(true)); + + return output; +} + + + +void setupMessageLimiter(const Opm::MessageLimits msgLimits, const std::string& stdout_log_id) { + std::shared_ptr stream_log = Opm::OpmLog::getBackend(stdout_log_id); + + const std::map limits = {{Opm::Log::MessageType::Note, + msgLimits.getCommentPrintLimit(0)}, + {Opm::Log::MessageType::Info, + msgLimits.getMessagePrintLimit(0)}, + {Opm::Log::MessageType::Warning, + msgLimits.getWarningPrintLimit(0)}, + {Opm::Log::MessageType::Error, + msgLimits.getErrorPrintLimit(0)}, + {Opm::Log::MessageType::Problem, + msgLimits.getProblemPrintLimit(0)}, + {Opm::Log::MessageType::Bug, + msgLimits.getBugPrintLimit(0)}}; + stream_log->setMessageLimiter(std::make_shared(10, limits)); } // ----------------- Main program ----------------- template -int mainFlow(int argc, char** argv, bool outputCout, bool outputFiles) +int mainFlow(int argc, char** argv) { + Dune::Timer externalSetupTimer; + externalSetupTimer.start(); + + detail::handleVersionCmdLine(argc, argv); // MPI setup. #if HAVE_DUNE_FEM Dune::Fem::MPIManager::initialize(argc, argv); @@ -151,15 +305,21 @@ int mainFlow(int argc, char** argv, bool outputCout, bool outputFiles) typedef TTAG(FlowEarlyBird) PreTypeTag; typedef GET_PROP_TYPE(PreTypeTag, Problem) PreProblem; - PreProblem::setBriefDescription("Simple Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project."); + PreProblem::setBriefDescription("Flow, an advanced reservoir simulator for ECL-decks provided by the Open Porous Media project."); int status = Opm::FlowMainEbos::setupParameters_(argc, argv); - if (status != 0) + if (status != 0) { // if setupParameters_ returns a value smaller than 0, there was no error, but // the program should abort. This is the case e.g. for the --help and the // --print-properties parameters. +#if HAVE_MPI + MPI_Finalize(); +#endif return (status >= 0)?status:0; + } + FileOutputMode outputMode = FileOutputMode::OUTPUT_NONE; + bool outputCout = false; if (mpiRank == 0) outputCout = EWOMS_GET_PARAM(PreTypeTag, bool, EnableTerminalOutput); @@ -176,28 +336,57 @@ int mainFlow(int argc, char** argv, bool outputCout, bool outputFiles) // Create Deck and EclipseState. try { - Opm::Parser parser; - typedef std::pair ParseModePair; - typedef std::vector ParseModePairs; - ParseModePairs tmp; - tmp.push_back(ParseModePair(Opm::ParseContext::PARSE_RANDOM_SLASH, Opm::InputError::IGNORE)); - tmp.push_back(ParseModePair(Opm::ParseContext::PARSE_MISSING_DIMS_KEYWORD, Opm::InputError::WARN)); - tmp.push_back(ParseModePair(Opm::ParseContext::SUMMARY_UNKNOWN_WELL, Opm::InputError::WARN)); - tmp.push_back(ParseModePair(Opm::ParseContext::SUMMARY_UNKNOWN_GROUP, Opm::InputError::WARN)); - Opm::ParseContext parseContext(tmp); - Opm::ErrorGuard errorGuard; + if (outputCout) { + std::cout << "Reading deck file '" << deckFilename << "'\n"; + std::cout.flush(); + } + std::shared_ptr deck; + std::shared_ptr eclipseState; + std::shared_ptr schedule; + std::shared_ptr summaryConfig; + { + Opm::Parser parser; + Opm::ParseContext parseContext; + Opm::ErrorGuard errorGuard; + outputMode = setupLogging(mpiRank, + deckFilename, + EWOMS_GET_PARAM(PreTypeTag, std::string, OutputDir), + EWOMS_GET_PARAM(PreTypeTag, std::string, OutputMode), + outputCout, "STDOUT_LOGGER"); - std::shared_ptr deck = std::make_shared< Opm::Deck >( parser.parseFile(deckFilename , parseContext, errorGuard) ); - if ( outputCout ) { - Opm::checkDeck(*deck, parser, parseContext, errorGuard); - Opm::MissingFeatures::checkKeywords(*deck); - } - //Opm::Runspec runspec( *deck ); - //const auto& phases = runspec.phases(); + if (EWOMS_GET_PARAM(PreTypeTag, bool, EclStrictParsing)) + parseContext.update( Opm::InputError::DELAYED_EXIT1); + else { + parseContext.update(Opm::ParseContext::PARSE_RANDOM_SLASH, Opm::InputError::IGNORE); + parseContext.update(Opm::ParseContext::PARSE_MISSING_DIMS_KEYWORD, Opm::InputError::WARN); + parseContext.update(Opm::ParseContext::SUMMARY_UNKNOWN_WELL, Opm::InputError::WARN); + parseContext.update(Opm::ParseContext::SUMMARY_UNKNOWN_GROUP, Opm::InputError::WARN); + } - std::shared_ptr eclipseState = std::make_shared< Opm::EclipseState > ( *deck, parseContext, errorGuard ); - Opm::flowEbosSetDeck(*deck, *eclipseState); - return Opm::flowEbosMain(argc, argv, outputCout, outputFiles); + Opm::FlowMainEbos::printPRTHeader(outputCout); + + deck.reset( new Opm::Deck( parser.parseFile(deckFilename , parseContext, errorGuard))); + Opm::MissingFeatures::checkKeywords(*deck, parseContext, errorGuard); + if ( outputCout ) + Opm::checkDeck(*deck, parser, parseContext, errorGuard); + + eclipseState.reset( new Opm::EclipseState(*deck, parseContext, errorGuard )); + schedule.reset(new Opm::Schedule(*deck, *eclipseState, parseContext, errorGuard)); + summaryConfig.reset( new Opm::SummaryConfig(*deck, *schedule, eclipseState->getTableManager(), parseContext, errorGuard)); + setupMessageLimiter(schedule->getMessageLimits(), "STDOUT_LOGGER"); + + Opm::checkConsistentArrayDimensions(*eclipseState, *schedule, parseContext, errorGuard); + + if (errorGuard) { + errorGuard.dump(); + errorGuard.clear(); + + throw std::runtime_error("Unrecoverable errors were encountered while loading input."); + } + } + bool outputFiles = (outputMode != FileOutputMode::OUTPUT_NONE); + Opm::flowEbosSetDeck(*deck, *eclipseState); + return Opm::flowEbosMain(argc, argv, outputCout, outputFiles); } catch (const std::invalid_argument& e) {