Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2025 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 : char * specific; 58 0 : auto ierr = PetscErrorMessage(cast_int<PetscErrorCode>(error_code), &text, &specific); 59 : // This is one scenario where we ignore the error code 60 : // returned by a PETSc function :) 61 0 : libmesh_ignore(ierr); 62 : 63 : // Usually the "specific" error message string is more useful than 64 : // the generic text corresponding to the error_code, since many 65 : // SETERRQ calls just use error_code == 1 66 0 : if (specific) 67 0 : what_message = std::string(specific); 68 0 : else if (text) 69 0 : what_message = std::string(text); 70 0 : } 71 : }; 72 : 73 : 74 : 75 : // Macro which we call in functions returning a datatype convertible 76 : // to PetscErrorCode after every PETSc function that returns an error code. 77 : #define LIBMESH_CHKERRQ(ierr) \ 78 : do { \ 79 : if (ierr != 0) \ 80 : throw libMesh::PetscSolverException(ierr); \ 81 : } while (0) 82 : 83 : // Two-argument CHKERR macro that takes both a comm and an error 84 : // code. When exceptions are enabled, the comm is not used for 85 : // anything, so we libmesh_ignore() it. 86 : #define LIBMESH_CHKERRA(comm, ierr) \ 87 : do { \ 88 : libmesh_ignore(comm); \ 89 : LIBMESH_CHKERRQ(ierr); \ 90 : } while (0) 91 : 92 : #else 93 : 94 : // If we don't have exceptions enabled, just fall back on calling 95 : // PETSc's CHKERRQ or CHKERRABORT macros. 96 : #define LIBMESH_CHKERRQ(ierr) CHKERRQ(ierr); 97 : #define LIBMESH_CHKERRA(comm, ierr) CHKERRABORT(comm, ierr); 98 : 99 : #endif 100 : 101 : #define PETSC_BEGIN_END(Function) \ 102 : template<class ...Args> \ 103 : inline \ 104 : void Function ## BeginEnd(const Parallel::Communicator & comm, const Args&... args) \ 105 : { \ 106 : PetscErrorCode ierr = LIBMESH_PETSC_SUCCESS; \ 107 : ierr = Function ## Begin(args...); \ 108 : LIBMESH_CHKERRA(comm.get(), ierr); \ 109 : ierr = Function ## End(args...); \ 110 : LIBMESH_CHKERRA(comm.get(), ierr); \ 111 : } 112 : 113 229455 : PETSC_BEGIN_END(VecScatter) // VecScatterBeginEnd 114 1062126 : PETSC_BEGIN_END(MatAssembly) // MatAssemblyBeginEnd 115 3557038 : PETSC_BEGIN_END(VecAssembly) // VecAssemblyBeginEnd 116 3671951 : PETSC_BEGIN_END(VecGhostUpdate) // VecGhostUpdateBeginEnd 117 : 118 : // To use instead of PETSc idioms that'd call CHKERRQ or PetscCall(). 119 : #define LibmeshPetscCallQ(...) \ 120 : do \ 121 : { \ 122 : PetscErrorCode libmesh_petsc_call_ierr; \ 123 : libmesh_petsc_call_ierr = __VA_ARGS__; \ 124 : LIBMESH_CHKERRQ(libmesh_petsc_call_ierr); \ 125 : } while (0) 126 : 127 : // To use instead of PETSc idioms that'd call CHKERRABORT or PetscCallAbort(). 128 : #define LibmeshPetscCallA(comm, ...) \ 129 : do \ 130 : { \ 131 : PetscErrorCode libmesh_petsc_call_ierr; \ 132 : libmesh_petsc_call_ierr = __VA_ARGS__; \ 133 : LIBMESH_CHKERRA(comm, libmesh_petsc_call_ierr); \ 134 : } while (0) 135 : 136 : // Shortcut for LibmeshPetscCallA for use within a ParallelObject, i.e. when 137 : // we can rely on the communicator being available from the "this" pointer. 138 : #define LibmeshPetscCall(...) \ 139 : LibmeshPetscCallA(this->comm().get(), __VA_ARGS__) 140 : 141 : // Shortcut for LibmeshPetscCallA for use when we have a Parallel::Communicator 142 : // available instead of just a bare MPI communicator. 143 : #define LibmeshPetscCall2(comm, ...) \ 144 : LibmeshPetscCallA(comm.get(), __VA_ARGS__) 145 : 146 : #ifdef LIBMESH_ENABLE_EXCEPTIONS 147 : #define LibmeshPetscCallExternal(func, ...) \ 148 : do { \ 149 : const auto libmesh_petsc_call_external_ierr = cast_int<int>(func(__VA_ARGS__)); \ 150 : if (libmesh_petsc_call_external_ierr != 0) \ 151 : throw PetscSolverException(libmesh_petsc_call_external_ierr); \ 152 : } while (0) 153 : #else 154 : #define LibmeshPetscCallExternal(func, ...) \ 155 : do { \ 156 : const auto libmesh_petsc_call_external_ierr = cast_int<int>(func(__VA_ARGS__)); \ 157 : if (libmesh_petsc_call_external_ierr != 0) \ 158 : libmesh_terminate_handler(); \ 159 : } while (0) 160 : #endif 161 : 162 : 163 : } // namespace libMesh 164 : 165 : #endif // LIBMESH_HAVE_PETSC 166 : #endif // LIBMESH_PETSC_SOLVER_EXCEPTION_H