diff --git a/opm/models/discretization/common/fvbasediscretization.hh b/opm/models/discretization/common/fvbasediscretization.hh index eae22639c53..53eea027230 100644 --- a/opm/models/discretization/common/fvbasediscretization.hh +++ b/opm/models/discretization/common/fvbasediscretization.hh @@ -67,8 +67,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -726,49 +728,86 @@ public: { invalidateIntensiveQuantitiesCache(timeIdx); + // exceptions must not escape the parallel block below (that calls + // std::terminate()); tuck any exception away and rethrow it after the + // block, so that e.g. a failed flash in the property evaluation leads + // to a time step chop instead of an abort + std::mutex exceptionLock; + std::exception_ptr exceptionPtr = nullptr; + // loop over all elements... ThreadedEntityIterator threadedElemIt(gridView_); #ifdef _OPENMP #pragma omp parallel #endif { - ElementContext elemCtx(simulator_); - ElementIterator elemIt = threadedElemIt.beginParallel(); - for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) { - const Element& elem = *elemIt; - elemCtx.updatePrimaryStencil(elem); - elemCtx.updatePrimaryIntensiveQuantities(timeIdx); + try { + ElementContext elemCtx(simulator_); + for (ElementIterator elemIt = threadedElemIt.beginParallel(); + !threadedElemIt.isFinished(elemIt); + elemIt = threadedElemIt.increment()) + { + const Element& elem = *elemIt; + elemCtx.updatePrimaryStencil(elem); + elemCtx.updatePrimaryIntensiveQuantities(timeIdx); + } + } + catch (...) { + std::lock_guard take(exceptionLock); + exceptionPtr = std::current_exception(); + threadedElemIt.setFinished(); } } + + if (exceptionPtr) { + std::rethrow_exception(exceptionPtr); + } } template void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType& gridView) const { + // see the overload above for why exceptions are bridged out of the + // parallel block like this + std::mutex exceptionLock; + std::exception_ptr exceptionPtr = nullptr; + // loop over all elements... ThreadedEntityIterator threadedElemIt(gridView); #ifdef _OPENMP #pragma omp parallel #endif { - - ElementContext elemCtx(simulator_); - auto elemIt = threadedElemIt.beginParallel(); - for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) { - if (elemIt->partitionType() != Dune::InteriorEntity) { - continue; - } - const Element& elem = *elemIt; - elemCtx.updatePrimaryStencil(elem); - // Mark cache for this element as invalid. - const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx); - for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) { - const unsigned globalIndex = elemCtx.globalSpaceIndex(dofIdx, timeIdx); - setIntensiveQuantitiesCacheEntryValidity(globalIndex, timeIdx, false); + try { + ElementContext elemCtx(simulator_); + for (auto elemIt = threadedElemIt.beginParallel(); + !threadedElemIt.isFinished(elemIt); + elemIt = threadedElemIt.increment()) + { + if (elemIt->partitionType() != Dune::InteriorEntity) { + continue; + } + const Element& elem = *elemIt; + elemCtx.updatePrimaryStencil(elem); + // Mark cache for this element as invalid. + const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx); + for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) { + const unsigned globalIndex = elemCtx.globalSpaceIndex(dofIdx, timeIdx); + setIntensiveQuantitiesCacheEntryValidity(globalIndex, timeIdx, false); + } + // Update for this element. + elemCtx.updatePrimaryIntensiveQuantities(timeIdx); } - // Update for this element. - elemCtx.updatePrimaryIntensiveQuantities(timeIdx); } + catch (...) { + std::lock_guard take(exceptionLock); + exceptionPtr = std::current_exception(); + threadedElemIt.setFinished(); + } + } + + if (exceptionPtr) { + std::rethrow_exception(exceptionPtr); } } diff --git a/opm/simulators/flow/Banners.cpp b/opm/simulators/flow/Banners.cpp index bc1cc80e5e3..d552ad0ae79 100644 --- a/opm/simulators/flow/Banners.cpp +++ b/opm/simulators/flow/Banners.cpp @@ -121,7 +121,8 @@ void printFlowTrailer(int nprocs, const double total_setup_time, const double deck_read_time, const SimulatorReport& report, - const std::string_view extra_summary) + const std::string_view extra_summary, + const bool performance_details) { std::ostringstream ss; ss << "\n\n================ End of simulation ===============\n\n"; @@ -129,7 +130,7 @@ void printFlowTrailer(int nprocs, ss << fmt::format("Threads per MPI process: {:9}\n", nthreads); ss << fmt::format("Setup time: {:9.2f} s\n", total_setup_time); ss << fmt::format(" Deck input: {:9.2f} s\n", deck_read_time); - report.reportFullyImplicit(ss); + report.reportFullyImplicit(ss, performance_details); if (!extra_summary.empty()) { if (extra_summary.front() != '\n') { ss << '\n'; diff --git a/opm/simulators/flow/Banners.hpp b/opm/simulators/flow/Banners.hpp index ef342b6d8fc..bb3fce6e776 100644 --- a/opm/simulators/flow/Banners.hpp +++ b/opm/simulators/flow/Banners.hpp @@ -46,7 +46,8 @@ void printFlowTrailer(int nprocs, const double total_setup_time, const double deck_read_time, const SimulatorReport& report, - std::string_view extra_summary); + std::string_view extra_summary, + const bool performance_details = false); } // namespace Opm diff --git a/opm/simulators/flow/ConvergenceOutputConfiguration.cpp b/opm/simulators/flow/ConvergenceOutputConfiguration.cpp index 74a246ff526..ff0a4e9bf86 100644 --- a/opm/simulators/flow/ConvergenceOutputConfiguration.cpp +++ b/opm/simulators/flow/ConvergenceOutputConfiguration.cpp @@ -57,7 +57,7 @@ namespace { fmt::format("Unsupported convergence output " "option value{}: {}\n" "Supported values are \"none\", " - "\"steps\", and \"iterations\"", + "\"steps\", \"iterations\", and \"performance\"", pl, fmt::join(unsupp.begin(), u, ", ")) }; } @@ -65,7 +65,7 @@ namespace { throw std::invalid_argument { fmt::format("Option {}:\n - Unsupported value{}: {}\n" " - Supported values are \"none\", " - "\"steps\", and \"iterations\"", + "\"steps\", \"iterations\", and \"performance\"", optionName, pl, fmt::join(unsupp.begin(), u, ", ")) }; @@ -79,11 +79,13 @@ namespace { auto opt = std::vector