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