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