Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 3 : 4 : // This library is free software; you can redistribute it and/or 5 : // modify it under the terms of the GNU Lesser General Public 6 : // License as published by the Free Software Foundation; either 7 : // version 2.1 of the License, or (at your option) any later version. 8 : 9 : // This library is distributed in the hope that it will be useful, 10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 : // Lesser General Public License for more details. 13 : 14 : // You should have received a copy of the GNU Lesser General Public 15 : // License along with this library; if not, write to the Free Software 16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 : 18 : #ifndef LIBMESH_PETSC_SOLVER_EXCEPTION_H 19 : #define LIBMESH_PETSC_SOLVER_EXCEPTION_H 20 : 21 : #include "libmesh/libmesh_common.h" 22 : 23 : #ifdef LIBMESH_HAVE_PETSC 24 : 25 : #include "libmesh/libmesh_exceptions.h" 26 : #include "libmesh/petsc_macro.h" 27 : #include "timpi/communicator.h" 28 : 29 : #ifdef I 30 : # define LIBMESH_SAW_I 31 : #endif 32 : 33 : #include "libmesh/ignore_warnings.h" 34 : #include <petscsys.h> 35 : #include "libmesh/restore_warnings.h" 36 : 37 : #ifndef LIBMESH_SAW_I 38 : # undef I // Avoid complex.h contamination 39 : #endif 40 : 41 : namespace libMesh 42 : { 43 : 44 : // The SolverException class is only defined when exceptions are enabled. 45 : #ifdef LIBMESH_ENABLE_EXCEPTIONS 46 : 47 : /** 48 : * A specialization of the SolverException class for PETSc. 49 : */ 50 : class PetscSolverException : public SolverException 51 : { 52 : public: 53 0 : PetscSolverException(int error_code_in) : 54 0 : SolverException(error_code_in) 55 : { 56 : const char * text; 57 : #if PETSC_VERSION_LESS_THAN(3,25,0) 58 : char * specific; 59 : #else 60 : const char * specific; 61 : #endif 62 0 : auto ierr = PetscErrorMessage(cast_int<PetscErrorCode>(error_code), &text, &specific); 63 : // This is one scenario where we ignore the error code 64 : // returned by a PETSc function :) 65 0 : libmesh_ignore(ierr); 66 : 67 : // Usually the "specific" error message string is more useful than 68 : // the generic text corresponding to the error_code, since many 69 : // SETERRQ calls just use error_code == 1 70 0 : if (specific) 71 0 : what_message = std::string(specific); 72 0 : else if (text) 73 0 : what_message = std::string(text); 74 0 : } 75 : }; 76 : 77 : 78 : 79 : // Macro which we call in functions returning a datatype convertible 80 : // to PetscErrorCode after every PETSc function that returns an error code. 81 : #define LIBMESH_CHKERRQ(ierr) \ 82 : do { \ 83 : if (ierr != 0) \ 84 : throw libMesh::PetscSolverException(ierr); \ 85 : } while (0) 86 : 87 : // Two-argument CHKERR macro that takes both a comm and an error 88 : // code. When exceptions are enabled, the comm is not used for 89 : // anything, so we libmesh_ignore() it. 90 : #define LIBMESH_CHKERRA(comm, ierr) \ 91 : do { \ 92 : libmesh_ignore(comm); \ 93 : LIBMESH_CHKERRQ(ierr); \ 94 : } while (0) 95 : 96 : #else 97 : 98 : // If we don't have exceptions enabled, just fall back on calling 99 : // PETSc's CHKERRQ or CHKERRABORT macros. 100 : #define LIBMESH_CHKERRQ(ierr) CHKERRQ(ierr); 101 : #define LIBMESH_CHKERRA(comm, ierr) CHKERRABORT(comm, ierr); 102 : 103 : #endif 104 : 105 : #define PETSC_BEGIN_END(Function) \ 106 : template<class ...Args> \ 107 : inline \ 108 : void Function ## BeginEnd(const Parallel::Communicator & comm, const Args&... args) \ 109 : { \ 110 : PetscErrorCode ierr = LIBMESH_PETSC_SUCCESS; \ 111 : ierr = Function ## Begin(args...); \ 112 : LIBMESH_CHKERRA(comm.get(), ierr); \ 113 : ierr = Function ## End(args...); \ 114 : LIBMESH_CHKERRA(comm.get(), ierr); \ 115 : } 116 : 117 112461 : PETSC_BEGIN_END(VecScatter) // VecScatterBeginEnd 118 1083362 : PETSC_BEGIN_END(MatAssembly) // MatAssemblyBeginEnd 119 3544038 : PETSC_BEGIN_END(VecAssembly) // VecAssemblyBeginEnd 120 3754975 : PETSC_BEGIN_END(VecGhostUpdate) // VecGhostUpdateBeginEnd 121 : 122 : // To use instead of PETSc idioms that'd call CHKERRQ or PetscCall(). 123 : #define LibmeshPetscCallQ(...) \ 124 : do \ 125 : { \ 126 : PetscErrorCode libmesh_petsc_call_ierr; \ 127 : libmesh_petsc_call_ierr = __VA_ARGS__; \ 128 : LIBMESH_CHKERRQ(libmesh_petsc_call_ierr); \ 129 : } while (0) 130 : 131 : // To use instead of PETSc idioms that'd call CHKERRABORT or PetscCallAbort(). 132 : #define LibmeshPetscCallA(comm, ...) \ 133 : do \ 134 : { \ 135 : PetscErrorCode libmesh_petsc_call_ierr; \ 136 : libmesh_petsc_call_ierr = __VA_ARGS__; \ 137 : LIBMESH_CHKERRA(comm, libmesh_petsc_call_ierr); \ 138 : } while (0) 139 : 140 : // Shortcut for LibmeshPetscCallA for use within a ParallelObject, i.e. when 141 : // we can rely on the communicator being available from the "this" pointer. 142 : #define LibmeshPetscCall(...) \ 143 : LibmeshPetscCallA(this->comm().get(), __VA_ARGS__) 144 : 145 : // Shortcut for LibmeshPetscCallA for use when we have a Parallel::Communicator 146 : // available instead of just a bare MPI communicator. 147 : #define LibmeshPetscCall2(comm, ...) \ 148 : LibmeshPetscCallA(comm.get(), __VA_ARGS__) 149 : 150 : #ifdef LIBMESH_ENABLE_EXCEPTIONS 151 : #define LibmeshPetscCallExternal(func, ...) \ 152 : do { \ 153 : const auto libmesh_petsc_call_external_ierr = cast_int<int>(func(__VA_ARGS__)); \ 154 : if (libmesh_petsc_call_external_ierr != 0) \ 155 : throw PetscSolverException(libmesh_petsc_call_external_ierr); \ 156 : } while (0) 157 : #else 158 : #define LibmeshPetscCallExternal(func, ...) \ 159 : do { \ 160 : const auto libmesh_petsc_call_external_ierr = cast_int<int>(func(__VA_ARGS__)); \ 161 : if (libmesh_petsc_call_external_ierr != 0) \ 162 : libmesh_terminate_handler(); \ 163 : } while (0) 164 : #endif 165 : 166 : 167 : } // namespace libMesh 168 : 169 : #endif // LIBMESH_HAVE_PETSC 170 : #endif // LIBMESH_PETSC_SOLVER_EXCEPTION_H