xref: /petsc/src/mat/interface/matreg.c (revision 2920cce0f08e88ce102428b9df84f61867de9dc8)
1be1d678aSKris Buschelman 
27e14e8a7SBarry Smith /*
399cd5145SBarry Smith      Mechanism for register PETSc matrix types
47e14e8a7SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
67e14e8a7SBarry Smith 
7ace3abfcSBarry Smith PetscBool MatRegisterAllCalled = PETSC_FALSE;
87e14e8a7SBarry Smith 
97e14e8a7SBarry Smith /*
1099cd5145SBarry Smith    Contains the list of registered Mat routines
117e14e8a7SBarry Smith */
12f4259b30SLisandro Dalcin PetscFunctionList MatList = NULL;
137e14e8a7SBarry Smith 
142c99ec25SJunchao Zhang /* MatGetRootType_Private - Gets the root type of the input matrix's type (e.g., MATAIJ for MATSEQAIJ)
152c99ec25SJunchao Zhang 
162c99ec25SJunchao Zhang    Not Collective
172c99ec25SJunchao Zhang 
182fe279fdSBarry Smith    Input Parameter:
192c99ec25SJunchao Zhang .  mat      - the input matrix, could be sequential or MPI
202c99ec25SJunchao Zhang 
212fe279fdSBarry Smith    Output Parameter:
222c99ec25SJunchao Zhang .  rootType  - the root matrix type
232c99ec25SJunchao Zhang 
242c99ec25SJunchao Zhang    Level: developer
252c99ec25SJunchao Zhang 
26db781477SPatrick Sanan .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat`
272c99ec25SJunchao Zhang */
28d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetRootType_Private(Mat mat, MatType *rootType)
29d71ae5a4SJacob Faibussowitsch {
302c99ec25SJunchao Zhang   PetscBool   found = PETSC_FALSE;
312c99ec25SJunchao Zhang   MatRootName names = MatRootNameList;
322c99ec25SJunchao Zhang   MatType     inType;
332c99ec25SJunchao Zhang 
342c99ec25SJunchao Zhang   PetscFunctionBegin;
352c99ec25SJunchao Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
369566063dSJacob Faibussowitsch   PetscCall(MatGetType(mat, &inType));
372c99ec25SJunchao Zhang   while (names) {
389566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(inType, names->mname, &found));
399566063dSJacob Faibussowitsch     if (!found) PetscCall(PetscStrcmp(inType, names->sname, &found));
402c99ec25SJunchao Zhang     if (found) {
412c99ec25SJunchao Zhang       found     = PETSC_TRUE;
422c99ec25SJunchao Zhang       *rootType = names->rname;
432c99ec25SJunchao Zhang       break;
442c99ec25SJunchao Zhang     }
452c99ec25SJunchao Zhang     names = names->next;
462c99ec25SJunchao Zhang   }
472c99ec25SJunchao Zhang   if (!found) *rootType = inType;
483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
492c99ec25SJunchao Zhang }
502c99ec25SJunchao Zhang 
51ac81f253SRichard Tran Mills /* MatGetMPIMatType_Private - Gets the MPI type corresponding to the input matrix's type (e.g., MATMPIAIJ for MATSEQAIJ)
52ac81f253SRichard Tran Mills 
53ac81f253SRichard Tran Mills    Not Collective
54ac81f253SRichard Tran Mills 
552fe279fdSBarry Smith    Input Parameter:
56ac81f253SRichard Tran Mills .  mat      - the input matrix, could be sequential or MPI
57ac81f253SRichard Tran Mills 
582fe279fdSBarry Smith    Output Parameter:
59ac81f253SRichard Tran Mills .  MPIType  - the parallel (MPI) matrix type
60ac81f253SRichard Tran Mills 
61ac81f253SRichard Tran Mills    Level: developer
62ac81f253SRichard Tran Mills 
63ac81f253SRichard Tran Mills .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat`
64ac81f253SRichard Tran Mills */
65d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetMPIMatType_Private(Mat mat, MatType *MPIType)
66d71ae5a4SJacob Faibussowitsch {
67ac81f253SRichard Tran Mills   PetscBool   found = PETSC_FALSE;
68ac81f253SRichard Tran Mills   MatRootName names = MatRootNameList;
69ac81f253SRichard Tran Mills   MatType     inType;
70ac81f253SRichard Tran Mills 
71ac81f253SRichard Tran Mills   PetscFunctionBegin;
72ac81f253SRichard Tran Mills   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
73ac81f253SRichard Tran Mills   PetscCall(MatGetType(mat, &inType));
74ac81f253SRichard Tran Mills   while (names) {
75ac81f253SRichard Tran Mills     PetscCall(PetscStrcmp(inType, names->sname, &found));
76ac81f253SRichard Tran Mills     if (!found) PetscCall(PetscStrcmp(inType, names->mname, &found));
77ac81f253SRichard Tran Mills     if (!found) PetscCall(PetscStrcmp(inType, names->rname, &found));
78ac81f253SRichard Tran Mills     if (found) {
79ac81f253SRichard Tran Mills       found    = PETSC_TRUE;
80ac81f253SRichard Tran Mills       *MPIType = names->mname;
81ac81f253SRichard Tran Mills       break;
82ac81f253SRichard Tran Mills     }
83ac81f253SRichard Tran Mills     names = names->next;
84ac81f253SRichard Tran Mills   }
85ac81f253SRichard Tran Mills   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_SUP, "No corresponding parallel (MPI) type for this matrix");
863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
87ac81f253SRichard Tran Mills }
88ac81f253SRichard Tran Mills 
897e14e8a7SBarry Smith /*@C
9099cd5145SBarry Smith   MatSetType - Builds matrix object for a particular matrix type
917e14e8a7SBarry Smith 
92c3339decSBarry Smith   Collective
937e14e8a7SBarry Smith 
947e14e8a7SBarry Smith   Input Parameters:
9599cd5145SBarry Smith + mat    - the matrix object
9699cd5145SBarry Smith - matype - matrix type
977e14e8a7SBarry Smith 
987e14e8a7SBarry Smith   Options Database Key:
992ef1f0ffSBarry Smith . -mat_type  <method> - Sets the type; see `MatType`
1007e14e8a7SBarry Smith 
1017e14e8a7SBarry Smith   Level: intermediate
1027e14e8a7SBarry Smith 
1032ef1f0ffSBarry Smith   Note:
1042ef1f0ffSBarry Smith   See `MatType` for possible values
1052ef1f0ffSBarry Smith 
106fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`
1077e14e8a7SBarry Smith @*/
108d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetType(Mat mat, MatType matype)
109d71ae5a4SJacob Faibussowitsch {
110a0bcfa1fSJunchao Zhang   PetscBool   sametype, found, subclass = PETSC_FALSE, matMPI = PETSC_FALSE, requestSeq = PETSC_FALSE;
11123bebc0bSBarry Smith   MatRootName names = MatRootNameList;
1125f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(Mat);
1137e14e8a7SBarry Smith 
1147e14e8a7SBarry Smith   PetscFunctionBegin;
1150700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
116117016b1SBarry Smith 
1179f3dd13dSJunchao Zhang   /* make this special case fast */
1189f3dd13dSJunchao Zhang   PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype));
1193ba16761SJacob Faibussowitsch   if (sametype) PetscFunctionReturn(PETSC_SUCCESS);
1209f3dd13dSJunchao Zhang 
121a0bcfa1fSJunchao Zhang   /* suppose with one MPI process, one created an MPIAIJ (mpiaij) matrix with MatCreateMPIAIJWithArrays(), and later tried
122a0bcfa1fSJunchao Zhang      to change its type via '-mat_type aijcusparse'. Even there is only one MPI rank, we need to adapt matype to
123a0bcfa1fSJunchao Zhang      'mpiaijcusparse' so that it will be treated as a subclass of MPIAIJ and proper MatCovert() will be called.
124a0bcfa1fSJunchao Zhang   */
125a0bcfa1fSJunchao Zhang   if (((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(((PetscObject)mat)->type_name, "mpi", &matMPI)); /* mat claims itself is an 'mpi' matrix */
126a0bcfa1fSJunchao Zhang   if (matype) PetscCall(PetscStrbeginswith(matype, "seq", &requestSeq));                                           /* user is requesting a 'seq' matrix */
127a0bcfa1fSJunchao Zhang   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);
128a0bcfa1fSJunchao Zhang 
12901bebe75SBarry Smith   while (names) {
1309566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(matype, names->rname, &found));
13101bebe75SBarry Smith     if (found) {
13201bebe75SBarry Smith       PetscMPIInt size;
1339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
134a0bcfa1fSJunchao Zhang       if (size == 1 && !matMPI) matype = names->sname; /* try to align the requested type (matype) with the existing type per seq/mpi */
13501bebe75SBarry Smith       else matype = names->mname;
13601bebe75SBarry Smith       break;
13701bebe75SBarry Smith     }
13801bebe75SBarry Smith     names = names->next;
13901bebe75SBarry Smith   }
14001bebe75SBarry Smith 
1419566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype));
1423ba16761SJacob Faibussowitsch   if (sametype) PetscFunctionReturn(PETSC_SUCCESS);
14392ff6ae8SBarry Smith 
1449566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(MatList, matype, &r));
1456adde796SStefano Zampini   PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype);
1467e14e8a7SBarry Smith 
1479566063dSJacob Faibussowitsch   if (mat->assembled && ((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(matype, ((PetscObject)mat)->type_name, &subclass));
148a0bcfa1fSJunchao Zhang   if (subclass) { /* mat is a subclass of the requested 'matype'? */
1499566063dSJacob Faibussowitsch     PetscCall(MatConvert(mat, matype, MAT_INPLACE_MATRIX, &mat));
1503ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
15128fc0bbcSJose E. Roman   }
152dbbe0bcdSBarry Smith   PetscTryTypeMethod(mat, destroy);
1530298fd71SBarry Smith   mat->ops->destroy = NULL;
15482e0f345SBarry Smith 
15532e7c8b0SBarry Smith   /* should these null spaces be removed? */
1569566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
1579566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
158dbbe0bcdSBarry Smith 
1599566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(mat->ops, sizeof(struct _MatOps)));
16082e0f345SBarry Smith   mat->preallocated  = PETSC_FALSE;
16182e0f345SBarry Smith   mat->assembled     = PETSC_FALSE;
16282e0f345SBarry Smith   mat->was_assembled = PETSC_FALSE;
16382e0f345SBarry Smith 
16482e0f345SBarry Smith   /*
16582e0f345SBarry Smith    Increment, rather than reset these: the object is logically the same, so its logging and
16682e0f345SBarry Smith    state is inherited.  Furthermore, resetting makes it possible for the same state to be
16782e0f345SBarry Smith    obtained with a different structure, confusing the PC.
16882e0f345SBarry Smith   */
16932e7c8b0SBarry Smith   mat->nonzerostate++;
1709566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
171a2ec6df8SKris Buschelman 
17235d8aa7fSBarry Smith   /* create the new data structure */
1739566063dSJacob Faibussowitsch   PetscCall((*r)(mat));
1743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1757e14e8a7SBarry Smith }
1767e14e8a7SBarry Smith 
1777e14e8a7SBarry Smith /*@C
178f87b78b8SBarry Smith   MatGetType - Gets the matrix type as a string from the matrix object.
1797e14e8a7SBarry Smith 
1807e14e8a7SBarry Smith   Not Collective
1817e14e8a7SBarry Smith 
1827e14e8a7SBarry Smith   Input Parameter:
18399cd5145SBarry Smith . mat - the matrix
1847e14e8a7SBarry Smith 
1857e14e8a7SBarry Smith   Output Parameter:
186fe59aa6dSJacob Faibussowitsch . type - name of matrix type
1877e14e8a7SBarry Smith 
1887e14e8a7SBarry Smith   Level: intermediate
1897e14e8a7SBarry Smith 
1901cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetType()`
1917e14e8a7SBarry Smith @*/
192d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetType(Mat mat, MatType *type)
193d71ae5a4SJacob Faibussowitsch {
1947e14e8a7SBarry Smith   PetscFunctionBegin;
1950700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
196c4e43342SLisandro Dalcin   PetscValidPointer(type, 2);
1977adad957SLisandro Dalcin   *type = ((PetscObject)mat)->type_name;
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1997e14e8a7SBarry Smith }
2007e14e8a7SBarry Smith 
2010d229a57SStefano Zampini /*@C
20211a5261eSBarry Smith   MatGetVecType - Gets the vector type the matrix will return with `MatCreateVecs()`
2030d229a57SStefano Zampini 
2040d229a57SStefano Zampini   Not Collective
2050d229a57SStefano Zampini 
2060d229a57SStefano Zampini   Input Parameter:
2070d229a57SStefano Zampini . mat - the matrix
2080d229a57SStefano Zampini 
2090d229a57SStefano Zampini   Output Parameter:
210fe59aa6dSJacob Faibussowitsch . vtype - name of vector type
2110d229a57SStefano Zampini 
2120d229a57SStefano Zampini   Level: intermediate
2130d229a57SStefano Zampini 
214fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetVecType()`, `VecType`
2150d229a57SStefano Zampini @*/
216d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetVecType(Mat mat, VecType *vtype)
217d71ae5a4SJacob Faibussowitsch {
2180d229a57SStefano Zampini   PetscFunctionBegin;
2190d229a57SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2200d229a57SStefano Zampini   PetscValidPointer(vtype, 2);
2210d229a57SStefano Zampini   *vtype = mat->defaultvectype;
2223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2230d229a57SStefano Zampini }
2240d229a57SStefano Zampini 
2250d229a57SStefano Zampini /*@C
22611a5261eSBarry Smith   MatSetVecType - Set the vector type the matrix will return with `MatCreateVecs()`
2270d229a57SStefano Zampini 
228c3339decSBarry Smith   Collective
2290d229a57SStefano Zampini 
2300d229a57SStefano Zampini   Input Parameters:
2310d229a57SStefano Zampini + mat   - the matrix object
2320d229a57SStefano Zampini - vtype - vector type
2330d229a57SStefano Zampini 
2342ef1f0ffSBarry Smith   Level: advanced
2352ef1f0ffSBarry Smith 
23611a5261eSBarry Smith   Note:
2370d229a57SStefano Zampini   This is rarely needed in practice since each matrix object internally sets the proper vector type.
2380d229a57SStefano Zampini 
2391cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `VecType`, `VecSetType()`, `MatGetVecType()`
2400d229a57SStefano Zampini @*/
241d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetVecType(Mat mat, VecType vtype)
242d71ae5a4SJacob Faibussowitsch {
2430d229a57SStefano Zampini   PetscFunctionBegin;
2440d229a57SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2459566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
2469566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, &mat->defaultvectype));
2473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2480d229a57SStefano Zampini }
2497e14e8a7SBarry Smith 
2503cea93caSBarry Smith /*@C
2512ef1f0ffSBarry Smith   MatRegister -  - Adds a new matrix type implementation
2521c84c290SBarry Smith 
2531c84c290SBarry Smith   Not Collective
2541c84c290SBarry Smith 
2551c84c290SBarry Smith   Input Parameters:
25667be906fSBarry Smith + sname    - name of a new user-defined matrix type
25767be906fSBarry Smith - function - routine to create method context
25867be906fSBarry Smith 
25967be906fSBarry Smith   Level: advanced
2601c84c290SBarry Smith 
26111a5261eSBarry Smith   Note:
26211a5261eSBarry Smith   `MatRegister()` may be called multiple times to add several user-defined solvers.
2631c84c290SBarry Smith 
264fe59aa6dSJacob Faibussowitsch   Example Usage:
2651c84c290SBarry Smith .vb
266bdf89e91SBarry Smith    MatRegister("my_mat", MyMatCreate);
2671c84c290SBarry Smith .ve
2681c84c290SBarry Smith 
2691c84c290SBarry Smith   Then, your solver can be chosen with the procedural interface via
2701c84c290SBarry Smith $     MatSetType(Mat, "my_mat")
2711c84c290SBarry Smith   or at runtime via the option
2721c84c290SBarry Smith $     -mat_type my_mat
2731c84c290SBarry Smith 
2741cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetType()`, `MatRegisterAll()`
2753cea93caSBarry Smith @*/
276d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegister(const char sname[], PetscErrorCode (*function)(Mat))
277d71ae5a4SJacob Faibussowitsch {
2787e14e8a7SBarry Smith   PetscFunctionBegin;
2799566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2809566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&MatList, sname, function));
2813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28299cd5145SBarry Smith }
28399cd5145SBarry Smith 
284f4259b30SLisandro Dalcin MatRootName MatRootNameList = NULL;
28501bebe75SBarry Smith 
28601bebe75SBarry Smith /*@C
287*2920cce0SJacob Faibussowitsch   MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type.
28801bebe75SBarry Smith 
28901bebe75SBarry Smith   Input Parameters:
29011a5261eSBarry Smith + rname - the rootname, for example, `MATAIJ`
29111a5261eSBarry Smith . sname - the name of the sequential matrix type, for example, `MATSEQAIJ`
29211a5261eSBarry Smith - mname - the name of the parallel matrix type, for example, `MATMPIAIJ`
29301bebe75SBarry Smith 
29467be906fSBarry Smith   Level: developer
29567be906fSBarry Smith 
296*2920cce0SJacob Faibussowitsch   Notes:
297*2920cce0SJacob Faibussowitsch   `MatSetType()` and `-mat_type name` will automatically use the sequential or parallel version
298*2920cce0SJacob Faibussowitsch   based on the size of the MPI communicator associated with the matrix.
299*2920cce0SJacob Faibussowitsch 
300*2920cce0SJacob Faibussowitsch   The matrix rootname should not be confused with the base type of the function
301*2920cce0SJacob Faibussowitsch   `PetscObjectBaseTypeCompare()`
30201bebe75SBarry Smith 
303fe59aa6dSJacob Faibussowitsch   Developer Notes:
30411a5261eSBarry Smith   PETSc vectors have a similar rootname that indicates PETSc should automatically select the appropriate `VecType` based on the
30511a5261eSBarry Smith   size of the communicator but it is implemented by simply having additional `VecCreate_RootName()` registerer routines that dispatch to the
30623bebc0bSBarry Smith   appropriate creation routine. Why have two different ways of implementing the same functionality for different types of objects? It is
30723bebc0bSBarry Smith   confusing.
30823bebc0bSBarry Smith 
3091cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `PetscObjectBaseTypeCompare()`
31001bebe75SBarry Smith @*/
311d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegisterRootName(const char rname[], const char sname[], const char mname[])
312d71ae5a4SJacob Faibussowitsch {
31323bebc0bSBarry Smith   MatRootName names;
31401bebe75SBarry Smith 
31501bebe75SBarry Smith   PetscFunctionBegin;
3169566063dSJacob Faibussowitsch   PetscCall(PetscNew(&names));
3179566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rname, &names->rname));
3189566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(sname, &names->sname));
3199566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mname, &names->mname));
32023bebc0bSBarry Smith   if (!MatRootNameList) {
32123bebc0bSBarry Smith     MatRootNameList = names;
32201bebe75SBarry Smith   } else {
32323bebc0bSBarry Smith     MatRootName next = MatRootNameList;
32401bebe75SBarry Smith     while (next->next) next = next->next;
32501bebe75SBarry Smith     next->next = names;
32601bebe75SBarry Smith   }
3273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32801bebe75SBarry Smith }
329