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_WRAPPED_PETSC_H 19 : #define LIBMESH_WRAPPED_PETSC_H 20 : 21 : #include "libmesh/libmesh_config.h" 22 : 23 : #ifdef LIBMESH_HAVE_PETSC 24 : 25 : // C++ includes 26 : #include <utility> // std::swap, std::move 27 : 28 : namespace libMesh 29 : { 30 : 31 : // Template class which wraps PETSc objects and specializes the 32 : // destructor to call the appropriate "XXXDestroy()" routine. 33 : template <typename T> 34 : struct WrappedPetsc 35 : { 36 : /** 37 : * Default constructor. This should mimic the way that we normally 38 : * write e.g. 39 : * KSP ksp; 40 : * and then proceed to use ksp in different PETSc routines. That is, 41 : * obj is not initialized to any particular value. 42 : */ 43 368839 : WrappedPetsc() : obj() {} 44 : 45 : /** 46 : * Constructor which initializes obj to a specific passed-in value. 47 : * This mimics code in which we explicitly create a PETSc object via 48 : * IS is = NULL; 49 : * Technically one could pass any pointer value in here, but it usually 50 : * only makes sense to pass nullptr. 51 : */ 52 23496 : WrappedPetsc(T obj_in) : obj(obj_in) {} 53 : 54 : /** 55 : * Destructor. Just calls destroy(). 56 : */ 57 80262 : ~WrappedPetsc() 58 : { 59 788740 : destroy(); 60 787770 : } 61 : 62 : /** 63 : * Calls destroy() _and_ sets the managed object to nullptr. As far 64 : * as I can tell, setting obj to nullptr is not done by the various 65 : * XXXDestroy() routines of PETSc, so we also don't do this in the 66 : * wrapping class's destructor, however, there are situations where 67 : * it is sometimes useful to both call the relevant XXXDestroy() 68 : * function and reset the pointer, hence the need for this function. 69 : */ 70 6 : void reset_to_zero() 71 : { 72 210 : destroy(); 73 210 : obj = nullptr; 74 204 : } 75 : 76 : /** 77 : * Copy constructor and copy assignment operator. These are deleted 78 : * since I don't think we can safely shallow copy PETSc objects like 79 : * KSP and Vec, which are internally reference-counted pointers and 80 : * probably don't do the right thing if they are shallow-copied. 81 : */ 82 : WrappedPetsc(const WrappedPetsc & other) = delete; 83 : WrappedPetsc & operator= (const WrappedPetsc &) = delete; 84 : 85 : /** 86 : * Move constructor. We could almost default this, but we need to 87 : * set other.obj to nullptr so that when it is subsequently 88 : * Destroy()ed it's just a no-op rather than messing up the 89 : * reference count or trying to double-free memory. 90 : */ 91 0 : WrappedPetsc(WrappedPetsc && other) noexcept 92 0 : : obj(other.obj) 93 : { 94 0 : other.obj = nullptr; 95 0 : } 96 : 97 : /** 98 : * Move-assignment operator. Use move-construct-and-swap idiom 99 : * instead of defaulting since we want to make sure our move 100 : * constructor leaves the passed-in object in a Destroy()able state. 101 : */ 102 : WrappedPetsc & operator= (WrappedPetsc && other) noexcept 103 : { 104 : WrappedPetsc tmp(std::move(other)); 105 : std::swap(tmp, *this); 106 : return *this; 107 : } 108 : 109 : /** 110 : * \returns pointer to the managed object 111 : * This is used to mimic code such as: 112 : * KSP ksp; 113 : * KSPCreate(comm, &ksp); 114 : * Since taking the address of the wrapping object doesn't make 115 : * sense in this context. 116 : */ 117 90549 : T * get() { return &obj; } 118 : 119 : /** 120 : * User-defined conversion function. We provide non-const access to 121 : * the underlying T object even when the "this" object is considered 122 : * const, since PETSc APIs which are "logically const" typically 123 : * still take non-const parameters. 124 : */ 125 4703570 : operator T() const { return obj; } 126 : 127 : /** 128 : * The "dereferencing" operator. Returns a reference to the managed 129 : * object. This is needed for some situations in which the 130 : * user-defined conversion operator doesn't work, for example with 131 : * C-style casts: 132 : * KSP ksp; 133 : * ... 134 : * PetscObjectSetOptionsPrefix((PetscObject)(*ksp), "balance_"); 135 : */ 136 1176 : T & operator*() { return obj; } 137 : 138 : /** 139 : * User-defined conversion to bool. This is intended to mimic code like: 140 : * IS is = nullptr; 141 : * ... 142 : * if (!is) 143 : * ... 144 : * Note that this comparison is thus concerned with obj itself and 145 : * not &obj. 146 : */ 147 1299032 : operator bool() const { return obj != nullptr; } 148 : 149 : /** 150 : * Must be specialized to call the appropriate XXXDestroy() routine 151 : * in order for a WrappedPetsc<T> object to be instantiated. 152 : * 153 : * We could try to do extra error checking in destroy() as shown 154 : * below, but note that: 155 : * 1.) destroy() is called from destructors, sometimes during 156 : * stack unwinding. If there's an error code returned from 157 : * XXXDestroy(), then our only option is to immediately terminate 158 : * the program, which would then kill any chance of recovering from 159 : * the exception. 160 : * 2.) It's not always safe to call non-Destroy() functions on PETSc objects 161 : * which are about to be Destroy()ed, that is, we would have to check 162 : * for nullptr, etc. which would lead to more complexity, and more code. 163 : * 164 : * One possible approach for extra error checking with immediate 165 : * abort on error: 166 : * 167 : * MPI_Comm comm; 168 : * PetscObjectGetComm((PetscObject)(&obj), &comm); 169 : * PetscErrorCode ierr = Type ## Destroy(&obj); 170 : * CHKERRABORT(comm, ierr); 171 : */ 172 : void destroy(); 173 : 174 : private: 175 : T obj; 176 : }; 177 : 178 : } // namespace libMesh 179 : 180 : #endif // LIBMESH_HAVE_PETSC 181 : 182 : #endif