1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
284fcf670SStefano Zampini #include <petsc/private/vecimpl.h> /* for Vec->ops->setvalues */
36098dc10SBarry Smith
MatConvert_Shell(Mat oldmat,MatType newtype,MatReuse reuse,Mat * newmat)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
MatGetDiagonal_CF(Mat A,Vec X)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
MatMult_CF(Mat A,Vec X,Vec Y)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
MatMultTranspose_CF(Mat A,Vec X,Vec Y)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
MatDestroy_CF(Mat A)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 {
131cc1eb50dSBarry Smith void *ctx;
132cc1eb50dSBarry Smith PetscCtxDestroyFn *destroy;
133b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat);
134b77ba244SStefano Zampini MatProductType ptype;
135b77ba244SStefano Zampini Mat Dwork;
136cc1eb50dSBarry Smith } MatProductCtx_MatMatCF;
137b77ba244SStefano Zampini
MatProductDestroy_CF(PetscCtxRt data)138*2a8381b2SBarry Smith static PetscErrorCode MatProductDestroy_CF(PetscCtxRt data)
139d71ae5a4SJacob Faibussowitsch {
140cc1eb50dSBarry Smith MatProductCtx_MatMatCF *mmcfdata = *(MatProductCtx_MatMatCF **)data;
141b77ba244SStefano Zampini
142b77ba244SStefano Zampini PetscFunctionBegin;
143cc1eb50dSBarry 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
MatProductNumericPhase_CF(Mat A,Mat B,Mat C,void * data)149d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumericPhase_CF(Mat A, Mat B, Mat C, void *data)
150d71ae5a4SJacob Faibussowitsch {
151cc1eb50dSBarry 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;
159cc1eb50dSBarry 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
MatProductSymbolicPhase_CF(Mat A,Mat B,Mat C,void ** data)168d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolicPhase_CF(Mat A, Mat B, Mat C, void **data)
169d71ae5a4SJacob Faibussowitsch {
170cc1eb50dSBarry 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;
181cc1eb50dSBarry Smith mmcfdata->ctx = C->product->data;
182cc1eb50dSBarry 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 */
MatProductSetFromOptions_CF(Mat D)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
MatConvertFrom_Shell(Mat A,MatType newtype,MatReuse reuse,Mat * B)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