xref: /petsc/src/mat/interface/matreg.c (revision dfbbaf821b4c49d07b4ce746493b0d955783fdf9)
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   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: `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 used by the matrix object.
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: `MatSetVecType()`
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 to be used for a matrix object
216 
217    Collective on Mat
218 
219    Input Parameters:
220 +  mat   - the matrix object
221 -  vtype - vector type
222 
223    Notes:
224      This is rarely needed in practice since each matrix object internally sets the proper vector type.
225 
226   Level: intermediate
227 
228 .seealso: `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    Notes:
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: `MatRegisterAll()`
264 
265   Level: advanced
266 @*/
267 PetscErrorCode  MatRegister(const char sname[],PetscErrorCode (*function)(Mat))
268 {
269   PetscFunctionBegin;
270   PetscCall(MatInitializePackage());
271   PetscCall(PetscFunctionListAdd(&MatList,sname,function));
272   PetscFunctionReturn(0);
273 }
274 
275 MatRootName MatRootNameList = NULL;
276 
277 /*@C
278       MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type. MatSetType()
279         and -mat_type will automatically use the sequential or parallel version based on the size of the MPI communicator associated with the
280         matrix.
281 
282   Input Parameters:
283 +     rname - the rootname, for example, MATAIJ
284 .     sname - the name of the sequential matrix type, for example, MATSEQAIJ
285 -     mname - the name of the parallel matrix type, for example, MATMPIAIJ
286 
287   Notes: The matrix rootname should not be confused with the base type of the function PetscObjectBaseTypeCompare()
288 
289   Developer Notes: 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: `PetscObjectBaseTypeCompare()`
297 
298 @*/
299 PetscErrorCode  MatRegisterRootName(const char rname[],const char sname[],const char mname[])
300 {
301   MatRootName    names;
302 
303   PetscFunctionBegin;
304   PetscCall(PetscNew(&names));
305   PetscCall(PetscStrallocpy(rname,&names->rname));
306   PetscCall(PetscStrallocpy(sname,&names->sname));
307   PetscCall(PetscStrallocpy(mname,&names->mname));
308   if (!MatRootNameList) {
309     MatRootNameList = names;
310   } else {
311     MatRootName next = MatRootNameList;
312     while (next->next) next = next->next;
313     next->next = names;
314   }
315   PetscFunctionReturn(0);
316 }
317