From 52c2655bcb769bebe1212cf7d135560bc57e21de Mon Sep 17 00:00:00 2001
From: Ludovic Aubry <ludovic.aubry@cea.fr>
Date: Mon, 9 Sep 2024 13:20:10 +0200
Subject: [PATCH] Fix a case when mfront would raise an exception and leave
 PetSc vectors in an unwanted state

---
 MathLib/LinAlg/LinAlg.h                       | 16 +++++++++++++++
 NumLib/ODESolver/NonlinearSolver.cpp          |  6 +++++-
 NumLib/ODESolver/TimeDiscretizedODESystem.cpp | 17 +++++++++++-----
 .../SmallDeformationProcess.cpp               | 20 ++++++++++++++-----
 4 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/MathLib/LinAlg/LinAlg.h b/MathLib/LinAlg/LinAlg.h
index 206395e8f90..038dd762743 100644
--- a/MathLib/LinAlg/LinAlg.h
+++ b/MathLib/LinAlg/LinAlg.h
@@ -17,6 +17,8 @@
 
 #ifdef USE_PETSC
 #include <petscsystypes.h>
+
+#include "PETSc/PETScVector.h"
 #endif
 
 namespace MathLib
@@ -204,6 +206,14 @@ void linearSysNormalize(PETScMatrix const& A, PETScMatrix& new_A,
 void finalizeAssembly(PETScMatrix& A);
 void finalizeAssembly(PETScVector& x);
 
+// Reduce operations for interprocess communications while using Petsc
+static inline int reduceMin(int val)
+{
+    int result;
+    MPI_Allreduce(&val, &result, 1, MPI_INTEGER, MPI_MIN, PETSC_COMM_WORLD);
+    return result;
+}
+
 }  // namespace LinAlg
 }  // namespace MathLib
 
@@ -276,6 +286,12 @@ void linearSysNormalize(EigenMatrix const& A, EigenMatrix& new_A,
 void finalizeAssembly(EigenMatrix& x);
 void finalizeAssembly(EigenVector& A);
 
+// Reduce operations for interprocess communications while using Petsc
+static inline int reduceMin(int val)
+{
+    return val;
+}
+
 }  // namespace LinAlg
 
 }  // namespace MathLib
diff --git a/NumLib/ODESolver/NonlinearSolver.cpp b/NumLib/ODESolver/NonlinearSolver.cpp
index 59c0886b55b..520e18442d2 100644
--- a/NumLib/ODESolver/NonlinearSolver.cpp
+++ b/NumLib/ODESolver/NonlinearSolver.cpp
@@ -356,6 +356,7 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Newton>::solve(
 
         BaseLib::RunTime time_assembly;
         time_assembly.start();
+        int ok = 1, g_ok = 0;
         try
         {
             sys.assemble(x, x_prev, process_id);
@@ -366,8 +367,11 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Newton>::solve(
                 e.what());
             error_norms_met = false;
             iteration = _maxiter;
-            break;
+            ok = 0;
         }
+        g_ok = MathLib::LinAlg::reduceMin(ok);
+        if (g_ok == 0)
+            break;
         sys.getResidual(*x[process_id], *x_prev[process_id], res);
         sys.getJacobian(J);
         INFO("[time] Assembly took {:g} s.", time_assembly.elapsed());
diff --git a/NumLib/ODESolver/TimeDiscretizedODESystem.cpp b/NumLib/ODESolver/TimeDiscretizedODESystem.cpp
index a536e2ff034..cfc584031a5 100644
--- a/NumLib/ODESolver/TimeDiscretizedODESystem.cpp
+++ b/NumLib/ODESolver/TimeDiscretizedODESystem.cpp
@@ -79,11 +79,18 @@ void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear,
 
     _b->setZero();
     _Jac->setZero();
-
-    _ode.preAssemble(t, dt, x_curr);
-    _ode.assembleWithJacobian(t, dt, x_new_timestep, x_prev, process_id, *_b,
-                              *_Jac);
-
+    try
+    {
+        _ode.preAssemble(t, dt, x_curr);
+        _ode.assembleWithJacobian(t, dt, x_new_timestep, x_prev, process_id,
+                                  *_b, *_Jac);
+    }
+    catch (AssemblyException const&)
+    {
+        MathLib::LinAlg::finalizeAssembly(*_b);
+        MathLib::LinAlg::finalizeAssembly(*_Jac);
+        throw;
+    }
     MathLib::LinAlg::finalizeAssembly(*_b);
     MathLib::LinAlg::finalizeAssembly(*_Jac);
 }
diff --git a/ProcessLib/SmallDeformation/SmallDeformationProcess.cpp b/ProcessLib/SmallDeformation/SmallDeformationProcess.cpp
index 8e9ea109e51..fdb73c82536 100644
--- a/ProcessLib/SmallDeformation/SmallDeformationProcess.cpp
+++ b/ProcessLib/SmallDeformation/SmallDeformationProcess.cpp
@@ -14,6 +14,7 @@
 
 #include "MeshLib/Utils/IntegrationPointWriter.h"
 #include "MeshLib/Utils/getOrCreateMeshProperty.h"
+#include "NumLib/Exceptions.h"
 #include "ProcessLib/Deformation/SolidMaterialInternalToSecondaryVariables.h"
 #include "ProcessLib/Output/CellAverageAlgorithm.h"
 #include "ProcessLib/Process.h"
@@ -162,11 +163,20 @@ void SmallDeformationProcess<DisplacementDim>::
     std::vector<NumLib::LocalToGlobalIndexMap const*> dof_table = {
         _local_to_global_index_map.get()};
     // Call global assembler for each local assembly item.
-    GlobalExecutor::executeSelectedMemberDereferenced(
-        _global_assembler, &VectorMatrixAssembler::assembleWithJacobian,
-        _local_assemblers, getActiveElementIDs(), dof_table, t, dt, x, x_prev,
-        process_id, &b, &Jac);
-
+    try
+    {
+        GlobalExecutor::executeSelectedMemberDereferenced(
+            _global_assembler, &VectorMatrixAssembler::assembleWithJacobian,
+            _local_assemblers, getActiveElementIDs(), dof_table, t, dt, x,
+            x_prev, process_id, &b, &Jac);
+    }
+    catch (NumLib::AssemblyException const&)
+    {
+        transformVariableFromGlobalVector(b, 0, *_local_to_global_index_map,
+                                          *_nodal_forces,
+                                          std::negate<double>());
+        throw;
+    }
     transformVariableFromGlobalVector(b, 0, *_local_to_global_index_map,
                                       *_nodal_forces, std::negate<double>());
 
-- 
GitLab