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