1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 284fcf670SStefano Zampini #include <petsc/private/vecimpl.h> /* for Vec->ops->setvalues */ 36098dc10SBarry Smith 4d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Shell(Mat oldmat, MatType newtype, MatReuse reuse, Mat *newmat) 5d71ae5a4SJacob Faibussowitsch { 6676c34cdSKris Buschelman Mat mat; 76098dc10SBarry Smith Vec in, out; 86696f472SJed Brown PetscScalar *array; 941319c1dSStefano Zampini PetscInt *dnnz, *onnz, *dnnzu, *onnzu; 1084fcf670SStefano Zampini PetscInt cst, cen, Nbs, mbs, nbs, rbs, cbs; 1141319c1dSStefano Zampini PetscInt im, i, m, n, M, N, *rows, start; 126098dc10SBarry Smith 133a40ed3dSBarry Smith PetscFunctionBegin; 149566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(oldmat, &start, NULL)); 1584fcf670SStefano Zampini PetscCall(MatGetOwnershipRangeColumn(oldmat, &cst, &cen)); 169566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(oldmat, &in, &out)); 179566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(oldmat, &m, &n)); 189566063dSJacob Faibussowitsch PetscCall(MatGetSize(oldmat, &M, &N)); 199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &rows)); 208af18dd8SStefano Zampini if (reuse != MAT_REUSE_MATRIX) { 219566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)oldmat), &mat)); 229566063dSJacob Faibussowitsch PetscCall(MatSetSizes(mat, m, n, M, N)); 239566063dSJacob Faibussowitsch PetscCall(MatSetType(mat, newtype)); 249566063dSJacob Faibussowitsch PetscCall(MatSetBlockSizesFromMats(mat, oldmat, oldmat)); 259566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(mat, &rbs, &cbs)); 2641319c1dSStefano Zampini mbs = m / rbs; 2741319c1dSStefano Zampini nbs = n / cbs; 2841319c1dSStefano Zampini Nbs = N / cbs; 2941319c1dSStefano Zampini cst = cst / cbs; 309566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(mbs, &dnnz, mbs, &onnz, mbs, &dnnzu, mbs, &onnzu)); 3141319c1dSStefano Zampini for (i = 0; i < mbs; i++) { 3241319c1dSStefano Zampini dnnz[i] = nbs; 3341319c1dSStefano Zampini onnz[i] = Nbs - nbs; 3441319c1dSStefano Zampini dnnzu[i] = PetscMax(nbs - i, 0); 3541319c1dSStefano Zampini onnzu[i] = PetscMax(Nbs - (cst + nbs), 0); 3641319c1dSStefano Zampini } 379566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mat, PETSC_DECIDE, dnnz, onnz, dnnzu, onnzu)); 389566063dSJacob Faibussowitsch PetscCall(PetscFree4(dnnz, onnz, dnnzu, onnzu)); 399566063dSJacob Faibussowitsch PetscCall(VecSetOption(in, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE)); 409566063dSJacob Faibussowitsch PetscCall(MatSetUp(mat)); 418af18dd8SStefano Zampini } else { 428af18dd8SStefano Zampini mat = *newmat; 439566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(mat)); 448af18dd8SStefano Zampini } 456696f472SJed Brown for (i = 0; i < N; i++) { 4641319c1dSStefano Zampini PetscInt j; 4741319c1dSStefano Zampini 489566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(in)); 4984fcf670SStefano Zampini if (in->ops->setvalues) { 509566063dSJacob Faibussowitsch PetscCall(VecSetValue(in, i, 1., INSERT_VALUES)); 5184fcf670SStefano Zampini } else { 5284fcf670SStefano Zampini if (i >= cst && i < cen) { 5384fcf670SStefano Zampini PetscCall(VecGetArray(in, &array)); 5484fcf670SStefano Zampini array[i - cst] = 1.0; 5584fcf670SStefano Zampini PetscCall(VecRestoreArray(in, &array)); 5684fcf670SStefano Zampini } 5784fcf670SStefano Zampini } 589566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(in)); 599566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(in)); 609566063dSJacob Faibussowitsch PetscCall(MatMult(oldmat, in, out)); 619566063dSJacob Faibussowitsch PetscCall(VecGetArray(out, &array)); 6241319c1dSStefano Zampini for (j = 0, im = 0; j < m; j++) { 6341319c1dSStefano Zampini if (PetscAbsScalar(array[j]) == 0.0) continue; 6441319c1dSStefano Zampini rows[im] = j + start; 6541319c1dSStefano Zampini array[im] = array[j]; 6641319c1dSStefano Zampini im++; 6741319c1dSStefano Zampini } 689566063dSJacob Faibussowitsch PetscCall(MatSetValues(mat, im, rows, 1, &i, array, INSERT_VALUES)); 699566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(out, &array)); 706098dc10SBarry Smith } 719566063dSJacob Faibussowitsch PetscCall(PetscFree(rows)); 729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&in)); 739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&out)); 749566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 759566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 76511c6705SHong Zhang if (reuse == MAT_INPLACE_MATRIX) { 779566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(oldmat, &mat)); 78c3d102feSKris Buschelman } else { 79676c34cdSKris Buschelman *newmat = mat; 80c3d102feSKris Buschelman } 813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 826098dc10SBarry Smith } 83251fad3fSStefano Zampini 84d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_CF(Mat A, Vec X) 85d71ae5a4SJacob Faibussowitsch { 86251fad3fSStefano Zampini Mat B; 87251fad3fSStefano Zampini 88251fad3fSStefano Zampini PetscFunctionBegin; 899566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 9028b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 919566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(B, X)); 923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 93251fad3fSStefano Zampini } 94251fad3fSStefano Zampini 95d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_CF(Mat A, Vec X, Vec Y) 96d71ae5a4SJacob Faibussowitsch { 97251fad3fSStefano Zampini Mat B; 98251fad3fSStefano Zampini 99251fad3fSStefano Zampini PetscFunctionBegin; 1009566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 10128b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 1029566063dSJacob Faibussowitsch PetscCall(MatMult(B, X, Y)); 1033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 104251fad3fSStefano Zampini } 105251fad3fSStefano Zampini 106d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_CF(Mat A, Vec X, Vec Y) 107d71ae5a4SJacob Faibussowitsch { 108251fad3fSStefano Zampini Mat B; 109251fad3fSStefano Zampini 110251fad3fSStefano Zampini PetscFunctionBegin; 1119566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 11228b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 1139566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(B, X, Y)); 1143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 115251fad3fSStefano Zampini } 116251fad3fSStefano Zampini 117d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_CF(Mat A) 118d71ae5a4SJacob Faibussowitsch { 119251fad3fSStefano Zampini Mat B; 120251fad3fSStefano Zampini 121251fad3fSStefano Zampini PetscFunctionBegin; 1229566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &B)); 12328b400f6SJacob Faibussowitsch PetscCheck(B, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing user matrix"); 1249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&B)); 125800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(A, NULL)); 1269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_anytype_C", NULL)); 1273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 128b77ba244SStefano Zampini } 129b77ba244SStefano Zampini 130b77ba244SStefano Zampini typedef struct { 131*cc1eb50dSBarry Smith void *ctx; 132*cc1eb50dSBarry Smith PetscCtxDestroyFn *destroy; 133b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat); 134b77ba244SStefano Zampini MatProductType ptype; 135b77ba244SStefano Zampini Mat Dwork; 136*cc1eb50dSBarry Smith } MatProductCtx_MatMatCF; 137b77ba244SStefano Zampini 138*cc1eb50dSBarry Smith static PetscErrorCode MatProductDestroy_CF(void **data) 139d71ae5a4SJacob Faibussowitsch { 140*cc1eb50dSBarry Smith MatProductCtx_MatMatCF *mmcfdata = *(MatProductCtx_MatMatCF **)data; 141b77ba244SStefano Zampini 142b77ba244SStefano Zampini PetscFunctionBegin; 143*cc1eb50dSBarry Smith if (mmcfdata->destroy) PetscCall((*mmcfdata->destroy)(&mmcfdata->ctx)); 1449566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmcfdata->Dwork)); 1459566063dSJacob Faibussowitsch PetscCall(PetscFree(mmcfdata)); 1463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 147b77ba244SStefano Zampini } 148b77ba244SStefano Zampini 149d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumericPhase_CF(Mat A, Mat B, Mat C, void *data) 150d71ae5a4SJacob Faibussowitsch { 151*cc1eb50dSBarry Smith MatProductCtx_MatMatCF *mmcfdata = (MatProductCtx_MatMatCF *)data; 152b77ba244SStefano Zampini 153b77ba244SStefano Zampini PetscFunctionBegin; 15428b400f6SJacob Faibussowitsch PetscCheck(mmcfdata, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing data"); 15528b400f6SJacob Faibussowitsch PetscCheck(mmcfdata->numeric, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing numeric operation"); 156b77ba244SStefano Zampini /* the MATSHELL interface allows us to play with the product data */ 1579566063dSJacob Faibussowitsch PetscCall(PetscNew(&C->product)); 158b77ba244SStefano Zampini C->product->type = mmcfdata->ptype; 159*cc1eb50dSBarry Smith C->product->data = mmcfdata->ctx; 160b77ba244SStefano Zampini C->product->Dwork = mmcfdata->Dwork; 1619566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &C->product->A)); 162b77ba244SStefano Zampini C->product->B = B; 1639566063dSJacob Faibussowitsch PetscCall((*mmcfdata->numeric)(C)); 1649566063dSJacob Faibussowitsch PetscCall(PetscFree(C->product)); 1653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 166b77ba244SStefano Zampini } 167b77ba244SStefano Zampini 168d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolicPhase_CF(Mat A, Mat B, Mat C, void **data) 169d71ae5a4SJacob Faibussowitsch { 170*cc1eb50dSBarry Smith MatProductCtx_MatMatCF *mmcfdata; 171b77ba244SStefano Zampini 172b77ba244SStefano Zampini PetscFunctionBegin; 1739566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &C->product->A)); 1749566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(C)); 1759566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(C)); 176b77ba244SStefano Zampini /* the MATSHELL interface does not allow non-empty product data */ 1779566063dSJacob Faibussowitsch PetscCall(PetscNew(&mmcfdata)); 178b77ba244SStefano Zampini 179b77ba244SStefano Zampini mmcfdata->numeric = C->ops->productnumeric; 180b77ba244SStefano Zampini mmcfdata->ptype = C->product->type; 181*cc1eb50dSBarry Smith mmcfdata->ctx = C->product->data; 182*cc1eb50dSBarry Smith mmcfdata->destroy = C->product->destroy; 183b77ba244SStefano Zampini mmcfdata->Dwork = C->product->Dwork; 184b77ba244SStefano Zampini 185b77ba244SStefano Zampini C->product->Dwork = NULL; 186b77ba244SStefano Zampini C->product->data = NULL; 187b77ba244SStefano Zampini C->product->destroy = NULL; 188b77ba244SStefano Zampini C->product->A = A; 189b77ba244SStefano Zampini 190b77ba244SStefano Zampini *data = mmcfdata; 1913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 192b77ba244SStefano Zampini } 193b77ba244SStefano Zampini 194b77ba244SStefano Zampini /* only for A of type shell, mainly used for MatMat operations of shells with AXPYs */ 195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_CF(Mat D) 196d71ae5a4SJacob Faibussowitsch { 197b77ba244SStefano Zampini Mat A, B, Ain; 198835f2295SStefano Zampini PetscErrorCode (*Af)(Mat) = NULL; 199b77ba244SStefano Zampini PetscBool flg; 200b77ba244SStefano Zampini 201b77ba244SStefano Zampini PetscFunctionBegin; 202b77ba244SStefano Zampini MatCheckProduct(D, 1); 2033ba16761SJacob Faibussowitsch if (D->product->type == MATPRODUCT_ABC) PetscFunctionReturn(PETSC_SUCCESS); 204b77ba244SStefano Zampini A = D->product->A; 205b77ba244SStefano Zampini B = D->product->B; 2069566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 2073ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 2089566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatProductSetFromOptions_anytype_C", &Af)); 209ac530a7eSPierre Jolivet if (Af == MatProductSetFromOptions_CF) PetscCall(MatShellGetContext(A, &Ain)); 210ac530a7eSPierre Jolivet else PetscFunctionReturn(PETSC_SUCCESS); 211b77ba244SStefano Zampini D->product->A = Ain; 2129566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(D)); 213b77ba244SStefano Zampini D->product->A = A; 214b77ba244SStefano Zampini if (D->ops->productsymbolic) { /* we have a symbolic match, now populate the MATSHELL operations */ 2159566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation(A, D->product->type, MatProductSymbolicPhase_CF, MatProductNumericPhase_CF, MatProductDestroy_CF, ((PetscObject)B)->type_name, NULL)); 2169566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(D)); 217b77ba244SStefano Zampini } 2183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 219251fad3fSStefano Zampini } 220251fad3fSStefano Zampini 221d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvertFrom_Shell(Mat A, MatType newtype, MatReuse reuse, Mat *B) 222d71ae5a4SJacob Faibussowitsch { 223251fad3fSStefano Zampini Mat M; 224251fad3fSStefano Zampini PetscBool flg; 225251fad3fSStefano Zampini 226251fad3fSStefano Zampini PetscFunctionBegin; 2279566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATSHELL, &flg)); 22828b400f6SJacob Faibussowitsch PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only conversion to MATSHELL"); 229251fad3fSStefano Zampini if (reuse == MAT_INITIAL_MATRIX) { 2309566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)A)); 2319566063dSJacob Faibussowitsch PetscCall(MatCreateShell(PetscObjectComm((PetscObject)A), A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, A, &M)); 2329566063dSJacob Faibussowitsch PetscCall(MatSetBlockSizesFromMats(M, A, A)); 23357d50842SBarry Smith PetscCall(MatShellSetOperation(M, MATOP_MULT, (PetscErrorCodeFn *)MatMult_CF)); 23457d50842SBarry Smith PetscCall(MatShellSetOperation(M, MATOP_MULT_TRANSPOSE, (PetscErrorCodeFn *)MatMultTranspose_CF)); 23557d50842SBarry Smith PetscCall(MatShellSetOperation(M, MATOP_GET_DIAGONAL, (PetscErrorCodeFn *)MatGetDiagonal_CF)); 23657d50842SBarry Smith PetscCall(MatShellSetOperation(M, MATOP_DESTROY, (PetscErrorCodeFn *)MatDestroy_CF)); 2379566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)M, "MatProductSetFromOptions_anytype_C", MatProductSetFromOptions_CF)); 2389566063dSJacob Faibussowitsch PetscCall(PetscFree(M->defaultvectype)); 2399566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(A->defaultvectype, &M->defaultvectype)); 2402487f3f2SStefano Zampini #if defined(PETSC_HAVE_DEVICE) 2419566063dSJacob Faibussowitsch PetscCall(MatBindToCPU(M, A->boundtocpu)); 2422487f3f2SStefano Zampini #endif 243251fad3fSStefano Zampini *B = M; 244251fad3fSStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented"); 2453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 246251fad3fSStefano Zampini } 247