/* Copyright 2013, 2014, 2015 SINTEF ICT, Applied Mathematics. Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services Copyright 2015 IRIS AS Copyright 2014 STATOIL ASA. This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #include "config.h" #if HAVE_MPI #include "mpi.h" #endif #include "readDeck.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "UnsupportedFlowKeywords.hpp" #include "PartiallySupportedFlowKeywords.hpp" #include #include #include #include #include namespace Opm { void ensureOutputDirExists_(const std::string& cmdline_output_dir) { if (!Opm::filesystem::is_directory(cmdline_output_dir)) { try { Opm::filesystem::create_directories(cmdline_output_dir); } catch (...) { throw std::runtime_error(fmt::format("Creation of output directory '{}' failed\n", cmdline_output_dir)); } } } // 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 Opm::filesystem::path; path fpath(deck_filename); std::string baseName; std::ostringstream debugFileStream; std::ostringstream logFileStream; // Strip extension "." or ".DATA" std::string extension = uppercase(fpath.extension().string()); if (extension == ".DATA" || extension == ".") { baseName = uppercase(fpath.stem().string()); } else { baseName = uppercase(fpath.filename().string()); } std::string output_dir = cmdline_output_dir; if (output_dir.empty()) { output_dir = fpath.has_parent_path() ? absolute(fpath.parent_path()).generic_string() : Opm::filesystem::current_path().generic_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); } if (mpi_rank_ == 0) { 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; } namespace { 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()}, {Opm::Log::MessageType::Info, msgLimits.getMessagePrintLimit()}, {Opm::Log::MessageType::Warning, msgLimits.getWarningPrintLimit()}, {Opm::Log::MessageType::Error, msgLimits.getErrorPrintLimit()}, {Opm::Log::MessageType::Problem, msgLimits.getProblemPrintLimit()}, {Opm::Log::MessageType::Bug, msgLimits.getBugPrintLimit()}}; stream_log->setMessageLimiter(std::make_shared(10, limits)); } } void readDeck(int rank, std::string& deckFilename, std::unique_ptr& deck, std::unique_ptr& eclipseState, std::unique_ptr& schedule, std::unique_ptr& summaryConfig, std::unique_ptr errorGuard, std::shared_ptr& python, std::unique_ptr parseContext, bool initFromRestart, bool checkDeck, const std::optional& outputInterval) { if (!errorGuard) { errorGuard = std::make_unique(); } int parseSuccess = 1; // > 0 is success std::string failureMessage; if (rank==0) { try { if ( (!deck || !schedule || !summaryConfig ) && !parseContext) { OPM_THROW(std::logic_error, "We need a parse context if deck, schedule, or summaryConfig are not initialized"); } if (!deck) { Opm::Parser parser; deck = std::make_unique( parser.parseFile(deckFilename , *parseContext, *errorGuard)); Opm::KeywordValidation::KeywordValidator keyword_validator( Opm::FlowKeywordValidation::unsupportedKeywords(), Opm::FlowKeywordValidation::partially_supported_keywords_strings, Opm::FlowKeywordValidation::partially_supported_keywords_int); keyword_validator.validateDeck(*deck, *parseContext, *errorGuard); if ( checkDeck ) Opm::checkDeck(*deck, parser, *parseContext, *errorGuard); } if (!eclipseState) { #if HAVE_MPI eclipseState = std::make_unique(*deck); #else eclipseState = std::make_unique(*deck); #endif } /* For the time being initializing wells and groups from the restart file is not possible, but work is underways and it is included here as a switch. */ const auto& init_config = eclipseState->getInitConfig(); if (init_config.restartRequested() && initFromRestart) { int report_step = init_config.getRestartStep(); const auto& rst_filename = eclipseState->getIOConfig().getRestartFileName( init_config.getRestartRootName(), report_step, false ); Opm::EclIO::ERst rst_file(rst_filename); const auto& rst_state = Opm::RestartIO::RstState::load(rst_file, report_step); if (!schedule) schedule = std::make_unique(*deck, *eclipseState, *parseContext, *errorGuard, python, outputInterval, &rst_state); } else { if (!schedule) schedule = std::make_unique(*deck, *eclipseState, *parseContext, *errorGuard, python); } if (Opm::OpmLog::hasBackend("STDOUT_LOGGER")) // loggers might not be set up! { setupMessageLimiter(schedule->operator[](0).message_limits(), "STDOUT_LOGGER"); } if (!summaryConfig) summaryConfig = std::make_unique(*deck, *schedule, eclipseState->fieldProps(), eclipseState->aquifer(), *parseContext, *errorGuard); Opm::checkConsistentArrayDimensions(*eclipseState, *schedule, *parseContext, *errorGuard); } catch(const OpmInputError& input_error) { failureMessage = input_error.what(); parseSuccess = 0; } catch(const std::exception& std_error) { failureMessage = std_error.what(); parseSuccess = 0; } } #if HAVE_MPI else { if (!summaryConfig) summaryConfig = std::make_unique(); if (!schedule) schedule = std::make_unique(python); if (!eclipseState) eclipseState = std::make_unique(); } try { Opm::eclStateBroadcast(*eclipseState, *schedule, *summaryConfig); } catch(const std::exception& broadcast_error) { failureMessage = broadcast_error.what(); OpmLog::error(fmt::format("Distributing properties to all processes failed\n" "Internal error message: {}", broadcast_error.what())); parseSuccess = 0; } #endif if (*errorGuard) { // errors encountered parseSuccess = 0; errorGuard->dump(); errorGuard->clear(); } auto comm = Dune::MPIHelper::getCollectiveCommunication(); parseSuccess = comm.min(parseSuccess); if (!parseSuccess) { if (rank == 0) { OpmLog::error("Unrecoverable errors were encountered while loading input"); } #if HAVE_MPI MPI_Finalize(); #endif std::exit(EXIT_FAILURE); } } } // end namespace Opm