]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Deal with obnoxious NOX ways of reporting errors.
authorWolfgang Bangerth <bangerth@colostate.edu>
Tue, 9 May 2023 16:47:18 +0000 (10:47 -0600)
committerWolfgang Bangerth <bangerth@colostate.edu>
Tue, 9 May 2023 18:31:36 +0000 (12:31 -0600)
include/deal.II/trilinos/nox.templates.h

index 8df46cedaec5994d6a1b7660f794dd9759629c91..57d8974504356a9b1053d62ce55d2ac7baa67c84 100644 (file)
@@ -1121,18 +1121,78 @@ namespace TrilinosWrappers
     // callback functions. If so, exit by rethrowing the exception that
     // we had previously saved. This also calls the destructors of all of
     // the member variables above, so we do not have to clean things up by hand.
-    const auto status = solver->solve();
-    if (pending_exception)
+    //
+    // NOX has the annoying habit of reporting success through a return code,
+    // but if a user callback function throws an exception (which we translate
+    // into a return code of -1), then it throws its own exception. So we
+    // have to check both the return code and also catch exceptions :-(
+    try
       {
-        std::exception_ptr this_exception = pending_exception;
-        pending_exception                 = nullptr;
+        const auto status = solver->solve();
 
-        std::rethrow_exception(this_exception);
+        if (status == NOX::StatusTest::Converged)
+          return solver->getNumIterations();
+        else
+          {
+            // See if NOX aborted because we had thrown an exception in a user
+            // callback:
+            if (pending_exception)
+              {
+                std::exception_ptr this_exception = pending_exception;
+                pending_exception                 = nullptr;
+
+                std::rethrow_exception(this_exception);
+              }
+
+            // If that was not the case, NOX just didn't converge:
+            AssertThrow(status == NOX::StatusTest::Converged,
+                        ExcNOXNoConvergence());
+          }
       }
+    // See if NOX returned by triggering an exception. In a sign of generally
+    // poor software design, NOX throws an exception that is not of a class
+    // derived from std::exception, but just a char*. That's a nuisance -- you
+    // just have to know :-(
+    catch (const char *s)
+      {
+        // Like above, see if NOX aborted because there was an exception
+        // in a user callback. In that case, collate the errors if we can
+        // (namely, if the user exception was derived from std::exception),
+        // and otherwise just let the user exception propagate (then swallowing
+        // the NOX exception):
+        if (pending_exception)
+          {
+            std::exception_ptr this_exception = pending_exception;
+            pending_exception                 = nullptr;
+
+            try
+              {
+                std::rethrow_exception(this_exception);
+              }
+            catch (const std::exception &e)
+              {
+                // Collate the exception texts:
+                throw ExcMessage(
+                  "NOX aborted with an error text of <" + std::string(s) +
+                  "> after a user callback function had thrown an exception " +
+                  "with the following message:\n" + e.what());
+              }
+            catch (...)
+              {
+                // Let user exception propagate if of a different type:
+                throw;
+              }
+          }
 
-    AssertThrow(status == NOX::StatusTest::Converged, ExcNOXNoConvergence());
+        // NOX just happened to throw an exception, but it wasn't because there
+        // was a user callback exception before. Convert the char* to something
+        // more readable:
+        AssertThrow(false,
+                    ExcMessage("NOX aborted with an error text of <" +
+                               std::string(s) + ">."));
+      }
 
-    return solver->getNumIterations();
+    return 0; // unreachable
   }
 
 } // namespace TrilinosWrappers

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.