1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 26098dc10SBarry Smith 3d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Shell(Mat oldmat, MatType newtype, MatReuse reuse, Mat *newmat) 4d71ae5a4SJacob Faibussowitsch { 5676c34cdSKris Buschelman Mat mat; 66098dc10SBarry Smith Vec in, out; 76696f472SJed Brown PetscScalar *array; 841319c1dSStefano Zampini PetscInt *dnnz, *onnz, *dnnzu, *onnzu; 941319c1dSStefano Zampini PetscInt cst, Nbs, mbs, nbs, rbs, cbs; 1041319c1dSStefano Zampini PetscInt im, i, m, n, M, N, *rows, start; 116098dc10SBarry Smith 123a40ed3dSBarry Smith PetscFunctionBegin; 139566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(oldmat, &start, NULL)); 149566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(oldmat, &cst, NULL)); 159566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(oldmat, &in, &out)); 169566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(oldmat, &m, &n)); 179566063dSJacob Faibussowitsch PetscCall(MatGetSize(oldmat, &M, &N)); 189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &rows)); 198af18dd8SStefano Zampini if (reuse != MAT_REUSE_MATRIX) { 209566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)oldmat), &mat)); 219566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat, m, n, M, N)); 229566063dSJacob Faibussowitsch PetscCall(MatSetType(mat, newtype)); 239566063dSJacob Faibussowitsch PetscCall(MatSetBlockSizesFromMats(mat, oldmat, oldmat)); 249566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(mat, &rbs, &cbs)); 2541319c1dSStefano Zampini mbs = m / rbs; 2641319c1dSStefano Zampini nbs = n / cbs; 2741319c1dSStefano Zampini Nbs = N / cbs; 2841319c1dSStefano Zampini cst = cst / cbs; 299566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(mbs, &dnnz, mbs, &onnz, mbs, &dnnzu, mbs, &onnzu)); 3041319c1dSStefano Zampini for (i = 0; i < mbs; i++) { 3141319c1dSStefano Zampini dnnz[i] = nbs; 3241319c1dSStefano Zampini onnz[i] = Nbs - nbs; 3341319c1dSStefano Zampini dnnzu[i] = PetscMax(nbs - i, 0); 3441319c1dSStefano Zampini onnzu[i] = PetscMax(Nbs - (cst + nbs), 0); 3541319c1dSStefano Zampini } 369566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mat, PETSC_DECIDE, dnnz, onnz, dnnzu, onnzu)); 379566063dSJacob Faibussowitsch PetscCall(PetscFree4(dnnz, onnz, dnnzu, onnzu)); 389566063dSJacob Faibussowitsch PetscCall(VecSetOption(in, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE)); 399566063dSJacob Faibussowitsch PetscCall(MatSetUp(mat)); 408af18dd8SStefano Zampini } else { 418af18dd8SStefano Zampini mat = *newmat; 429566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mat)); 438af18dd8SStefano Zampini } 446696f472SJed Brown for (i = 0; i < N; i++) { 4541319c1dSStefano Zampini PetscInt j; 4641319c1dSStefano Zampini 479566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(in)); 489566063dSJacob Faibussowitsch PetscCall(VecSetValue(in, i, 1., INSERT_VALUES)); 499566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(in)); 509566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(in)); 519566063dSJacob Faibussowitsch PetscCall(MatMult(oldmat, in, out)); 529566063dSJacob Faibussowitsch PetscCall(VecGetArray(out, &array)); 5341319c1dSStefano Zampini for (j = 0, im = 0; j < m; j++) { 5441319c1dSStefano Zampini if (PetscAbsScalar(array[j]) == 0.0) continue; 5541319c1dSStefano Zampini rows[im] = j + start; 5641319c1dSStefano Zampini array[im] = array[j]; 5741319c1dSStefano Zampini im++; 5841319c1dSStefano Zampini } 599566063dSJacob Faibussowitsch PetscCall(MatSetValues(mat, im, rows, 1, &i, array, INSERT_VALUES)); 609566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(out, &array)); 616098dc10SBarry Smith } 629566063dSJacob Faibussowitsch PetscCall(PetscFree(rows)); 639566063dSJacob Faibussowitsch PetscCall(VecDestroy(&in)); 649566063dSJacob Faibussowitsch PetscCall(VecDestroy(&out)); 659566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 669566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 67511c6705SHong Zhang if (reuse == MAT_INPLACE_MATRIX) { 689566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(oldmat, &mat)); 69c3d102feSKris Buschelman } else { 70676c34cdSKris Buschelman *newmat = mat; 71c3d102feSKris Buschelman } 72*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 736098dc10SBarry Smith } 74251fad3fSStefano Zampini 75d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_CF(Mat A, Vec X) 76d71ae5a4SJacob Faibussowitsch { 77251fad3fSStefano Zampini Mat B; 78251fad3fSStefano Zampini 79251fad3fSStefano Zampini PetscFunctionBegin; 809566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 8128b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 829566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(B, X)); 83*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 84251fad3fSStefano Zampini } 85251fad3fSStefano Zampini 86d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_CF(Mat A, Vec X, Vec Y) 87d71ae5a4SJacob Faibussowitsch { 88251fad3fSStefano Zampini Mat B; 89251fad3fSStefano Zampini 90251fad3fSStefano Zampini PetscFunctionBegin; 919566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 9228b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 939566063dSJacob Faibussowitsch PetscCall(MatMult(B, X, Y)); 94*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 95251fad3fSStefano Zampini } 96251fad3fSStefano Zampini 97d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_CF(Mat A, Vec X, Vec Y) 98d71ae5a4SJacob Faibussowitsch { 99251fad3fSStefano Zampini Mat B; 100251fad3fSStefano Zampini 101251fad3fSStefano Zampini PetscFunctionBegin; 1029566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 10328b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 1049566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(B, X, Y)); 105*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 106251fad3fSStefano Zampini } 107251fad3fSStefano Zampini 108d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_CF(Mat A) 109d71ae5a4SJacob Faibussowitsch { 110251fad3fSStefano Zampini Mat B; 111251fad3fSStefano Zampini 112251fad3fSStefano Zampini PetscFunctionBegin; 1139566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 11428b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 1159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&B)); 116800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(A, NULL)); 1179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_anytype_C", NULL)); 118*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 119b77ba244SStefano Zampini } 120b77ba244SStefano Zampini 121b77ba244SStefano Zampini typedef struct { 122b77ba244SStefano Zampini void *userdata; 123b77ba244SStefano Zampini PetscErrorCode (*userdestroy)(void *); 124b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat); 125b77ba244SStefano Zampini MatProductType ptype; 126b77ba244SStefano Zampini Mat Dwork; 127b77ba244SStefano Zampini } MatMatCF; 128b77ba244SStefano Zampini 129d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductDestroy_CF(void *data) 130d71ae5a4SJacob Faibussowitsch { 131b77ba244SStefano Zampini MatMatCF *mmcfdata = (MatMatCF *)data; 132b77ba244SStefano Zampini 133b77ba244SStefano Zampini PetscFunctionBegin; 1341baa6e33SBarry Smith if (mmcfdata->userdestroy) PetscCall((*mmcfdata->userdestroy)(mmcfdata->userdata)); 1359566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmcfdata->Dwork)); 1369566063dSJacob Faibussowitsch PetscCall(PetscFree(mmcfdata)); 137*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 138b77ba244SStefano Zampini } 139b77ba244SStefano Zampini 140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumericPhase_CF(Mat A, Mat B, Mat C, void *data) 141d71ae5a4SJacob Faibussowitsch { 142b77ba244SStefano Zampini MatMatCF *mmcfdata = (MatMatCF *)data; 143b77ba244SStefano Zampini 144b77ba244SStefano Zampini PetscFunctionBegin; 14528b400f6SJacob Faibussowitsch PetscCheck(mmcfdata, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing data"); 14628b400f6SJacob Faibussowitsch PetscCheck(mmcfdata->numeric, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing numeric operation"); 147b77ba244SStefano Zampini /* the MATSHELL interface allows us to play with the product data */ 1489566063dSJacob Faibussowitsch PetscCall(PetscNew(&C->product)); 149b77ba244SStefano Zampini C->product->type = mmcfdata->ptype; 150b77ba244SStefano Zampini C->product->data = mmcfdata->userdata; 151b77ba244SStefano Zampini C->product->Dwork = mmcfdata->Dwork; 1529566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &C->product->A)); 153b77ba244SStefano Zampini C->product->B = B; 1549566063dSJacob Faibussowitsch PetscCall((*mmcfdata->numeric)(C)); 1559566063dSJacob Faibussowitsch PetscCall(PetscFree(C->product)); 156*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 157b77ba244SStefano Zampini } 158b77ba244SStefano Zampini 159d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolicPhase_CF(Mat A, Mat B, Mat C, void **data) 160d71ae5a4SJacob Faibussowitsch { 161b77ba244SStefano Zampini MatMatCF *mmcfdata; 162b77ba244SStefano Zampini 163b77ba244SStefano Zampini PetscFunctionBegin; 1649566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &C->product->A)); 1659566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(C)); 1669566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(C)); 167b77ba244SStefano Zampini /* the MATSHELL interface does not allow non-empty product data */ 1689566063dSJacob Faibussowitsch PetscCall(PetscNew(&mmcfdata)); 169b77ba244SStefano Zampini 170b77ba244SStefano Zampini mmcfdata->numeric = C->ops->productnumeric; 171b77ba244SStefano Zampini mmcfdata->ptype = C->product->type; 172b77ba244SStefano Zampini mmcfdata->userdata = C->product->data; 173b77ba244SStefano Zampini mmcfdata->userdestroy = C->product->destroy; 174b77ba244SStefano Zampini mmcfdata->Dwork = C->product->Dwork; 175b77ba244SStefano Zampini 176b77ba244SStefano Zampini C->product->Dwork = NULL; 177b77ba244SStefano Zampini C->product->data = NULL; 178b77ba244SStefano Zampini C->product->destroy = NULL; 179b77ba244SStefano Zampini C->product->A = A; 180b77ba244SStefano Zampini 181b77ba244SStefano Zampini *data = mmcfdata; 182*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 183b77ba244SStefano Zampini } 184b77ba244SStefano Zampini 185b77ba244SStefano Zampini /* only for A of type shell, mainly used for MatMat operations of shells with AXPYs */ 186d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_CF(Mat D) 187d71ae5a4SJacob Faibussowitsch { 188b77ba244SStefano Zampini Mat A, B, Ain; 189b77ba244SStefano Zampini void (*Af)(void) = NULL; 190b77ba244SStefano Zampini PetscBool flg; 191b77ba244SStefano Zampini 192b77ba244SStefano Zampini PetscFunctionBegin; 193b77ba244SStefano Zampini MatCheckProduct(D, 1); 194*3ba16761SJacob Faibussowitsch if (D->product->type == MATPRODUCT_ABC) PetscFunctionReturn(PETSC_SUCCESS); 195b77ba244SStefano Zampini A = D->product->A; 196b77ba244SStefano Zampini B = D->product->B; 1979566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 198*3ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1999566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatProductSetFromOptions_anytype_C", &Af)); 200b77ba244SStefano Zampini if (Af == (void (*)(void))MatProductSetFromOptions_CF) { 2019566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &Ain)); 202*3ba16761SJacob Faibussowitsch } else PetscFunctionReturn(PETSC_SUCCESS); 203b77ba244SStefano Zampini D->product->A = Ain; 2049566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(D)); 205b77ba244SStefano Zampini D->product->A = A; 206b77ba244SStefano Zampini if (D->ops->productsymbolic) { /* we have a symbolic match, now populate the MATSHELL operations */ 2079566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation(A, D->product->type, MatProductSymbolicPhase_CF, MatProductNumericPhase_CF, MatProductDestroy_CF, ((PetscObject)B)->type_name, NULL)); 2089566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(D)); 209b77ba244SStefano Zampini } 210*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 211251fad3fSStefano Zampini } 212251fad3fSStefano Zampini 213d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvertFrom_Shell(Mat A, MatType newtype, MatReuse reuse, Mat *B) 214d71ae5a4SJacob Faibussowitsch { 215251fad3fSStefano Zampini Mat M; 216251fad3fSStefano Zampini PetscBool flg; 217251fad3fSStefano Zampini 218251fad3fSStefano Zampini PetscFunctionBegin; 2199566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATSHELL, &flg)); 22028b400f6SJacob Faibussowitsch PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only conversion to MATSHELL"); 221251fad3fSStefano Zampini if (reuse == MAT_INITIAL_MATRIX) { 2229566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 2239566063dSJacob Faibussowitsch PetscCall(MatCreateShell(PetscObjectComm((PetscObject)A), A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, A, &M)); 2249566063dSJacob Faibussowitsch PetscCall(MatSetBlockSizesFromMats(M, A, A)); 2259566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(M, MATOP_MULT, (void (*)(void))MatMult_CF)); 2269566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(M, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_CF)); 2279566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(M, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_CF)); 2289566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(M, MATOP_DESTROY, (void (*)(void))MatDestroy_CF)); 2299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)M, "MatProductSetFromOptions_anytype_C", MatProductSetFromOptions_CF)); 2309566063dSJacob Faibussowitsch PetscCall(PetscFree(M->defaultvectype)); 2319566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(A->defaultvectype, &M->defaultvectype)); 2322487f3f2SStefano Zampini #if defined(PETSC_HAVE_DEVICE) 2339566063dSJacob Faibussowitsch PetscCall(MatBindToCPU(M, A->boundtocpu)); 2342487f3f2SStefano Zampini #endif 235251fad3fSStefano Zampini *B = M; 236251fad3fSStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented"); 237*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 238251fad3fSStefano Zampini } 239