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