xref: /petsc/src/mat/impls/shell/shellcnv.c (revision cc1eb50d5a4d6061e906552df09a79d2d9d16af2)
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