17e14e8a7SBarry Smith /* 299cd5145SBarry Smith Mechanism for register PETSc matrix types 37e14e8a7SBarry Smith */ 4af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 57e14e8a7SBarry Smith 6ace3abfcSBarry Smith PetscBool MatRegisterAllCalled = PETSC_FALSE; 77e14e8a7SBarry Smith 87e14e8a7SBarry Smith /* 999cd5145SBarry Smith Contains the list of registered Mat routines 107e14e8a7SBarry Smith */ 11f4259b30SLisandro Dalcin PetscFunctionList MatList = NULL; 127e14e8a7SBarry Smith 132c99ec25SJunchao Zhang /* MatGetRootType_Private - Gets the root type of the input matrix's type (e.g., MATAIJ for MATSEQAIJ) 142c99ec25SJunchao Zhang 152c99ec25SJunchao Zhang Not Collective 162c99ec25SJunchao Zhang 172fe279fdSBarry Smith Input Parameter: 182c99ec25SJunchao Zhang . mat - the input matrix, could be sequential or MPI 192c99ec25SJunchao Zhang 202fe279fdSBarry Smith Output Parameter: 212c99ec25SJunchao Zhang . rootType - the root matrix type 222c99ec25SJunchao Zhang 232c99ec25SJunchao Zhang Level: developer 242c99ec25SJunchao Zhang 25db781477SPatrick Sanan .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat` 262c99ec25SJunchao Zhang */ 27d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetRootType_Private(Mat mat, MatType *rootType) 28d71ae5a4SJacob Faibussowitsch { 292c99ec25SJunchao Zhang PetscBool found = PETSC_FALSE; 302c99ec25SJunchao Zhang MatRootName names = MatRootNameList; 312c99ec25SJunchao Zhang MatType inType; 322c99ec25SJunchao Zhang 332c99ec25SJunchao Zhang PetscFunctionBegin; 342c99ec25SJunchao Zhang PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 359566063dSJacob Faibussowitsch PetscCall(MatGetType(mat, &inType)); 362c99ec25SJunchao Zhang while (names) { 379566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(inType, names->mname, &found)); 389566063dSJacob Faibussowitsch if (!found) PetscCall(PetscStrcmp(inType, names->sname, &found)); 392c99ec25SJunchao Zhang if (found) { 402c99ec25SJunchao Zhang found = PETSC_TRUE; 412c99ec25SJunchao Zhang *rootType = names->rname; 422c99ec25SJunchao Zhang break; 432c99ec25SJunchao Zhang } 442c99ec25SJunchao Zhang names = names->next; 452c99ec25SJunchao Zhang } 462c99ec25SJunchao Zhang if (!found) *rootType = inType; 473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 482c99ec25SJunchao Zhang } 492c99ec25SJunchao Zhang 50ac81f253SRichard Tran Mills /* MatGetMPIMatType_Private - Gets the MPI type corresponding to the input matrix's type (e.g., MATMPIAIJ for MATSEQAIJ) 51ac81f253SRichard Tran Mills 52ac81f253SRichard Tran Mills Not Collective 53ac81f253SRichard Tran Mills 542fe279fdSBarry Smith Input Parameter: 55ac81f253SRichard Tran Mills . mat - the input matrix, could be sequential or MPI 56ac81f253SRichard Tran Mills 572fe279fdSBarry Smith Output Parameter: 58ac81f253SRichard Tran Mills . MPIType - the parallel (MPI) matrix type 59ac81f253SRichard Tran Mills 60ac81f253SRichard Tran Mills Level: developer 61ac81f253SRichard Tran Mills 62ac81f253SRichard Tran Mills .seealso: `MatGetType()`, `MatSetType()`, `MatType`, `Mat` 63ac81f253SRichard Tran Mills */ 64d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetMPIMatType_Private(Mat mat, MatType *MPIType) 65d71ae5a4SJacob Faibussowitsch { 66ac81f253SRichard Tran Mills PetscBool found = PETSC_FALSE; 67ac81f253SRichard Tran Mills MatRootName names = MatRootNameList; 68ac81f253SRichard Tran Mills MatType inType; 69ac81f253SRichard Tran Mills 70ac81f253SRichard Tran Mills PetscFunctionBegin; 71ac81f253SRichard Tran Mills PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 72ac81f253SRichard Tran Mills PetscCall(MatGetType(mat, &inType)); 73ac81f253SRichard Tran Mills while (names) { 74ac81f253SRichard Tran Mills PetscCall(PetscStrcmp(inType, names->sname, &found)); 75ac81f253SRichard Tran Mills if (!found) PetscCall(PetscStrcmp(inType, names->mname, &found)); 76ac81f253SRichard Tran Mills if (!found) PetscCall(PetscStrcmp(inType, names->rname, &found)); 77ac81f253SRichard Tran Mills if (found) { 78ac81f253SRichard Tran Mills found = PETSC_TRUE; 79ac81f253SRichard Tran Mills *MPIType = names->mname; 80ac81f253SRichard Tran Mills break; 81ac81f253SRichard Tran Mills } 82ac81f253SRichard Tran Mills names = names->next; 83ac81f253SRichard Tran Mills } 84ac81f253SRichard Tran Mills PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_SUP, "No corresponding parallel (MPI) type for this matrix"); 853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 86ac81f253SRichard Tran Mills } 87ac81f253SRichard Tran Mills 88cc4c1da9SBarry Smith /*@ 8999cd5145SBarry Smith MatSetType - Builds matrix object for a particular matrix type 907e14e8a7SBarry Smith 91c3339decSBarry Smith Collective 927e14e8a7SBarry Smith 937e14e8a7SBarry Smith Input Parameters: 9499cd5145SBarry Smith + mat - the matrix object 9599cd5145SBarry Smith - matype - matrix type 967e14e8a7SBarry Smith 977e14e8a7SBarry Smith Options Database Key: 982ef1f0ffSBarry Smith . -mat_type <method> - Sets the type; see `MatType` 997e14e8a7SBarry Smith 1007e14e8a7SBarry Smith Level: intermediate 1017e14e8a7SBarry Smith 1022ef1f0ffSBarry Smith Note: 1032ef1f0ffSBarry Smith See `MatType` for possible values 1042ef1f0ffSBarry Smith 105fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType` 1067e14e8a7SBarry Smith @*/ 107d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetType(Mat mat, MatType matype) 108d71ae5a4SJacob Faibussowitsch { 109a0bcfa1fSJunchao Zhang PetscBool sametype, found, subclass = PETSC_FALSE, matMPI = PETSC_FALSE, requestSeq = PETSC_FALSE; 11023bebc0bSBarry Smith MatRootName names = MatRootNameList; 1115f80ce2aSJacob Faibussowitsch PetscErrorCode (*r)(Mat); 1127e14e8a7SBarry Smith 1137e14e8a7SBarry Smith PetscFunctionBegin; 1140700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 115117016b1SBarry Smith 1169f3dd13dSJunchao Zhang /* make this special case fast */ 1179f3dd13dSJunchao Zhang PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 1183ba16761SJacob Faibussowitsch if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 1199f3dd13dSJunchao Zhang 120a0bcfa1fSJunchao Zhang /* suppose with one MPI process, one created an MPIAIJ (mpiaij) matrix with MatCreateMPIAIJWithArrays(), and later tried 121a0bcfa1fSJunchao Zhang to change its type via '-mat_type aijcusparse'. Even there is only one MPI rank, we need to adapt matype to 122a0bcfa1fSJunchao Zhang 'mpiaijcusparse' so that it will be treated as a subclass of MPIAIJ and proper MatCovert() will be called. 123a0bcfa1fSJunchao Zhang */ 124a0bcfa1fSJunchao Zhang if (((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(((PetscObject)mat)->type_name, "mpi", &matMPI)); /* mat claims itself is an 'mpi' matrix */ 125a0bcfa1fSJunchao Zhang if (matype) PetscCall(PetscStrbeginswith(matype, "seq", &requestSeq)); /* user is requesting a 'seq' matrix */ 126a0bcfa1fSJunchao 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); 127a0bcfa1fSJunchao Zhang 12801bebe75SBarry Smith while (names) { 1299566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(matype, names->rname, &found)); 13001bebe75SBarry Smith if (found) { 13101bebe75SBarry Smith PetscMPIInt size; 1329566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size)); 133a0bcfa1fSJunchao Zhang if (size == 1 && !matMPI) matype = names->sname; /* try to align the requested type (matype) with the existing type per seq/mpi */ 13401bebe75SBarry Smith else matype = names->mname; 13501bebe75SBarry Smith break; 13601bebe75SBarry Smith } 13701bebe75SBarry Smith names = names->next; 13801bebe75SBarry Smith } 13901bebe75SBarry Smith 1409566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 1413ba16761SJacob Faibussowitsch if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 14292ff6ae8SBarry Smith 1439566063dSJacob Faibussowitsch PetscCall(PetscFunctionListFind(MatList, matype, &r)); 1446adde796SStefano Zampini PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 1457e14e8a7SBarry Smith 1469566063dSJacob Faibussowitsch if (mat->assembled && ((PetscObject)mat)->type_name) PetscCall(PetscStrbeginswith(matype, ((PetscObject)mat)->type_name, &subclass)); 147a0bcfa1fSJunchao Zhang if (subclass) { /* mat is a subclass of the requested 'matype'? */ 1489566063dSJacob Faibussowitsch PetscCall(MatConvert(mat, matype, MAT_INPLACE_MATRIX, &mat)); 1493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15028fc0bbcSJose E. Roman } 151b79e0553SHong Zhang if (names && mat->assembled) { 152b79e0553SHong Zhang PetscCall(PetscStrbeginswith(names->rname, "sell", &sametype)); 153b79e0553SHong Zhang if (sametype) { /* mattype is MATSELL or its subclass */ 154b79e0553SHong Zhang PetscCall(MatConvert(mat, MATSELL, MAT_INPLACE_MATRIX, &mat)); /* convert to matsell first */ 155b79e0553SHong Zhang PetscCall(MatConvert(mat, matype, MAT_INPLACE_MATRIX, &mat)); 156b79e0553SHong Zhang PetscFunctionReturn(PETSC_SUCCESS); 157b79e0553SHong Zhang } 158b79e0553SHong Zhang } 159dbbe0bcdSBarry Smith PetscTryTypeMethod(mat, destroy); 1600298fd71SBarry Smith mat->ops->destroy = NULL; 16182e0f345SBarry Smith 16232e7c8b0SBarry Smith /* should these null spaces be removed? */ 1639566063dSJacob Faibussowitsch PetscCall(MatNullSpaceDestroy(&mat->nullsp)); 1649566063dSJacob Faibussowitsch PetscCall(MatNullSpaceDestroy(&mat->nearnullsp)); 165dbbe0bcdSBarry Smith 1669566063dSJacob Faibussowitsch PetscCall(PetscMemzero(mat->ops, sizeof(struct _MatOps))); 16782e0f345SBarry Smith mat->preallocated = PETSC_FALSE; 16882e0f345SBarry Smith mat->assembled = PETSC_FALSE; 16982e0f345SBarry Smith mat->was_assembled = PETSC_FALSE; 17082e0f345SBarry Smith 17182e0f345SBarry Smith /* 17282e0f345SBarry Smith Increment, rather than reset these: the object is logically the same, so its logging and 17382e0f345SBarry Smith state is inherited. Furthermore, resetting makes it possible for the same state to be 17482e0f345SBarry Smith obtained with a different structure, confusing the PC. 17582e0f345SBarry Smith */ 17632e7c8b0SBarry Smith mat->nonzerostate++; 1779566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 178a2ec6df8SKris Buschelman 17935d8aa7fSBarry Smith /* create the new data structure */ 1809566063dSJacob Faibussowitsch PetscCall((*r)(mat)); 1813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1827e14e8a7SBarry Smith } 1837e14e8a7SBarry Smith 184cc4c1da9SBarry Smith /*@ 185f87b78b8SBarry Smith MatGetType - Gets the matrix type as a string from the matrix object. 1867e14e8a7SBarry Smith 1877e14e8a7SBarry Smith Not Collective 1887e14e8a7SBarry Smith 1897e14e8a7SBarry Smith Input Parameter: 19099cd5145SBarry Smith . mat - the matrix 1917e14e8a7SBarry Smith 1927e14e8a7SBarry Smith Output Parameter: 193fe59aa6dSJacob Faibussowitsch . type - name of matrix type 1947e14e8a7SBarry Smith 1957e14e8a7SBarry Smith Level: intermediate 1967e14e8a7SBarry Smith 1971cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetType()` 1987e14e8a7SBarry Smith @*/ 199d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetType(Mat mat, MatType *type) 200d71ae5a4SJacob Faibussowitsch { 2017e14e8a7SBarry Smith PetscFunctionBegin; 2020700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2034f572ea9SToby Isaac PetscAssertPointer(type, 2); 2047adad957SLisandro Dalcin *type = ((PetscObject)mat)->type_name; 2053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2067e14e8a7SBarry Smith } 2077e14e8a7SBarry Smith 208963a61daSJose E. Roman /*@ 20911a5261eSBarry Smith MatGetVecType - Gets the vector type the matrix will return with `MatCreateVecs()` 2100d229a57SStefano Zampini 2110d229a57SStefano Zampini Not Collective 2120d229a57SStefano Zampini 2130d229a57SStefano Zampini Input Parameter: 2140d229a57SStefano Zampini . mat - the matrix 2150d229a57SStefano Zampini 2160d229a57SStefano Zampini Output Parameter: 217fe59aa6dSJacob Faibussowitsch . vtype - name of vector type 2180d229a57SStefano Zampini 2190d229a57SStefano Zampini Level: intermediate 2200d229a57SStefano Zampini 221fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetVecType()`, `VecType` 2220d229a57SStefano Zampini @*/ 223d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetVecType(Mat mat, VecType *vtype) 224d71ae5a4SJacob Faibussowitsch { 2250d229a57SStefano Zampini PetscFunctionBegin; 2260d229a57SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2274f572ea9SToby Isaac PetscAssertPointer(vtype, 2); 2280d229a57SStefano Zampini *vtype = mat->defaultvectype; 2293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2300d229a57SStefano Zampini } 2310d229a57SStefano Zampini 232963a61daSJose E. Roman /*@ 23311a5261eSBarry Smith MatSetVecType - Set the vector type the matrix will return with `MatCreateVecs()` 2340d229a57SStefano Zampini 235c3339decSBarry Smith Collective 2360d229a57SStefano Zampini 2370d229a57SStefano Zampini Input Parameters: 2380d229a57SStefano Zampini + mat - the matrix object 2390d229a57SStefano Zampini - vtype - vector type 2400d229a57SStefano Zampini 2412ef1f0ffSBarry Smith Level: advanced 2422ef1f0ffSBarry Smith 24311a5261eSBarry Smith Note: 2440d229a57SStefano Zampini This is rarely needed in practice since each matrix object internally sets the proper vector type. 2450d229a57SStefano Zampini 2461cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `VecType`, `VecSetType()`, `MatGetVecType()` 2470d229a57SStefano Zampini @*/ 248d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetVecType(Mat mat, VecType vtype) 249d71ae5a4SJacob Faibussowitsch { 2500d229a57SStefano Zampini PetscFunctionBegin; 2510d229a57SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2529566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 2539566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, &mat->defaultvectype)); 2543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2550d229a57SStefano Zampini } 2567e14e8a7SBarry Smith 2573cea93caSBarry Smith /*@C 258*0b4b7b1cSBarry Smith MatRegister - Adds a new matrix type implementation that is usable as a `Mat` in PETSc 2591c84c290SBarry Smith 260cc4c1da9SBarry Smith Not Collective, No Fortran Support 2611c84c290SBarry Smith 2621c84c290SBarry Smith Input Parameters: 26367be906fSBarry Smith + sname - name of a new user-defined matrix type 26467be906fSBarry Smith - function - routine to create method context 26567be906fSBarry Smith 26667be906fSBarry Smith Level: advanced 2671c84c290SBarry Smith 26811a5261eSBarry Smith Note: 26911a5261eSBarry Smith `MatRegister()` may be called multiple times to add several user-defined solvers. 2701c84c290SBarry Smith 271*0b4b7b1cSBarry Smith A simpler alternative to using `MatRegister()` for an application specific matrix format is to use `MatCreateShell()`, which 272*0b4b7b1cSBarry Smith generates a `Mat` of `MatType` `MATSHELL`. One can then use `MatShellSetContext()` and `MatShellSetOperation()` to provide 273*0b4b7b1cSBarry Smith the data structures and routines customized for their matrix format. 274*0b4b7b1cSBarry Smith 275fe59aa6dSJacob Faibussowitsch Example Usage: 2761c84c290SBarry Smith .vb 277bdf89e91SBarry Smith MatRegister("my_mat", MyMatCreate); 2781c84c290SBarry Smith .ve 2791c84c290SBarry Smith 280a3b724e8SBarry Smith Then, your solver can be chosen with the procedural interface via `MatSetType(Mat, "my_mat")` or at runtime via the option 281a3b724e8SBarry Smith `-mat_type my_mat` 2821c84c290SBarry Smith 2831cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `MatSetType()`, `MatRegisterAll()` 2843cea93caSBarry Smith @*/ 285d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegister(const char sname[], PetscErrorCode (*function)(Mat)) 286d71ae5a4SJacob Faibussowitsch { 2877e14e8a7SBarry Smith PetscFunctionBegin; 2889566063dSJacob Faibussowitsch PetscCall(MatInitializePackage()); 2899566063dSJacob Faibussowitsch PetscCall(PetscFunctionListAdd(&MatList, sname, function)); 2903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 29199cd5145SBarry Smith } 29299cd5145SBarry Smith 293f4259b30SLisandro Dalcin MatRootName MatRootNameList = NULL; 29401bebe75SBarry Smith 295cc4c1da9SBarry Smith /*@ 2962920cce0SJacob Faibussowitsch MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type. 29701bebe75SBarry Smith 29801bebe75SBarry Smith Input Parameters: 29911a5261eSBarry Smith + rname - the rootname, for example, `MATAIJ` 30011a5261eSBarry Smith . sname - the name of the sequential matrix type, for example, `MATSEQAIJ` 30111a5261eSBarry Smith - mname - the name of the parallel matrix type, for example, `MATMPIAIJ` 30201bebe75SBarry Smith 30367be906fSBarry Smith Level: developer 30467be906fSBarry Smith 3052920cce0SJacob Faibussowitsch Notes: 3062920cce0SJacob Faibussowitsch `MatSetType()` and `-mat_type name` will automatically use the sequential or parallel version 3072920cce0SJacob Faibussowitsch based on the size of the MPI communicator associated with the matrix. 3082920cce0SJacob Faibussowitsch 3092920cce0SJacob Faibussowitsch The matrix rootname should not be confused with the base type of the function 3102920cce0SJacob Faibussowitsch `PetscObjectBaseTypeCompare()` 31101bebe75SBarry Smith 312fe59aa6dSJacob Faibussowitsch Developer Notes: 31311a5261eSBarry Smith PETSc vectors have a similar rootname that indicates PETSc should automatically select the appropriate `VecType` based on the 31411a5261eSBarry Smith size of the communicator but it is implemented by simply having additional `VecCreate_RootName()` registerer routines that dispatch to the 31523bebc0bSBarry Smith appropriate creation routine. Why have two different ways of implementing the same functionality for different types of objects? It is 31623bebc0bSBarry Smith confusing. 31723bebc0bSBarry Smith 3181cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `PetscObjectBaseTypeCompare()` 31901bebe75SBarry Smith @*/ 320d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegisterRootName(const char rname[], const char sname[], const char mname[]) 321d71ae5a4SJacob Faibussowitsch { 32223bebc0bSBarry Smith MatRootName names; 32301bebe75SBarry Smith 32401bebe75SBarry Smith PetscFunctionBegin; 3259566063dSJacob Faibussowitsch PetscCall(PetscNew(&names)); 3269566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(rname, &names->rname)); 3279566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(sname, &names->sname)); 3289566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(mname, &names->mname)); 32923bebc0bSBarry Smith if (!MatRootNameList) { 33023bebc0bSBarry Smith MatRootNameList = names; 33101bebe75SBarry Smith } else { 33223bebc0bSBarry Smith MatRootName next = MatRootNameList; 33301bebe75SBarry Smith while (next->next) next = next->next; 33401bebe75SBarry Smith next->next = names; 33501bebe75SBarry Smith } 3363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33701bebe75SBarry Smith } 338