xref: /petsc/src/mat/interface/matreg.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
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 
182c99ec25SJunchao Zhang    Input Parameters:
192c99ec25SJunchao Zhang .  mat      - the input matrix, could be sequential or MPI
202c99ec25SJunchao Zhang 
212c99ec25SJunchao Zhang    Output Parameters:
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;
482c99ec25SJunchao Zhang   PetscFunctionReturn(0);
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 
55ac81f253SRichard Tran Mills    Input Parameters:
56ac81f253SRichard Tran Mills .  mat      - the input matrix, could be sequential or MPI
57ac81f253SRichard Tran Mills 
58ac81f253SRichard Tran Mills    Output Parameters:
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");
86ac81f253SRichard Tran Mills   PetscFunctionReturn(0);
87ac81f253SRichard Tran Mills }
88ac81f253SRichard Tran Mills 
897e14e8a7SBarry Smith /*@C
9099cd5145SBarry Smith    MatSetType - Builds matrix object for a particular matrix type
917e14e8a7SBarry Smith 
92*c3339decSBarry 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:
9999cd5145SBarry Smith .  -mat_type  <method> - Sets the type; use -help for a list
10099cd5145SBarry Smith     of available methods (for instance, seqaij)
1017e14e8a7SBarry Smith 
10211a5261eSBarry Smith    Note:
10399cd5145SBarry Smith    See "${PETSC_DIR}/include/petscmat.h" for available methods
1047e14e8a7SBarry Smith 
1057e14e8a7SBarry Smith   Level: intermediate
1067e14e8a7SBarry Smith 
107db781477SPatrick Sanan .seealso: `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat`
1087e14e8a7SBarry Smith @*/
109d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetType(Mat mat, MatType matype)
110d71ae5a4SJacob Faibussowitsch {
111a0bcfa1fSJunchao Zhang   PetscBool   sametype, found, subclass = PETSC_FALSE, matMPI = PETSC_FALSE, requestSeq = PETSC_FALSE;
11223bebc0bSBarry Smith   MatRootName names = MatRootNameList;
1135f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(Mat);
1147e14e8a7SBarry Smith 
1157e14e8a7SBarry Smith   PetscFunctionBegin;
1160700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
117117016b1SBarry Smith 
118a0bcfa1fSJunchao Zhang   /* suppose with one MPI process, one created an MPIAIJ (mpiaij) matrix with MatCreateMPIAIJWithArrays(), and later tried
119a0bcfa1fSJunchao Zhang      to change its type via '-mat_type aijcusparse'. Even there is only one MPI rank, we need to adapt matype to
120a0bcfa1fSJunchao Zhang      'mpiaijcusparse' so that it will be treated as a subclass of MPIAIJ and proper MatCovert() will be called.
121a0bcfa1fSJunchao Zhang   */
122a0bcfa1fSJunchao Zhang   if (((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(((PetscObject)mat)->type_name, "mpi", &matMPI)); /* mat claims itself is an 'mpi' matrix */
123a0bcfa1fSJunchao Zhang   if (matype) PetscCall(PetscStrbeginswith(matype, "seq", &requestSeq));                                           /* user is requesting a 'seq' matrix */
124a0bcfa1fSJunchao 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);
125a0bcfa1fSJunchao Zhang 
12601bebe75SBarry Smith   while (names) {
1279566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(matype, names->rname, &found));
12801bebe75SBarry Smith     if (found) {
12901bebe75SBarry Smith       PetscMPIInt size;
1309566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
131a0bcfa1fSJunchao Zhang       if (size == 1 && !matMPI) matype = names->sname; /* try to align the requested type (matype) with the existing type per seq/mpi */
13201bebe75SBarry Smith       else matype = names->mname;
13301bebe75SBarry Smith       break;
13401bebe75SBarry Smith     }
13501bebe75SBarry Smith     names = names->next;
13601bebe75SBarry Smith   }
13701bebe75SBarry Smith 
1389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype));
13992ff6ae8SBarry Smith   if (sametype) PetscFunctionReturn(0);
14092ff6ae8SBarry Smith 
1419566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(MatList, matype, &r));
1425f80ce2aSJacob Faibussowitsch   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype);
1437e14e8a7SBarry Smith 
1449566063dSJacob Faibussowitsch   if (mat->assembled && ((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(matype, ((PetscObject)mat)->type_name, &subclass));
145a0bcfa1fSJunchao Zhang   if (subclass) { /* mat is a subclass of the requested 'matype'? */
1469566063dSJacob Faibussowitsch     PetscCall(MatConvert(mat, matype, MAT_INPLACE_MATRIX, &mat));
1473dcd2dd8SBarry Smith     PetscFunctionReturn(0);
14828fc0bbcSJose E. Roman   }
149dbbe0bcdSBarry Smith   PetscTryTypeMethod(mat, destroy);
1500298fd71SBarry Smith   mat->ops->destroy = NULL;
15182e0f345SBarry Smith 
15232e7c8b0SBarry Smith   /* should these null spaces be removed? */
1539566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
1549566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
155dbbe0bcdSBarry Smith 
1569566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(mat->ops, sizeof(struct _MatOps)));
15782e0f345SBarry Smith   mat->preallocated  = PETSC_FALSE;
15882e0f345SBarry Smith   mat->assembled     = PETSC_FALSE;
15982e0f345SBarry Smith   mat->was_assembled = PETSC_FALSE;
16082e0f345SBarry Smith 
16182e0f345SBarry Smith   /*
16282e0f345SBarry Smith    Increment, rather than reset these: the object is logically the same, so its logging and
16382e0f345SBarry Smith    state is inherited.  Furthermore, resetting makes it possible for the same state to be
16482e0f345SBarry Smith    obtained with a different structure, confusing the PC.
16582e0f345SBarry Smith   */
16632e7c8b0SBarry Smith   mat->nonzerostate++;
1679566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
168a2ec6df8SKris Buschelman 
16935d8aa7fSBarry Smith   /* create the new data structure */
1709566063dSJacob Faibussowitsch   PetscCall((*r)(mat));
1717e14e8a7SBarry Smith   PetscFunctionReturn(0);
1727e14e8a7SBarry Smith }
1737e14e8a7SBarry Smith 
1747e14e8a7SBarry Smith /*@C
175f87b78b8SBarry Smith    MatGetType - Gets the matrix type as a string from the matrix object.
1767e14e8a7SBarry Smith 
1777e14e8a7SBarry Smith    Not Collective
1787e14e8a7SBarry Smith 
1797e14e8a7SBarry Smith    Input Parameter:
18099cd5145SBarry Smith .  mat - the matrix
1817e14e8a7SBarry Smith 
1827e14e8a7SBarry Smith    Output Parameter:
18399cd5145SBarry Smith .  name - name of matrix type
1847e14e8a7SBarry Smith 
1857e14e8a7SBarry Smith    Level: intermediate
1867e14e8a7SBarry Smith 
18711a5261eSBarry Smith .seealso: `MatType`, `MatSetType()`
1887e14e8a7SBarry Smith @*/
189d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetType(Mat mat, MatType *type)
190d71ae5a4SJacob Faibussowitsch {
1917e14e8a7SBarry Smith   PetscFunctionBegin;
1920700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
193c4e43342SLisandro Dalcin   PetscValidPointer(type, 2);
1947adad957SLisandro Dalcin   *type = ((PetscObject)mat)->type_name;
1957e14e8a7SBarry Smith   PetscFunctionReturn(0);
1967e14e8a7SBarry Smith }
1977e14e8a7SBarry Smith 
1980d229a57SStefano Zampini /*@C
19911a5261eSBarry Smith    MatGetVecType - Gets the vector type the matrix will return with `MatCreateVecs()`
2000d229a57SStefano Zampini 
2010d229a57SStefano Zampini    Not Collective
2020d229a57SStefano Zampini 
2030d229a57SStefano Zampini    Input Parameter:
2040d229a57SStefano Zampini .  mat - the matrix
2050d229a57SStefano Zampini 
2060d229a57SStefano Zampini    Output Parameter:
2070d229a57SStefano Zampini .  name - name of vector type
2080d229a57SStefano Zampini 
2090d229a57SStefano Zampini    Level: intermediate
2100d229a57SStefano Zampini 
21111a5261eSBarry Smith .seealso: `MatType`, `Mat`, `MatSetVecType()`, `VecType`
2120d229a57SStefano Zampini @*/
213d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetVecType(Mat mat, VecType *vtype)
214d71ae5a4SJacob Faibussowitsch {
2150d229a57SStefano Zampini   PetscFunctionBegin;
2160d229a57SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2170d229a57SStefano Zampini   PetscValidPointer(vtype, 2);
2180d229a57SStefano Zampini   *vtype = mat->defaultvectype;
2190d229a57SStefano Zampini   PetscFunctionReturn(0);
2200d229a57SStefano Zampini }
2210d229a57SStefano Zampini 
2220d229a57SStefano Zampini /*@C
22311a5261eSBarry Smith    MatSetVecType - Set the vector type the matrix will return with `MatCreateVecs()`
2240d229a57SStefano Zampini 
225*c3339decSBarry Smith    Collective
2260d229a57SStefano Zampini 
2270d229a57SStefano Zampini    Input Parameters:
2280d229a57SStefano Zampini +  mat   - the matrix object
2290d229a57SStefano Zampini -  vtype - vector type
2300d229a57SStefano Zampini 
23111a5261eSBarry Smith    Note:
2320d229a57SStefano Zampini      This is rarely needed in practice since each matrix object internally sets the proper vector type.
2330d229a57SStefano Zampini 
2340d229a57SStefano Zampini   Level: intermediate
2350d229a57SStefano Zampini 
23611a5261eSBarry Smith .seealso: `VecType`, `VecSetType()`, `MatGetVecType()`
2370d229a57SStefano Zampini @*/
238d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetVecType(Mat mat, VecType vtype)
239d71ae5a4SJacob Faibussowitsch {
2400d229a57SStefano Zampini   PetscFunctionBegin;
2410d229a57SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2429566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
2439566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, &mat->defaultvectype));
2440d229a57SStefano Zampini   PetscFunctionReturn(0);
2450d229a57SStefano Zampini }
2467e14e8a7SBarry Smith 
2473cea93caSBarry Smith /*@C
2481c84c290SBarry Smith   MatRegister -  - Adds a new matrix type
2491c84c290SBarry Smith 
2501c84c290SBarry Smith    Not Collective
2511c84c290SBarry Smith 
2521c84c290SBarry Smith    Input Parameters:
2531c84c290SBarry Smith +  name - name of a new user-defined matrix type
2541c84c290SBarry Smith -  routine_create - routine to create method context
2551c84c290SBarry Smith 
25611a5261eSBarry Smith    Note:
25711a5261eSBarry Smith    `MatRegister()` may be called multiple times to add several user-defined solvers.
2581c84c290SBarry Smith 
2591c84c290SBarry Smith    Sample usage:
2601c84c290SBarry Smith .vb
261bdf89e91SBarry Smith    MatRegister("my_mat",MyMatCreate);
2621c84c290SBarry Smith .ve
2631c84c290SBarry Smith 
2641c84c290SBarry Smith    Then, your solver can be chosen with the procedural interface via
2651c84c290SBarry Smith $     MatSetType(Mat,"my_mat")
2661c84c290SBarry Smith    or at runtime via the option
2671c84c290SBarry Smith $     -mat_type my_mat
2681c84c290SBarry Smith 
2691c84c290SBarry Smith    Level: advanced
2701c84c290SBarry Smith 
27111a5261eSBarry Smith .seealso: `Mat`, `MatType`, `MatSetType()`, `MatRegisterAll()`
2723cea93caSBarry Smith @*/
273d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegister(const char sname[], PetscErrorCode (*function)(Mat))
274d71ae5a4SJacob Faibussowitsch {
2757e14e8a7SBarry Smith   PetscFunctionBegin;
2769566063dSJacob Faibussowitsch   PetscCall(MatInitializePackage());
2779566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&MatList, sname, function));
27899cd5145SBarry Smith   PetscFunctionReturn(0);
27999cd5145SBarry Smith }
28099cd5145SBarry Smith 
281f4259b30SLisandro Dalcin MatRootName MatRootNameList = NULL;
28201bebe75SBarry Smith 
28301bebe75SBarry Smith /*@C
28411a5261eSBarry Smith       MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type. `MatSetType()`
28523bebc0bSBarry Smith         and -mat_type will automatically use the sequential or parallel version based on the size of the MPI communicator associated with the
28623bebc0bSBarry Smith         matrix.
28701bebe75SBarry Smith 
28801bebe75SBarry Smith   Input Parameters:
28911a5261eSBarry Smith +     rname - the rootname, for example, `MATAIJ`
29011a5261eSBarry Smith .     sname - the name of the sequential matrix type, for example, `MATSEQAIJ`
29111a5261eSBarry Smith -     mname - the name of the parallel matrix type, for example, `MATMPIAIJ`
29201bebe75SBarry Smith 
29311a5261eSBarry Smith   Note:
29411a5261eSBarry Smith   The matrix rootname should not be confused with the base type of the function `PetscObjectBaseTypeCompare()`
29501bebe75SBarry Smith 
29611a5261eSBarry Smith   Developer Note:
29711a5261eSBarry Smith   PETSc vectors have a similar rootname that indicates PETSc should automatically select the appropriate `VecType` based on the
29811a5261eSBarry Smith       size of the communicator but it is implemented by simply having additional `VecCreate_RootName()` registerer routines that dispatch to the
29923bebc0bSBarry Smith       appropriate creation routine. Why have two different ways of implementing the same functionality for different types of objects? It is
30023bebc0bSBarry Smith       confusing.
30123bebc0bSBarry Smith 
30223bebc0bSBarry Smith   Level: developer
30323bebc0bSBarry Smith 
30411a5261eSBarry Smith .seealso: `Mat`, `MatType`, `PetscObjectBaseTypeCompare()`
30501bebe75SBarry Smith @*/
306d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegisterRootName(const char rname[], const char sname[], const char mname[])
307d71ae5a4SJacob Faibussowitsch {
30823bebc0bSBarry Smith   MatRootName names;
30901bebe75SBarry Smith 
31001bebe75SBarry Smith   PetscFunctionBegin;
3119566063dSJacob Faibussowitsch   PetscCall(PetscNew(&names));
3129566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rname, &names->rname));
3139566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(sname, &names->sname));
3149566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mname, &names->mname));
31523bebc0bSBarry Smith   if (!MatRootNameList) {
31623bebc0bSBarry Smith     MatRootNameList = names;
31701bebe75SBarry Smith   } else {
31823bebc0bSBarry Smith     MatRootName next = MatRootNameList;
31901bebe75SBarry Smith     while (next->next) next = next->next;
32001bebe75SBarry Smith     next->next = names;
32101bebe75SBarry Smith   }
32201bebe75SBarry Smith   PetscFunctionReturn(0);
32301bebe75SBarry Smith }
324