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