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