#include /* MatConvert_Basic - Converts from any input format to another format. Does not do preallocation so in general will be slow */ PetscErrorCode MatConvert_Basic(Mat mat, MatType newtype, MatReuse reuse, Mat *newmat) { Mat M; const PetscScalar *vwork; PetscInt i, rstart, rend, nz; const PetscInt *cwork; PetscBool isSBAIJ; PetscFunctionBegin; if (!mat->ops->getrow) { /* missing get row, use matvecs */ PetscCall(MatConvert_Shell(mat, newtype, reuse, newmat)); PetscFunctionReturn(PETSC_SUCCESS); } PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATSEQSBAIJ, &isSBAIJ)); if (!isSBAIJ) PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPISBAIJ, &isSBAIJ)); PetscCheck(!isSBAIJ, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot convert from SBAIJ matrix since cannot obtain entire rows of matrix"); if (reuse == MAT_REUSE_MATRIX) { M = *newmat; } else { PetscInt m, n, lm, ln; PetscCall(MatGetSize(mat, &m, &n)); PetscCall(MatGetLocalSize(mat, &lm, &ln)); PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &M)); PetscCall(MatSetSizes(M, lm, ln, m, n)); PetscCall(MatSetBlockSizesFromMats(M, mat, mat)); PetscCall(MatSetType(M, newtype)); PetscCall(MatSetUp(M)); PetscCall(MatSetOption(M, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE)); PetscCall(MatSetOption(M, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE)); PetscCall(MatSetOption(M, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); PetscCall(PetscObjectTypeCompare((PetscObject)M, MATSEQSBAIJ, &isSBAIJ)); if (!isSBAIJ) PetscCall(PetscObjectTypeCompare((PetscObject)M, MATMPISBAIJ, &isSBAIJ)); if (isSBAIJ) PetscCall(MatSetOption(M, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE)); } PetscCall(MatGetOwnershipRange(mat, &rstart, &rend)); for (i = rstart; i < rend; i++) { PetscCall(MatGetRow(mat, i, &nz, &cwork, &vwork)); PetscCall(MatSetValues(M, 1, &i, nz, cwork, vwork, INSERT_VALUES)); PetscCall(MatRestoreRow(mat, i, &nz, &cwork, &vwork)); } PetscCall(MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY)); if (reuse != MAT_REUSE_MATRIX) PetscCall(MatSetOption(M, MAT_NO_OFF_PROC_ENTRIES, PETSC_FALSE)); if (reuse == MAT_INPLACE_MATRIX) { PetscCall(MatHeaderReplace(mat, &M)); } else { *newmat = M; } PetscFunctionReturn(PETSC_SUCCESS); }