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 106*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat` 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)); 1455f80ce2aSJacob Faibussowitsch PetscCheck(r, PETSC_COMM_SELF, 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: 18699cd5145SBarry Smith . name - name of matrix type 1877e14e8a7SBarry Smith 1887e14e8a7SBarry Smith Level: intermediate 1897e14e8a7SBarry Smith 190*1cc06b55SBarry 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: 2100d229a57SStefano Zampini . name - name of vector type 2110d229a57SStefano Zampini 2120d229a57SStefano Zampini Level: intermediate 2130d229a57SStefano Zampini 214*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `Mat`, `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 239*1cc06b55SBarry 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 2641c84c290SBarry Smith Sample 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 274*1cc06b55SBarry 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 28711a5261eSBarry Smith MatRegisterRootName - Registers a name that can be used for either a sequential or its corresponding parallel matrix type. `MatSetType()` 2882ef1f0ffSBarry Smith and `-mat_type name` will automatically use the sequential or parallel version based on the size of the MPI communicator associated with the 28923bebc0bSBarry Smith matrix. 29001bebe75SBarry Smith 29101bebe75SBarry Smith Input Parameters: 29211a5261eSBarry Smith + rname - the rootname, for example, `MATAIJ` 29311a5261eSBarry Smith . sname - the name of the sequential matrix type, for example, `MATSEQAIJ` 29411a5261eSBarry Smith - mname - the name of the parallel matrix type, for example, `MATMPIAIJ` 29501bebe75SBarry Smith 29667be906fSBarry Smith Level: developer 29767be906fSBarry Smith 29811a5261eSBarry Smith Note: 29911a5261eSBarry Smith The matrix rootname should not be confused with the base type of the function `PetscObjectBaseTypeCompare()` 30001bebe75SBarry Smith 30111a5261eSBarry Smith Developer Note: 30211a5261eSBarry Smith PETSc vectors have a similar rootname that indicates PETSc should automatically select the appropriate `VecType` based on the 30311a5261eSBarry Smith size of the communicator but it is implemented by simply having additional `VecCreate_RootName()` registerer routines that dispatch to the 30423bebc0bSBarry Smith appropriate creation routine. Why have two different ways of implementing the same functionality for different types of objects? It is 30523bebc0bSBarry Smith confusing. 30623bebc0bSBarry Smith 307*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatType`, `PetscObjectBaseTypeCompare()` 30801bebe75SBarry Smith @*/ 309d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRegisterRootName(const char rname[], const char sname[], const char mname[]) 310d71ae5a4SJacob Faibussowitsch { 31123bebc0bSBarry Smith MatRootName names; 31201bebe75SBarry Smith 31301bebe75SBarry Smith PetscFunctionBegin; 3149566063dSJacob Faibussowitsch PetscCall(PetscNew(&names)); 3159566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(rname, &names->rname)); 3169566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(sname, &names->sname)); 3179566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(mname, &names->mname)); 31823bebc0bSBarry Smith if (!MatRootNameList) { 31923bebc0bSBarry Smith MatRootNameList = names; 32001bebe75SBarry Smith } else { 32123bebc0bSBarry Smith MatRootName next = MatRootNameList; 32201bebe75SBarry Smith while (next->next) next = next->next; 32301bebe75SBarry Smith next->next = names; 32401bebe75SBarry Smith } 3253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 32601bebe75SBarry Smith } 327