xref: /petsc/src/mat/interface/matreg.c (revision df4cd43f92eaa320656440c40edb1046daee8f75)
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