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