From 634f0d61d8e99249aae1de9f33684e2d5933131c Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 18 Mar 2021 08:29:23 +0100 Subject: [PATCH] Deferred logger will throw "correct" exception --- opm/simulators/utils/DeferredLogger.hpp | 19 +++ .../utils/DeferredLoggingErrorHelpers.hpp | 38 ++++-- .../wells/BlackoilWellModel_impl.hpp | 120 ++++++++++++++---- 3 files changed, 142 insertions(+), 35 deletions(-) diff --git a/opm/simulators/utils/DeferredLogger.hpp b/opm/simulators/utils/DeferredLogger.hpp index ec02889bf..e7d724c38 100644 --- a/opm/simulators/utils/DeferredLogger.hpp +++ b/opm/simulators/utils/DeferredLogger.hpp @@ -33,6 +33,25 @@ namespace Opm * 2) a call to logMessages adds the messages to OpmLog backends * */ +namespace ExceptionType +{ + + +/* + If an exception has been raised on more than processor simultaneously the + highest number type will be thrown in the subsequent global rethrow. +*/ + +enum ExcEnum { + NONE = 0, + RUNTIME_ERROR = 1, + INVALID_ARGUMENT = 2, + LOGIC_ERROR = 3, + DEFAULT = 4, // will throw std::logic_error() +}; +} + + class DeferredLogger { public: diff --git a/opm/simulators/utils/DeferredLoggingErrorHelpers.hpp b/opm/simulators/utils/DeferredLoggingErrorHelpers.hpp index 8bc0a267f..9daf3e24e 100644 --- a/opm/simulators/utils/DeferredLoggingErrorHelpers.hpp +++ b/opm/simulators/utils/DeferredLoggingErrorHelpers.hpp @@ -49,15 +49,40 @@ throw Exception(oss__.str()); \ } while (false) -inline void checkForExceptionsAndThrow(int exception_thrown, const std::string& message) -{ +namespace { + +void _throw(Opm::ExceptionType::ExcEnum exc_type, const std::string& message) { const auto& cc = Dune::MPIHelper::getCollectiveCommunication(); - if (cc.max(exception_thrown) == 1) { + auto global_exc = cc.max(exc_type); + + switch (global_exc) { + case Opm::ExceptionType::NONE: + break; + case Opm::ExceptionType::RUNTIME_ERROR: throw std::runtime_error(message); + break; + case Opm::ExceptionType::INVALID_ARGUMENT: + throw std::invalid_argument(message); + break; + case Opm::ExceptionType::DEFAULT: + case Opm::ExceptionType::LOGIC_ERROR: + throw std::logic_error(message); + break; + default: + throw std::logic_error(message); } } -inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logger, int exception_thrown, const std::string& message, const bool terminal_output) +} + + + +inline void checkForExceptionsAndThrow(Opm::ExceptionType::ExcEnum exc_type, const std::string& message) +{ + _throw(exc_type, message); +} + +inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logger, Opm::ExceptionType::ExcEnum exc_type , const std::string& message, const bool terminal_output) { Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(deferred_logger); if (terminal_output) { @@ -67,10 +92,7 @@ inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logge // cleared from the global logger, but we must also clear them // from the local logger. deferred_logger.clearMessages(); - const auto& cc = Dune::MPIHelper::getCollectiveCommunication(); - if (cc.max(exception_thrown) == 1) { - throw std::runtime_error(message); - } + _throw(exc_type, message); } #endif // OPM_DEFERREDLOGGINGERRORHELPERS_HPP diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 9fe6136fb..1929f70e0 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -309,7 +309,8 @@ namespace Opm { updateAndCommunicateGroupData(local_deferredLogger); const int reportStepIdx = ebosSimulator_.episodeIndex(); const double simulationTime = ebosSimulator_.time(); - int exception_thrown = 0; + std::string exc_msg; + auto exc_type = ExceptionType::NONE; try { // test wells wellTesting(reportStepIdx, simulationTime, local_deferredLogger); @@ -342,11 +343,21 @@ namespace Opm { setRepRadiusPerfLength(); } } - } catch (std::exception& e) { - exception_thrown = 1; + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); } - logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "beginTimeStep() failed.", terminal_output_); + logAndCheckForExceptionsAndThrow(local_deferredLogger, exc_type, "beginTimeStep() failed: " + exc_msg, terminal_output_); for (auto& well : well_container_) { well->setVFPProperties(vfp_properties_.get()); @@ -395,19 +406,33 @@ namespace Opm { try { well->calculateExplicitQuantities(ebosSimulator_, well_state_, local_deferredLogger); well->solveWellEquation(ebosSimulator_, well_state_, local_deferredLogger); - } catch (std::exception& e) { + } catch (const std::exception& e) { const std::string msg = "Compute initial well solution for new well " + well->name() + " failed. Continue with zero initial rates"; local_deferredLogger.warning("WELL_INITIAL_SOLVE_FAILED", msg); } } } - } catch (std::exception& e) { + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); + } + + if (exc_type != ExceptionType::NONE) { const std::string msg = "Compute initial well solution for new wells failed. Continue with zero initial rates"; local_deferredLogger.warning("WELL_INITIAL_SOLVE_FAILED", msg); } logAndCheckForExceptionsAndThrow(local_deferredLogger, - exception_thrown, "beginTimeStep() failed.", terminal_output_); + exc_type, "beginTimeStep() failed: " + exc_msg, terminal_output_); } @@ -986,7 +1011,8 @@ namespace Opm { updatePerforationIntensiveQuantities(); - int exception_thrown = 0; + auto exc_type = ExceptionType::NONE; + std::string exc_msg; try { if (iterationIdx == 0) { calculateExplicitQuantities(local_deferredLogger); @@ -1011,12 +1037,21 @@ namespace Opm { well_state_.enableGliftOptimization(); assembleWellEq(B_avg, dt, local_deferredLogger); well_state_.disableGliftOptimization(); - - } catch (std::exception& e) { - exception_thrown = 1; + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); } - logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "assemble() failed.", terminal_output_); + logAndCheckForExceptionsAndThrow(local_deferredLogger, exc_type, "assemble() failed: " + exc_msg, terminal_output_); last_report_.converged = true; last_report_.assemble_time_well += perfTimer.stop(); } @@ -1135,18 +1170,28 @@ namespace Opm { recoverWellSolutionAndUpdateWellState(const BVector& x) { Opm::DeferredLogger local_deferredLogger; - - int exception_thrown = 0; + auto exc_type = ExceptionType::NONE; + std::string exc_msg; try { if (localWellsActive()) { for (auto& well : well_container_) { well->recoverWellSolutionAndUpdateWellState(x, well_state_, local_deferredLogger); } } - } catch (std::exception& e) { - exception_thrown = 1; + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); } - logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "recoverWellSolutionAndUpdateWellState() failed.", terminal_output_); + logAndCheckForExceptionsAndThrow(local_deferredLogger, exc_type, "recoverWellSolutionAndUpdateWellState() failed: " + exc_msg, terminal_output_); } @@ -1455,7 +1500,8 @@ namespace Opm { const Opm::SummaryConfig& summaryConfig = ebosSimulator_.vanguard().summaryConfig(); const bool write_restart_file = ebosSimulator_.vanguard().schedule().write_rst_file(reportStepIdx); - int exception_thrown = 0; + auto exc_type = ExceptionType::NONE; + std::string exc_msg; for (const auto& well : well_container_) { const bool needed_for_summary = ((summaryConfig.hasSummaryKey( "WWPI:" + well->name()) || summaryConfig.hasSummaryKey( "WOPI:" + well->name()) || @@ -1474,14 +1520,23 @@ namespace Opm { for (int p = 0; p < np; ++p) { well_potentials[well->indexOfWell() * np + p] = std::abs(potentials[p]); } - } catch (std::exception& e) { - exception_thrown = 1; + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); } } } - - logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, - "computeWellPotentials() failed.", + logAndCheckForExceptionsAndThrow(deferred_logger, exc_type, + "computeWellPotentials() failed: " + exc_msg, terminal_output_); // Store it in the well state @@ -1520,7 +1575,8 @@ namespace Opm { BlackoilWellModel:: prepareTimeStep(Opm::DeferredLogger& deferred_logger) { - int exception_thrown = 0; + auto exc_type = ExceptionType::NONE; + std::string exc_msg; try { for (const auto& well : well_container_) { well->checkWellOperability(ebosSimulator_, well_state_, deferred_logger); @@ -1545,10 +1601,20 @@ namespace Opm { } } // end of for (const auto& well : well_container_) updatePrimaryVariables(deferred_logger); - } catch (std::exception& e) { - exception_thrown = 1; + } catch (const std::runtime_error& e) { + exc_type = ExceptionType::RUNTIME_ERROR; + exc_msg = e.what(); + } catch (const std::invalid_argument& e) { + exc_type = ExceptionType::INVALID_ARGUMENT; + exc_msg = e.what(); + } catch (const std::logic_error& e) { + exc_type = ExceptionType::LOGIC_ERROR; + exc_msg = e.what(); + } catch (const std::exception& e) { + exc_type = ExceptionType::DEFAULT; + exc_msg = e.what(); } - logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "prepareTimestep() failed.", terminal_output_); + logAndCheckForExceptionsAndThrow(deferred_logger, exc_type, "prepareTimestep() failed: " + exc_msg, terminal_output_); }