Merge pull request #4750 from blattms/prevent-mpi-abort

Do a graceful exit instead of MPI_Abort for expected exceptions.
This commit is contained in:
Markus Blatt 2023-07-20 18:52:47 +02:00 committed by GitHub
commit 941e4230c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 257 additions and 74 deletions

View File

@ -25,7 +25,10 @@
int main(int argc, char** argv)
{
auto mainObject = Opm::Main(argc, argv);
return mainObject.runDynamic();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runDynamic();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}

View File

@ -35,6 +35,9 @@ struct EclEnableAquifers<TypeTag, TTag::EclFlowProblemAlugrid> {
int main(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemAlugrid;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}

View File

@ -60,8 +60,11 @@ std::vector<int> loadBalanceInZOnly(const Dune::CpGrid& grid)
int main(int argc, char** argv)
{
auto mainObject = Opm::Main(argc, argv);
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
Opm::EclCpGridVanguard<Opm::Properties::TTag::EclFlowProblem>::setExternalLoadBalancer(loadBalanceInZOnly);
return mainObject.runDynamic();
auto ret = mainObject->runDynamic();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}

View File

@ -70,8 +70,11 @@ int flowEbosBlackoilTpfaMain(int argc, char** argv, bool outputCout, bool output
int flowEbosBlackoilTpfaMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowProblemTPFA;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
} // namespace Opm

View File

@ -45,8 +45,11 @@ int flowEbosBlackoilMain(int argc, char** argv, bool outputCout, bool outputFile
int flowEbosBlackoilMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -31,8 +31,11 @@ namespace Properties {
int flowEbosBlackoilPolyMain(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemPoly;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosBrineMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosBrineMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowBrineProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -37,8 +37,11 @@ struct EnableEnergy<TypeTag, TTag::EclFlowBrineProblem> {
int flowEbosBrineEnergyMain(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowBrineProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -63,8 +63,11 @@ int flowEbosBrinePrecsaltVapwatMain(int argc, char** argv, bool outputCout, bool
int flowEbosBrinePrecsaltVapwatMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowBrinePrecsaltVapwatProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -58,8 +58,11 @@ int flowEbosBrineSaltPrecipitationMain(int argc, char** argv, bool outputCout, b
int flowEbosBrineSaltPrecipitationMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowBrineSaltPrecipitationProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosEnergyMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowEnergyProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosExtboMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosExtboMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowExtboProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosFoamMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosFoamMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowFoamProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -86,8 +86,11 @@ int flowEbosGasOilMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosGasOilMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasOilProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -78,8 +78,11 @@ int flowEbosGasOilEnergyMain(int argc, char** argv, bool outputCout, bool output
int flowEbosGasOilEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasOilEnergyProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -78,8 +78,11 @@ int flowEbosGasOilDiffuseMain(int argc, char** argv, bool outputCout, bool outpu
int flowEbosGasOilDiffuseMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasOilDiffuseProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -90,8 +90,11 @@ int flowEbosGasWaterMain(int argc, char** argv, bool outputCout, bool outputFile
int flowEbosGasWaterMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -77,8 +77,11 @@ int flowEbosGasWaterBrineMain(int argc, char** argv, bool outputCout, bool outpu
int flowEbosGasWaterBrineMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterBrineProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -100,8 +100,11 @@ int flowEbosGasWaterDissolutionMain(int argc, char** argv, bool outputCout, bool
int flowEbosGasWaterDissolutionMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterDissolutionProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -100,8 +100,11 @@ int flowEbosGasWaterDissolutionDiffuseMain(int argc, char** argv, bool outputCou
int flowEbosGasWaterDissolutionDiffuseMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterDissolutionDiffuseProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -105,8 +105,11 @@ int flowEbosGasWaterEnergyMain(int argc, char** argv, bool outputCout, bool outp
int flowEbosGasWaterEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterEnergyProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -98,8 +98,11 @@ int flowEbosGasWaterSaltprecEnergyMain(int argc, char** argv, bool outputCout, b
int flowEbosGasWaterSaltprecEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterSaltprecEnergyProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -93,8 +93,11 @@ int flowEbosGasWaterSaltprecVapwatMain(int argc, char** argv, bool outputCout, b
int flowEbosGasWaterSaltprecVapwatMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterSaltprecVapwatProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -83,8 +83,11 @@ int flowEbosGasWaterSolventMain(int argc, char** argv, bool outputCout, bool out
int flowEbosGasWaterSolventMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowGasWaterSolventProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -77,8 +77,11 @@ int flowEbosMICPMain(int argc, char** argv, bool outputCout, bool outputFiles)
int flowEbosMICPMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowMICPProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -89,8 +89,11 @@ int flowEbosOilWaterMain(int argc, char** argv, bool outputCout, bool outputFile
int flowEbosOilWaterMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowOilWaterProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -77,8 +77,11 @@ int flowEbosOilWaterBrineMain(int argc, char** argv, bool outputCout, bool outpu
int flowEbosOilWaterBrineMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowOilWaterBrineProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -77,8 +77,11 @@ int flowEbosOilWaterPolymerMain(int argc, char** argv, bool outputCout, bool out
int flowEbosOilWaterPolymerMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowOilWaterPolymerProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -90,8 +90,11 @@ int flowEbosOilWaterPolymerInjectivityMain(int argc, char** argv, bool outputCou
int flowEbosOilWaterPolymerInjectivityMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowOilWaterPolymerInjectivityProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -84,8 +84,11 @@ int flowEbosWaterOnlyMain(int argc, char** argv, bool outputCout, bool outputFil
int flowEbosWaterOnlyMainStandalone(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemWaterOnly;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -79,8 +79,11 @@ int flowEbosWaterOnlyEnergyMain(int argc, char** argv, bool outputCout, bool out
int flowEbosWaterOnlyEnergyMainStandalone(int argc, char** argv)
{
using TypeTag = Opm::Properties::TTag::EclFlowProblemWaterOnlyEnergy;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosPolymerMain(int argc, char** argv, bool outputCout, bool outputFiles
int flowEbosPolymerMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowPolymerProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -53,8 +53,11 @@ int flowEbosSolventMain(int argc, char** argv, bool outputCout, bool outputFiles
int flowEbosSolventMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowSolventProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -58,8 +58,11 @@ int flowEbosSolventFoamMain(int argc, char** argv, bool outputCout, bool outputF
int flowEbosSolventFoamMainStandalone(int argc, char** argv)
{
using TypeTag = Properties::TTag::EclFlowSolventFoamProblem;
auto mainObject = Opm::Main(argc, argv);
return mainObject.runStatic<TypeTag>();
auto mainObject = std::make_unique<Opm::Main>(argc, argv);
auto ret = mainObject->runStatic<TypeTag>();
// Destruct mainObject as the destructor calls MPI_Finalize!
mainObject.reset();
return ret;
}
}

View File

@ -77,6 +77,84 @@ void handleExtraConvergenceOutput(SimulatorReport& report,
report.fullReports(os);
}
}
void checkAllMPIProcesses()
{
#if HAVE_MPI
const auto& comm = EclGenericVanguard::comm();
if (comm.size() > 1)
{
// we try to prevent the abort here.
// For that we need a signal that each process is here.
// Each process sends a message to rank 0.
const int tag = 357912;
if (comm.rank() == 0)
{
// wait for a message from all processes.
std::vector<MPI_Request> requests(comm.size() - 1, MPI_REQUEST_NULL);
std::vector<int> data(comm.size()-1);
for(decltype(comm.size()) i = 1; i < comm.size(); ++i)
{
if (auto error = MPI_Irecv(data.data() + i, 1, MPI_INT, i, tag, comm, requests.data() + i - 1);
error != MPI_SUCCESS) {
OpmLog::error(fmt::format("Error: Could not set up MPI receive (error code : {})", error));
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
}
std::size_t msgs = comm.size() - 1;
for(std::size_t tries = 0; msgs >0 && tries < 3; ++tries)
{
sleep(3);
int flag, idx;
for(auto left_msgs = msgs; left_msgs > 0; --left_msgs)
{
if( auto error = MPI_Testany(comm.size()-1, requests.data(), &idx, &flag, MPI_STATUS_IGNORE);
error != MPI_SUCCESS) {
OpmLog::error(fmt::format("Error: Could not test for MPI message (error code : {})", error));
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
if (flag)
{
--msgs;
}
}
}
if (msgs) {
// seems like some processes are stuck. Abort just to be save
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
}
else
{
int data= 3;
MPI_Request request = MPI_REQUEST_NULL;
if (auto error = MPI_Isend(&data, 1, MPI_INT, 0, tag, comm, &request);
error != MPI_SUCCESS) {
OpmLog::error(fmt::format("Error: Could send MPI message (error code : {})", error));
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
bool completed = false;
for(std::size_t tries = 0; !completed && tries < 3; tries++)
{
sleep(3);
int flag;
if( auto error = MPI_Test(&request, &flag, MPI_STATUS_IGNORE);
error != MPI_SUCCESS) {
OpmLog::error(fmt::format("Error: Could not test for MPI message (error code : {})", error));
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
if (flag)
{
completed = true;
}
}
if (!completed) {
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
}
}
}
#endif
}
} // namespace detail
} // namespace Opm

View File

@ -75,6 +75,8 @@ struct OutputInterval<TypeTag, TTag::EclFlowProblem> {
namespace Opm {
namespace detail {
void checkAllMPIProcesses();
void mergeParallelLogFiles(std::string_view output_dir,
std::string_view deck_filename,
bool enableLoggingFalloutWarning);
@ -338,10 +340,7 @@ void handleExtraConvergenceOutput(SimulatorReport& report,
std::cout << message.str() << "\n";
}
}
#if HAVE_MPI
if (this->mpi_size_ > 1)
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
#endif
detail::checkAllMPIProcesses();
return EXIT_FAILURE;
};
@ -364,10 +363,14 @@ void handleExtraConvergenceOutput(SimulatorReport& report,
return exitCode;
}
catch (const LinearTimeSteppingBreakdown& e) {
return logger(e, "Simulation aborted: ");
auto exitCode = logger(e, "Simulation aborted: ");
executeCleanup_();
return exitCode;
}
catch (const std::exception& e) {
return logger(e, "Simulation aborted as program threw an unexpected exception: ");
auto exitCode = logger(e, "Simulation aborted as program threw an unexpected exception: ");
executeCleanup_();
return exitCode;
}
}