1 2 /* 3 Mechanism for register PETSc matrix types 4 */ 5 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 6 7 PetscBool MatRegisterAllCalled = PETSC_FALSE; 8 9 /* 10 Contains the list of registered Mat routines 11 */ 12 PetscFunctionList MatList = NULL; 13 14 /* MatGetRootType_Private - Gets the root type of the input matrix's type (e.g., MATAIJ for MATSEQAIJ) 15 16 Not Collective 17 18 Input Parameters: 19 . mat - the input matrix, could be sequential or MPI 20 21 Output Parameters: 22 . rootType - the root matrix type 23 24 Level: developer 25 26 .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat` 27 */ 28 PetscErrorCode MatGetRootType_Private(Mat mat, MatType *rootType) { 29 PetscBool found = PETSC_FALSE; 30 MatRootName names = MatRootNameList; 31 MatType inType; 32 33 PetscFunctionBegin; 34 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 35 PetscCall(MatGetType(mat, &inType)); 36 while (names) { 37 PetscCall(PetscStrcmp(inType, names->mname, &found)); 38 if (!found) PetscCall(PetscStrcmp(inType, names->sname, &found)); 39 if (found) { 40 found = PETSC_TRUE; 41 *rootType = names->rname; 42 break; 43 } 44 names = names->next; 45 } 46 if (!found) *rootType = inType; 47 PetscFunctionReturn(0); 48 } 49 50 /* MatGetMPIMatType_Private - Gets the MPI type corresponding to the input matrix's type (e.g., MATMPIAIJ for MATSEQAIJ) 51 52 Not Collective 53 54 Input Parameters: 55 . mat - the input matrix, could be sequential or MPI 56 57 Output Parameters: 58 . MPIType - the parallel (MPI) matrix type 59 60 Level: developer 61 62 .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat` 63 */ 64 PetscErrorCode MatGetMPIMatType_Private(Mat mat, MatType *MPIType) { 65 PetscBool found = PETSC_FALSE; 66 MatRootName names = MatRootNameList; 67 MatType inType; 68 69 PetscFunctionBegin; 70 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 71 PetscCall(MatGetType(mat, &inType)); 72 while (names) { 73 PetscCall(PetscStrcmp(inType, names->sname, &found)); 74 if (!found) PetscCall(PetscStrcmp(inType, names->mname, &found)); 75 if (!found) PetscCall(PetscStrcmp(inType, names->rname, &found)); 76 if (found) { 77 found = PETSC_TRUE; 78 *MPIType = names->mname; 79 break; 80 } 81 names = names->next; 82 } 83 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_SUP, "No corresponding parallel (MPI) type for this matrix"); 84 PetscFunctionReturn(0); 85 } 86 87 /*@C 88 MatSetType - Builds matrix object for a particular matrix type 89 90 Collective on Mat 91 92 Input Parameters: 93 + mat - the matrix object 94 - matype - matrix type 95 96 Options Database Key: 97 . -mat_type <method> - Sets the type; use -help for a list 98 of available methods (for instance, seqaij) 99 100 Notes: 101 See "${PETSC_DIR}/include/petscmat.h" for available methods 102 103 Level: intermediate 104 105 .seealso: `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat` 106 @*/ 107 PetscErrorCode MatSetType(Mat mat, MatType matype) { 108 PetscBool sametype, found, subclass = PETSC_FALSE; 109 MatRootName names = MatRootNameList; 110 PetscErrorCode (*r)(Mat); 111 112 PetscFunctionBegin; 113 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 114 115 while (names) { 116 PetscCall(PetscStrcmp(matype, names->rname, &found)); 117 if (found) { 118 PetscMPIInt size; 119 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size)); 120 if (size == 1) matype = names->sname; 121 else matype = names->mname; 122 break; 123 } 124 names = names->next; 125 } 126 127 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 128 if (sametype) PetscFunctionReturn(0); 129 130 PetscCall(PetscFunctionListFind(MatList, matype, &r)); 131 PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 132 133 if (mat->assembled && ((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(matype, ((PetscObject)mat)->type_name, &subclass)); 134 if (subclass) { 135 PetscCall(MatConvert(mat, matype, MAT_INPLACE_MATRIX, &mat)); 136 PetscFunctionReturn(0); 137 } 138 PetscTryTypeMethod(mat, destroy); 139 mat->ops->destroy = NULL; 140 141 /* should these null spaces be removed? */ 142 PetscCall(MatNullSpaceDestroy(&mat->nullsp)); 143 PetscCall(MatNullSpaceDestroy(&mat->nearnullsp)); 144 145 PetscCall(PetscMemzero(mat->ops, sizeof(struct _MatOps))); 146 mat->preallocated = PETSC_FALSE; 147 mat->assembled = PETSC_FALSE; 148 mat->was_assembled = PETSC_FALSE; 149 150 /* 151 Increment, rather than reset these: the object is logically the same, so its logging and 152 state is inherited. Furthermore, resetting makes it possible for the same state to be 153 obtained with a different structure, confusing the PC. 154 */ 155 mat->nonzerostate++; 156 PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 157 158 /* create the new data structure */ 159 PetscCall((*r)(mat)); 160 PetscFunctionReturn(0); 161 } 162 163 /*@C 164 MatGetType - Gets the matrix type as a string from the matrix object. 165 166 Not Collective 167 168 Input Parameter: 169 . mat - the matrix 170 171 Output Parameter: 172 . name - name of matrix type 173 174 Level: intermediate 175 176 .seealso: `MatSetType()` 177 @*/ 178 PetscErrorCode MatGetType(Mat mat, MatType *type) { 179 PetscFunctionBegin; 180 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 181 PetscValidPointer(type, 2); 182 *type = ((PetscObject)mat)->type_name; 183 PetscFunctionReturn(0); 184 } 185 186 /*@C 187 MatGetVecType - Gets the vector type used by the matrix object. 188 189 Not Collective 190 191 Input Parameter: 192 . mat - the matrix 193 194 Output Parameter: 195 . name - name of vector type 196 197 Level: intermediate 198 199 .seealso: `MatSetVecType()` 200 @*/ 201 PetscErrorCode MatGetVecType(Mat mat, VecType *vtype) { 202 PetscFunctionBegin; 203 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 204 PetscValidPointer(vtype, 2); 205 *vtype = mat->defaultvectype; 206 PetscFunctionReturn(0); 207 } 208 209 /*@C 210 MatSetVecType - Set the vector type to be used for a matrix object 211 212 Collective on Mat 213 214 Input Parameters: 215 + mat - the matrix object 216 - vtype - vector type 217 218 Notes: 219 This is rarely needed in practice since each matrix object internally sets the proper vector type. 220 221 Level: intermediate 222 223 .seealso: `VecSetType()`, `MatGetVecType()` 224 @*/ 225 PetscErrorCode MatSetVecType(Mat mat, VecType vtype) { 226 PetscFunctionBegin; 227 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 228 PetscCall(PetscFree(mat->defaultvectype)); 229 PetscCall(PetscStrallocpy(vtype, &mat->defaultvectype)); 230 PetscFunctionReturn(0); 231 } 232 233 /*@C 234 MatRegister - - Adds a new matrix type 235 236 Not Collective 237 238 Input Parameters: 239 + name - name of a new user-defined matrix type 240 - routine_create - routine to create method context 241 242 Notes: 243 MatRegister() may be called multiple times to add several user-defined solvers. 244 245 Sample usage: 246 .vb 247 MatRegister("my_mat",MyMatCreate); 248 .ve 249 250 Then, your solver can be chosen with the procedural interface via 251 $ MatSetType(Mat,"my_mat") 252 or at runtime via the option 253 $ -mat_type my_mat 254 255 Level: advanced 256 257 .seealso: `MatRegisterAll()` 258 259 Level: advanced 260 @*/ 261 PetscErrorCode MatRegister(const char sname[], PetscErrorCode (*function)(Mat)) { 262 PetscFunctionBegin; 263 PetscCall(MatInitializePackage()); 264 PetscCall(PetscFunctionListAdd(&MatList, sname, function)); 265 PetscFunctionReturn(0); 266 } 267 268 MatRootName MatRootNameList = NULL; 269 270 /*@C 271 MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type. MatSetType() 272 and -mat_type will automatically use the sequential or parallel version based on the size of the MPI communicator associated with the 273 matrix. 274 275 Input Parameters: 276 + rname - the rootname, for example, MATAIJ 277 . sname - the name of the sequential matrix type, for example, MATSEQAIJ 278 - mname - the name of the parallel matrix type, for example, MATMPIAIJ 279 280 Notes: The matrix rootname should not be confused with the base type of the function PetscObjectBaseTypeCompare() 281 282 Developer Notes: PETSc vectors have a similar rootname that indicates PETSc should automatically select the appropriate VecType based on the 283 size of the communicator but it is implemented by simply having additional VecCreate_RootName() registerer routines that dispatch to the 284 appropriate creation routine. Why have two different ways of implementing the same functionality for different types of objects? It is 285 confusing. 286 287 Level: developer 288 289 .seealso: `PetscObjectBaseTypeCompare()` 290 291 @*/ 292 PetscErrorCode MatRegisterRootName(const char rname[], const char sname[], const char mname[]) { 293 MatRootName names; 294 295 PetscFunctionBegin; 296 PetscCall(PetscNew(&names)); 297 PetscCall(PetscStrallocpy(rname, &names->rname)); 298 PetscCall(PetscStrallocpy(sname, &names->sname)); 299 PetscCall(PetscStrallocpy(mname, &names->mname)); 300 if (!MatRootNameList) { 301 MatRootNameList = names; 302 } else { 303 MatRootName next = MatRootNameList; 304 while (next->next) next = next->next; 305 next->next = names; 306 } 307 PetscFunctionReturn(0); 308 } 309