xref: /petsc/src/ksp/pc/impls/h2opus/pch2opus.c (revision 3ba1676111f5c958fe6c2729b46ca4d523958bb3)
153022affSStefano Zampini #include <petsc/private/pcimpl.h>
253022affSStefano Zampini #include <petsc/private/matimpl.h>
353022affSStefano Zampini #include <h2opusconf.h>
453022affSStefano Zampini 
553022affSStefano Zampini /* Use GPU only if H2OPUS is configured for GPU */
653022affSStefano Zampini #if defined(PETSC_HAVE_CUDA) && defined(H2OPUS_USE_GPU)
753022affSStefano Zampini   #define PETSC_H2OPUS_USE_GPU
853022affSStefano Zampini #endif
953022affSStefano Zampini 
1053022affSStefano Zampini typedef struct {
1153022affSStefano Zampini   Mat         A;
1253022affSStefano Zampini   Mat         M;
1353022affSStefano Zampini   PetscScalar s0;
1453022affSStefano Zampini 
1553022affSStefano Zampini   /* sampler for Newton-Schultz */
1653022affSStefano Zampini   Mat      S;
1753022affSStefano Zampini   PetscInt hyperorder;
1853022affSStefano Zampini   Vec      wns[4];
1953022affSStefano Zampini   Mat      wnsmat[4];
2053022affSStefano Zampini 
2153022affSStefano Zampini   /* convergence testing */
2253022affSStefano Zampini   Mat T;
2353022affSStefano Zampini   Vec w;
2453022affSStefano Zampini 
2553022affSStefano Zampini   /* Support for PCSetCoordinates */
2653022affSStefano Zampini   PetscInt   sdim;
2753022affSStefano Zampini   PetscInt   nlocc;
2853022affSStefano Zampini   PetscReal *coords;
2953022affSStefano Zampini 
3053022affSStefano Zampini   /* Newton-Schultz customization */
3153022affSStefano Zampini   PetscInt  maxits;
3253022affSStefano Zampini   PetscReal rtol, atol;
3353022affSStefano Zampini   PetscBool monitor;
3453022affSStefano Zampini   PetscBool useapproximatenorms;
3553022affSStefano Zampini   NormType  normtype;
3653022affSStefano Zampini 
3753022affSStefano Zampini   /* Used when pmat != MATH2OPUS */
3853022affSStefano Zampini   PetscReal eta;
3953022affSStefano Zampini   PetscInt  leafsize;
4053022affSStefano Zampini   PetscInt  max_rank;
4153022affSStefano Zampini   PetscInt  bs;
4253022affSStefano Zampini   PetscReal mrtol;
4353022affSStefano Zampini 
448db51263SStefano Zampini   /* CPU/GPU */
458db51263SStefano Zampini   PetscBool forcecpu;
4653022affSStefano Zampini   PetscBool boundtocpu;
4753022affSStefano Zampini } PC_H2OPUS;
4853022affSStefano Zampini 
4953022affSStefano Zampini PETSC_EXTERN PetscErrorCode MatNorm_H2OPUS(Mat, NormType, PetscReal *);
5053022affSStefano Zampini 
51d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_H2OPUS(PC pc)
52d71ae5a4SJacob Faibussowitsch {
5353022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
5453022affSStefano Zampini 
5553022affSStefano Zampini   PetscFunctionBegin;
5653022affSStefano Zampini   pch2opus->sdim  = 0;
5753022affSStefano Zampini   pch2opus->nlocc = 0;
589566063dSJacob Faibussowitsch   PetscCall(PetscFree(pch2opus->coords));
599566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->A));
609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->M));
619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->T));
629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->w));
639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->S));
649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[0]));
659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[1]));
669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[2]));
679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[3]));
689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[0]));
699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[1]));
709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[2]));
719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[3]));
72*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7353022affSStefano Zampini }
7453022affSStefano Zampini 
75d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_H2OPUS(PC pc, PetscInt sdim, PetscInt nlocc, PetscReal *coords)
76d71ae5a4SJacob Faibussowitsch {
7753022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
7853022affSStefano Zampini   PetscBool  reset    = PETSC_TRUE;
7953022affSStefano Zampini 
8053022affSStefano Zampini   PetscFunctionBegin;
8153022affSStefano Zampini   if (pch2opus->sdim && sdim == pch2opus->sdim && nlocc == pch2opus->nlocc) {
829566063dSJacob Faibussowitsch     PetscCall(PetscArraycmp(pch2opus->coords, coords, sdim * nlocc, &reset));
8353022affSStefano Zampini     reset = (PetscBool)!reset;
8453022affSStefano Zampini   }
851c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &reset, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
8653022affSStefano Zampini   if (reset) {
879566063dSJacob Faibussowitsch     PetscCall(PCReset_H2OPUS(pc));
889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sdim * nlocc, &pch2opus->coords));
899566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(pch2opus->coords, coords, sdim * nlocc));
9053022affSStefano Zampini     pch2opus->sdim  = sdim;
9153022affSStefano Zampini     pch2opus->nlocc = nlocc;
9253022affSStefano Zampini   }
93*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9453022affSStefano Zampini }
9553022affSStefano Zampini 
96d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_H2OPUS(PC pc)
97d71ae5a4SJacob Faibussowitsch {
9853022affSStefano Zampini   PetscFunctionBegin;
999566063dSJacob Faibussowitsch   PetscCall(PCReset_H2OPUS(pc));
1009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
1019566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
102*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10353022affSStefano Zampini }
10453022affSStefano Zampini 
105d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_H2OPUS(PC pc, PetscOptionItems *PetscOptionsObject)
106d71ae5a4SJacob Faibussowitsch {
10753022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
10853022affSStefano Zampini 
10953022affSStefano Zampini   PetscFunctionBegin;
110d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "H2OPUS options");
1119566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_h2opus_maxits", "Maximum number of iterations for Newton-Schultz", NULL, pch2opus->maxits, &pch2opus->maxits, NULL));
1129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_h2opus_monitor", "Monitor Newton-Schultz convergence", NULL, pch2opus->monitor, &pch2opus->monitor, NULL));
1139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_h2opus_atol", "Absolute tolerance", NULL, pch2opus->atol, &pch2opus->atol, NULL));
1149566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_h2opus_rtol", "Relative tolerance", NULL, pch2opus->rtol, &pch2opus->rtol, NULL));
1159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_h2opus_norm_type", "Norm type for convergence monitoring", NULL, NormTypes, (PetscEnum)pch2opus->normtype, (PetscEnum *)&pch2opus->normtype, NULL));
1169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_h2opus_hyperorder", "Hyper power order of sampling", NULL, pch2opus->hyperorder, &pch2opus->hyperorder, NULL));
1179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_h2opus_leafsize", "Leaf size when constructed from kernel", NULL, pch2opus->leafsize, &pch2opus->leafsize, NULL));
1189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_h2opus_eta", "Admissibility condition tolerance", NULL, pch2opus->eta, &pch2opus->eta, NULL));
1199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_h2opus_maxrank", "Maximum rank when constructed from matvecs", NULL, pch2opus->max_rank, &pch2opus->max_rank, NULL));
1209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_h2opus_samples", "Number of samples to be taken concurrently when constructing from matvecs", NULL, pch2opus->bs, &pch2opus->bs, NULL));
1219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_h2opus_mrtol", "Relative tolerance for construction from sampling", NULL, pch2opus->mrtol, &pch2opus->mrtol, NULL));
1228db51263SStefano Zampini   PetscCall(PetscOptionsBool("-pc_h2opus_forcecpu", "Force construction on CPU", NULL, pch2opus->forcecpu, &pch2opus->forcecpu, NULL));
123d0609cedSBarry Smith   PetscOptionsHeadEnd();
124*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12553022affSStefano Zampini }
12653022affSStefano Zampini 
12753022affSStefano Zampini typedef struct {
12853022affSStefano Zampini   Mat A;
12953022affSStefano Zampini   Mat M;
13053022affSStefano Zampini   Vec w;
13153022affSStefano Zampini } AAtCtx;
13253022affSStefano Zampini 
133d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_AAt(Mat A, Vec x, Vec y)
134d71ae5a4SJacob Faibussowitsch {
13553022affSStefano Zampini   AAtCtx *aat;
13653022affSStefano Zampini 
13753022affSStefano Zampini   PetscFunctionBegin;
1389566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, (void *)&aat));
1399566063dSJacob Faibussowitsch   /* PetscCall(MatMultTranspose(aat->M,x,aat->w)); */
1409566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(aat->A, x, aat->w));
1419566063dSJacob Faibussowitsch   PetscCall(MatMult(aat->A, aat->w, y));
142*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14353022affSStefano Zampini }
14453022affSStefano Zampini 
145d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCH2OpusSetUpInit(PC pc)
146d71ae5a4SJacob Faibussowitsch {
14753022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
14853022affSStefano Zampini   Mat        A        = pc->useAmat ? pc->mat : pc->pmat, AAt;
14953022affSStefano Zampini   PetscInt   M, m;
15053022affSStefano Zampini   VecType    vtype;
15153022affSStefano Zampini   PetscReal  n;
15253022affSStefano Zampini   AAtCtx     aat;
15353022affSStefano Zampini 
15453022affSStefano Zampini   PetscFunctionBegin;
15553022affSStefano Zampini   aat.A = A;
15653022affSStefano Zampini   aat.M = pch2opus->M; /* unused so far */
1579566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &aat.w));
1589566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, NULL));
1599566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, NULL));
1609566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)A), m, m, M, M, &aat, &AAt));
1619566063dSJacob Faibussowitsch   PetscCall(MatBindToCPU(AAt, pch2opus->boundtocpu));
1629566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(AAt, MATOP_MULT, (void (*)(void))MatMult_AAt));
1639566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(AAt, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMult_AAt));
1649566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(AAt, MATOP_NORM, (void (*)(void))MatNorm_H2OPUS));
1659566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
1669566063dSJacob Faibussowitsch   PetscCall(MatShellSetVecType(AAt, vtype));
1679566063dSJacob Faibussowitsch   PetscCall(MatNorm(AAt, NORM_1, &n));
16853022affSStefano Zampini   pch2opus->s0 = 1. / n;
1699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&aat.w));
1709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&AAt));
171*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17253022affSStefano Zampini }
17353022affSStefano Zampini 
174d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyKernel_H2OPUS(PC pc, Vec x, Vec y, PetscBool t)
175d71ae5a4SJacob Faibussowitsch {
17653022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
17753022affSStefano Zampini 
17853022affSStefano Zampini   PetscFunctionBegin;
1799566063dSJacob Faibussowitsch   if (t) PetscCall(MatMultTranspose(pch2opus->M, x, y));
1809566063dSJacob Faibussowitsch   else PetscCall(MatMult(pch2opus->M, x, y));
181*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18253022affSStefano Zampini }
18353022affSStefano Zampini 
184d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyMatKernel_H2OPUS(PC pc, Mat X, Mat Y, PetscBool t)
185d71ae5a4SJacob Faibussowitsch {
18653022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
18753022affSStefano Zampini 
18853022affSStefano Zampini   PetscFunctionBegin;
1899566063dSJacob Faibussowitsch   if (t) PetscCall(MatTransposeMatMult(pch2opus->M, X, MAT_REUSE_MATRIX, PETSC_DEFAULT, &Y));
1909566063dSJacob Faibussowitsch   else PetscCall(MatMatMult(pch2opus->M, X, MAT_REUSE_MATRIX, PETSC_DEFAULT, &Y));
191*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19253022affSStefano Zampini }
19353022affSStefano Zampini 
194d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyMat_H2OPUS(PC pc, Mat X, Mat Y)
195d71ae5a4SJacob Faibussowitsch {
19653022affSStefano Zampini   PetscFunctionBegin;
1979566063dSJacob Faibussowitsch   PetscCall(PCApplyMatKernel_H2OPUS(pc, X, Y, PETSC_FALSE));
198*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19953022affSStefano Zampini }
20053022affSStefano Zampini 
201d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTransposeMat_H2OPUS(PC pc, Mat X, Mat Y)
202d71ae5a4SJacob Faibussowitsch {
20353022affSStefano Zampini   PetscFunctionBegin;
2049566063dSJacob Faibussowitsch   PetscCall(PCApplyMatKernel_H2OPUS(pc, X, Y, PETSC_TRUE));
205*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20653022affSStefano Zampini }
20753022affSStefano Zampini 
208d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_H2OPUS(PC pc, Vec x, Vec y)
209d71ae5a4SJacob Faibussowitsch {
21053022affSStefano Zampini   PetscFunctionBegin;
2119566063dSJacob Faibussowitsch   PetscCall(PCApplyKernel_H2OPUS(pc, x, y, PETSC_FALSE));
212*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21353022affSStefano Zampini }
21453022affSStefano Zampini 
215d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_H2OPUS(PC pc, Vec x, Vec y)
216d71ae5a4SJacob Faibussowitsch {
21753022affSStefano Zampini   PetscFunctionBegin;
2189566063dSJacob Faibussowitsch   PetscCall(PCApplyKernel_H2OPUS(pc, x, y, PETSC_TRUE));
219*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22053022affSStefano Zampini }
22153022affSStefano Zampini 
22253022affSStefano Zampini /* used to test the norm of (M^-1 A - I) */
223d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultKernel_MAmI(Mat M, Vec x, Vec y, PetscBool t)
224d71ae5a4SJacob Faibussowitsch {
22553022affSStefano Zampini   PC         pc;
22653022affSStefano Zampini   Mat        A;
22753022affSStefano Zampini   PC_H2OPUS *pch2opus;
22853022affSStefano Zampini   PetscBool  sideleft = PETSC_TRUE;
22953022affSStefano Zampini 
23053022affSStefano Zampini   PetscFunctionBegin;
2319566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(M, (void *)&pc));
23253022affSStefano Zampini   pch2opus = (PC_H2OPUS *)pc->data;
2339566063dSJacob Faibussowitsch   if (!pch2opus->w) PetscCall(MatCreateVecs(pch2opus->M, &pch2opus->w, NULL));
23453022affSStefano Zampini   A = pch2opus->A;
2359566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->w, pch2opus->boundtocpu));
23653022affSStefano Zampini   if (t) {
23753022affSStefano Zampini     if (sideleft) {
2389566063dSJacob Faibussowitsch       PetscCall(PCApplyTranspose_H2OPUS(pc, x, pch2opus->w));
2399566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(A, pch2opus->w, y));
24053022affSStefano Zampini     } else {
2419566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(A, x, pch2opus->w));
2429566063dSJacob Faibussowitsch       PetscCall(PCApplyTranspose_H2OPUS(pc, pch2opus->w, y));
24353022affSStefano Zampini     }
24453022affSStefano Zampini   } else {
24553022affSStefano Zampini     if (sideleft) {
2469566063dSJacob Faibussowitsch       PetscCall(MatMult(A, x, pch2opus->w));
2479566063dSJacob Faibussowitsch       PetscCall(PCApply_H2OPUS(pc, pch2opus->w, y));
24853022affSStefano Zampini     } else {
2499566063dSJacob Faibussowitsch       PetscCall(PCApply_H2OPUS(pc, x, pch2opus->w));
2509566063dSJacob Faibussowitsch       PetscCall(MatMult(A, pch2opus->w, y));
25153022affSStefano Zampini     }
25253022affSStefano Zampini   }
2538db51263SStefano Zampini   PetscCall(VecAXPY(y, -1.0, x));
254*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25553022affSStefano Zampini }
25653022affSStefano Zampini 
257d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_MAmI(Mat A, Vec x, Vec y)
258d71ae5a4SJacob Faibussowitsch {
25953022affSStefano Zampini   PetscFunctionBegin;
2609566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_MAmI(A, x, y, PETSC_FALSE));
261*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26253022affSStefano Zampini }
26353022affSStefano Zampini 
264d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_MAmI(Mat A, Vec x, Vec y)
265d71ae5a4SJacob Faibussowitsch {
26653022affSStefano Zampini   PetscFunctionBegin;
2679566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_MAmI(A, x, y, PETSC_TRUE));
268*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26953022affSStefano Zampini }
27053022affSStefano Zampini 
27153022affSStefano Zampini /* HyperPower kernel:
27253022affSStefano Zampini Y = R = x
27353022affSStefano Zampini for i = 1 . . . l - 1 do
27453022affSStefano Zampini   R = (I - A * Xk) * R
27553022affSStefano Zampini   Y = Y + R
27653022affSStefano Zampini Y = Xk * Y
27753022affSStefano Zampini */
278d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultKernel_Hyper(Mat M, Vec x, Vec y, PetscBool t)
279d71ae5a4SJacob Faibussowitsch {
28053022affSStefano Zampini   PC         pc;
28153022affSStefano Zampini   Mat        A;
28253022affSStefano Zampini   PC_H2OPUS *pch2opus;
28353022affSStefano Zampini 
28453022affSStefano Zampini   PetscFunctionBegin;
2859566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(M, (void *)&pc));
28653022affSStefano Zampini   pch2opus = (PC_H2OPUS *)pc->data;
28753022affSStefano Zampini   A        = pch2opus->A;
2889566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pch2opus->M, pch2opus->wns[0] ? NULL : &pch2opus->wns[0], pch2opus->wns[1] ? NULL : &pch2opus->wns[1]));
2899566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pch2opus->M, pch2opus->wns[2] ? NULL : &pch2opus->wns[2], pch2opus->wns[3] ? NULL : &pch2opus->wns[3]));
2909566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[0], pch2opus->boundtocpu));
2919566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[1], pch2opus->boundtocpu));
2929566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[2], pch2opus->boundtocpu));
2939566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[3], pch2opus->boundtocpu));
2949566063dSJacob Faibussowitsch   PetscCall(VecCopy(x, pch2opus->wns[0]));
2959566063dSJacob Faibussowitsch   PetscCall(VecCopy(x, pch2opus->wns[3]));
29653022affSStefano Zampini   if (t) {
2975f80ce2aSJacob Faibussowitsch     for (PetscInt i = 0; i < pch2opus->hyperorder - 1; i++) {
2989566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(A, pch2opus->wns[0], pch2opus->wns[1]));
2999566063dSJacob Faibussowitsch       PetscCall(PCApplyTranspose_H2OPUS(pc, pch2opus->wns[1], pch2opus->wns[2]));
3009566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pch2opus->wns[0], -1., pch2opus->wns[2]));
3019566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pch2opus->wns[3], 1., pch2opus->wns[0]));
30253022affSStefano Zampini     }
3039566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose_H2OPUS(pc, pch2opus->wns[3], y));
30453022affSStefano Zampini   } else {
3055f80ce2aSJacob Faibussowitsch     for (PetscInt i = 0; i < pch2opus->hyperorder - 1; i++) {
3069566063dSJacob Faibussowitsch       PetscCall(PCApply_H2OPUS(pc, pch2opus->wns[0], pch2opus->wns[1]));
3079566063dSJacob Faibussowitsch       PetscCall(MatMult(A, pch2opus->wns[1], pch2opus->wns[2]));
3089566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pch2opus->wns[0], -1., pch2opus->wns[2]));
3099566063dSJacob Faibussowitsch       PetscCall(VecAXPY(pch2opus->wns[3], 1., pch2opus->wns[0]));
31053022affSStefano Zampini     }
3119566063dSJacob Faibussowitsch     PetscCall(PCApply_H2OPUS(pc, pch2opus->wns[3], y));
31253022affSStefano Zampini   }
313*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31453022affSStefano Zampini }
31553022affSStefano Zampini 
316d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Hyper(Mat M, Vec x, Vec y)
317d71ae5a4SJacob Faibussowitsch {
31853022affSStefano Zampini   PetscFunctionBegin;
3199566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_Hyper(M, x, y, PETSC_FALSE));
320*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32153022affSStefano Zampini }
32253022affSStefano Zampini 
323d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Hyper(Mat M, Vec x, Vec y)
324d71ae5a4SJacob Faibussowitsch {
32553022affSStefano Zampini   PetscFunctionBegin;
3269566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_Hyper(M, x, y, PETSC_TRUE));
327*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32853022affSStefano Zampini }
32953022affSStefano Zampini 
33053022affSStefano Zampini /* Hyper power kernel, MatMat version */
331d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatMultKernel_Hyper(Mat M, Mat X, Mat Y, PetscBool t)
332d71ae5a4SJacob Faibussowitsch {
33353022affSStefano Zampini   PC         pc;
33453022affSStefano Zampini   Mat        A;
33553022affSStefano Zampini   PC_H2OPUS *pch2opus;
33653022affSStefano Zampini   PetscInt   i;
33753022affSStefano Zampini 
33853022affSStefano Zampini   PetscFunctionBegin;
3399566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(M, (void *)&pc));
34053022affSStefano Zampini   pch2opus = (PC_H2OPUS *)pc->data;
34153022affSStefano Zampini   A        = pch2opus->A;
34253022affSStefano Zampini   if (pch2opus->wnsmat[0] && pch2opus->wnsmat[0]->cmap->N != X->cmap->N) {
3439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[0]));
3449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[1]));
34553022affSStefano Zampini   }
34653022affSStefano Zampini   if (!pch2opus->wnsmat[0]) {
3479566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(X, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[0]));
3489566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Y, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[1]));
34953022affSStefano Zampini   }
35053022affSStefano Zampini   if (pch2opus->wnsmat[2] && pch2opus->wnsmat[2]->cmap->N != X->cmap->N) {
3519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[2]));
3529566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[3]));
35353022affSStefano Zampini   }
35453022affSStefano Zampini   if (!pch2opus->wnsmat[2]) {
3559566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(X, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[2]));
3569566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Y, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[3]));
35753022affSStefano Zampini   }
3589566063dSJacob Faibussowitsch   PetscCall(MatCopy(X, pch2opus->wnsmat[0], SAME_NONZERO_PATTERN));
3599566063dSJacob Faibussowitsch   PetscCall(MatCopy(X, pch2opus->wnsmat[3], SAME_NONZERO_PATTERN));
36053022affSStefano Zampini   if (t) {
36153022affSStefano Zampini     for (i = 0; i < pch2opus->hyperorder - 1; i++) {
3629566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(A, pch2opus->wnsmat[0], MAT_REUSE_MATRIX, PETSC_DEFAULT, &pch2opus->wnsmat[1]));
3639566063dSJacob Faibussowitsch       PetscCall(PCApplyTransposeMat_H2OPUS(pc, pch2opus->wnsmat[1], pch2opus->wnsmat[2]));
3649566063dSJacob Faibussowitsch       PetscCall(MatAXPY(pch2opus->wnsmat[0], -1., pch2opus->wnsmat[2], SAME_NONZERO_PATTERN));
3659566063dSJacob Faibussowitsch       PetscCall(MatAXPY(pch2opus->wnsmat[3], 1., pch2opus->wnsmat[0], SAME_NONZERO_PATTERN));
36653022affSStefano Zampini     }
3679566063dSJacob Faibussowitsch     PetscCall(PCApplyTransposeMat_H2OPUS(pc, pch2opus->wnsmat[3], Y));
36853022affSStefano Zampini   } else {
36953022affSStefano Zampini     for (i = 0; i < pch2opus->hyperorder - 1; i++) {
3709566063dSJacob Faibussowitsch       PetscCall(PCApplyMat_H2OPUS(pc, pch2opus->wnsmat[0], pch2opus->wnsmat[1]));
3719566063dSJacob Faibussowitsch       PetscCall(MatMatMult(A, pch2opus->wnsmat[1], MAT_REUSE_MATRIX, PETSC_DEFAULT, &pch2opus->wnsmat[2]));
3729566063dSJacob Faibussowitsch       PetscCall(MatAXPY(pch2opus->wnsmat[0], -1., pch2opus->wnsmat[2], SAME_NONZERO_PATTERN));
3739566063dSJacob Faibussowitsch       PetscCall(MatAXPY(pch2opus->wnsmat[3], 1., pch2opus->wnsmat[0], SAME_NONZERO_PATTERN));
37453022affSStefano Zampini     }
3759566063dSJacob Faibussowitsch     PetscCall(PCApplyMat_H2OPUS(pc, pch2opus->wnsmat[3], Y));
37653022affSStefano Zampini   }
377*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37853022affSStefano Zampini }
37953022affSStefano Zampini 
380d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatMultNumeric_Hyper(Mat M, Mat X, Mat Y, void *ctx)
381d71ae5a4SJacob Faibussowitsch {
38253022affSStefano Zampini   PetscFunctionBegin;
3839566063dSJacob Faibussowitsch   PetscCall(MatMatMultKernel_Hyper(M, X, Y, PETSC_FALSE));
384*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38553022affSStefano Zampini }
38653022affSStefano Zampini 
38753022affSStefano Zampini /* Basic Newton-Schultz sampler: (2 * I - M * A)*M */
388d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultKernel_NS(Mat M, Vec x, Vec y, PetscBool t)
389d71ae5a4SJacob Faibussowitsch {
39053022affSStefano Zampini   PC         pc;
39153022affSStefano Zampini   Mat        A;
39253022affSStefano Zampini   PC_H2OPUS *pch2opus;
39353022affSStefano Zampini 
39453022affSStefano Zampini   PetscFunctionBegin;
3959566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(M, (void *)&pc));
39653022affSStefano Zampini   pch2opus = (PC_H2OPUS *)pc->data;
39753022affSStefano Zampini   A        = pch2opus->A;
3989566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(pch2opus->M, pch2opus->wns[0] ? NULL : &pch2opus->wns[0], pch2opus->wns[1] ? NULL : &pch2opus->wns[1]));
3999566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[0], pch2opus->boundtocpu));
4009566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(pch2opus->wns[1], pch2opus->boundtocpu));
40153022affSStefano Zampini   if (t) {
4029566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose_H2OPUS(pc, x, y));
4039566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, y, pch2opus->wns[1]));
4049566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose_H2OPUS(pc, pch2opus->wns[1], pch2opus->wns[0]));
4059566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(y, -1., 2., pch2opus->wns[0]));
40653022affSStefano Zampini   } else {
4079566063dSJacob Faibussowitsch     PetscCall(PCApply_H2OPUS(pc, x, y));
4089566063dSJacob Faibussowitsch     PetscCall(MatMult(A, y, pch2opus->wns[0]));
4099566063dSJacob Faibussowitsch     PetscCall(PCApply_H2OPUS(pc, pch2opus->wns[0], pch2opus->wns[1]));
4109566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(y, -1., 2., pch2opus->wns[1]));
41153022affSStefano Zampini   }
412*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41353022affSStefano Zampini }
41453022affSStefano Zampini 
415d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_NS(Mat M, Vec x, Vec y)
416d71ae5a4SJacob Faibussowitsch {
41753022affSStefano Zampini   PetscFunctionBegin;
4189566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_NS(M, x, y, PETSC_FALSE));
419*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42053022affSStefano Zampini }
42153022affSStefano Zampini 
422d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_NS(Mat M, Vec x, Vec y)
423d71ae5a4SJacob Faibussowitsch {
42453022affSStefano Zampini   PetscFunctionBegin;
4259566063dSJacob Faibussowitsch   PetscCall(MatMultKernel_NS(M, x, y, PETSC_TRUE));
426*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42753022affSStefano Zampini }
42853022affSStefano Zampini 
42953022affSStefano Zampini /* Basic Newton-Schultz sampler: (2 * I - M * A)*M, MatMat version */
430d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatMultKernel_NS(Mat M, Mat X, Mat Y, PetscBool t)
431d71ae5a4SJacob Faibussowitsch {
43253022affSStefano Zampini   PC         pc;
43353022affSStefano Zampini   Mat        A;
43453022affSStefano Zampini   PC_H2OPUS *pch2opus;
43553022affSStefano Zampini 
43653022affSStefano Zampini   PetscFunctionBegin;
4379566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(M, (void *)&pc));
43853022affSStefano Zampini   pch2opus = (PC_H2OPUS *)pc->data;
43953022affSStefano Zampini   A        = pch2opus->A;
44053022affSStefano Zampini   if (pch2opus->wnsmat[0] && pch2opus->wnsmat[0]->cmap->N != X->cmap->N) {
4419566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[0]));
4429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&pch2opus->wnsmat[1]));
44353022affSStefano Zampini   }
44453022affSStefano Zampini   if (!pch2opus->wnsmat[0]) {
4459566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(X, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[0]));
4469566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Y, MAT_SHARE_NONZERO_PATTERN, &pch2opus->wnsmat[1]));
44753022affSStefano Zampini   }
44853022affSStefano Zampini   if (t) {
4499566063dSJacob Faibussowitsch     PetscCall(PCApplyTransposeMat_H2OPUS(pc, X, Y));
4509566063dSJacob Faibussowitsch     PetscCall(MatTransposeMatMult(A, Y, MAT_REUSE_MATRIX, PETSC_DEFAULT, &pch2opus->wnsmat[1]));
4519566063dSJacob Faibussowitsch     PetscCall(PCApplyTransposeMat_H2OPUS(pc, pch2opus->wnsmat[1], pch2opus->wnsmat[0]));
4529566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 2.));
4539566063dSJacob Faibussowitsch     PetscCall(MatAXPY(Y, -1., pch2opus->wnsmat[0], SAME_NONZERO_PATTERN));
45453022affSStefano Zampini   } else {
4559566063dSJacob Faibussowitsch     PetscCall(PCApplyMat_H2OPUS(pc, X, Y));
4569566063dSJacob Faibussowitsch     PetscCall(MatMatMult(A, Y, MAT_REUSE_MATRIX, PETSC_DEFAULT, &pch2opus->wnsmat[0]));
4579566063dSJacob Faibussowitsch     PetscCall(PCApplyMat_H2OPUS(pc, pch2opus->wnsmat[0], pch2opus->wnsmat[1]));
4589566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 2.));
4599566063dSJacob Faibussowitsch     PetscCall(MatAXPY(Y, -1., pch2opus->wnsmat[1], SAME_NONZERO_PATTERN));
46053022affSStefano Zampini   }
461*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46253022affSStefano Zampini }
46353022affSStefano Zampini 
464d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatMultNumeric_NS(Mat M, Mat X, Mat Y, void *ctx)
465d71ae5a4SJacob Faibussowitsch {
46653022affSStefano Zampini   PetscFunctionBegin;
4679566063dSJacob Faibussowitsch   PetscCall(MatMatMultKernel_NS(M, X, Y, PETSC_FALSE));
468*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46953022affSStefano Zampini }
47053022affSStefano Zampini 
471d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCH2OpusSetUpSampler_Private(PC pc)
472d71ae5a4SJacob Faibussowitsch {
47353022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
47453022affSStefano Zampini   Mat        A        = pc->useAmat ? pc->mat : pc->pmat;
47553022affSStefano Zampini 
47653022affSStefano Zampini   PetscFunctionBegin;
47753022affSStefano Zampini   if (!pch2opus->S) {
47853022affSStefano Zampini     PetscInt M, N, m, n;
47953022affSStefano Zampini 
4809566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, &N));
4819566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, &n));
4829566063dSJacob Faibussowitsch     PetscCall(MatCreateShell(PetscObjectComm((PetscObject)A), m, n, M, N, pc, &pch2opus->S));
4839566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(pch2opus->S, A, A));
48453022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
4859566063dSJacob Faibussowitsch     PetscCall(MatShellSetVecType(pch2opus->S, VECCUDA));
48653022affSStefano Zampini #endif
48753022affSStefano Zampini   }
48853022affSStefano Zampini   if (pch2opus->hyperorder >= 2) {
4899566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->S, MATOP_MULT, (void (*)(void))MatMult_Hyper));
4909566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->S, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Hyper));
4919566063dSJacob Faibussowitsch     PetscCall(MatShellSetMatProductOperation(pch2opus->S, MATPRODUCT_AB, NULL, MatMatMultNumeric_Hyper, NULL, MATDENSE, MATDENSE));
4929566063dSJacob Faibussowitsch     PetscCall(MatShellSetMatProductOperation(pch2opus->S, MATPRODUCT_AB, NULL, MatMatMultNumeric_Hyper, NULL, MATDENSECUDA, MATDENSECUDA));
49353022affSStefano Zampini   } else {
4949566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->S, MATOP_MULT, (void (*)(void))MatMult_NS));
4959566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->S, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_NS));
4969566063dSJacob Faibussowitsch     PetscCall(MatShellSetMatProductOperation(pch2opus->S, MATPRODUCT_AB, NULL, MatMatMultNumeric_NS, NULL, MATDENSE, MATDENSE));
4979566063dSJacob Faibussowitsch     PetscCall(MatShellSetMatProductOperation(pch2opus->S, MATPRODUCT_AB, NULL, MatMatMultNumeric_NS, NULL, MATDENSECUDA, MATDENSECUDA));
49853022affSStefano Zampini   }
4999566063dSJacob Faibussowitsch   PetscCall(MatPropagateSymmetryOptions(A, pch2opus->S));
5009566063dSJacob Faibussowitsch   PetscCall(MatBindToCPU(pch2opus->S, pch2opus->boundtocpu));
50153022affSStefano Zampini   /* XXX */
5029566063dSJacob Faibussowitsch   PetscCall(MatSetOption(pch2opus->S, MAT_SYMMETRIC, PETSC_TRUE));
503*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50453022affSStefano Zampini }
50553022affSStefano Zampini 
506d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_H2OPUS(PC pc)
507d71ae5a4SJacob Faibussowitsch {
50853022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
50953022affSStefano Zampini   Mat        A        = pc->useAmat ? pc->mat : pc->pmat;
51053022affSStefano Zampini   NormType   norm     = pch2opus->normtype;
51153022affSStefano Zampini   PetscReal  initerr  = 0.0, err;
51253022affSStefano Zampini   PetscBool  ish2opus;
51353022affSStefano Zampini 
51453022affSStefano Zampini   PetscFunctionBegin;
51553022affSStefano Zampini   if (!pch2opus->T) {
51653022affSStefano Zampini     PetscInt    M, N, m, n;
51753022affSStefano Zampini     const char *prefix;
51853022affSStefano Zampini 
5199566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
5209566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, &N));
5219566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, &n));
5229566063dSJacob Faibussowitsch     PetscCall(MatCreateShell(PetscObjectComm((PetscObject)pc->pmat), m, n, M, N, pc, &pch2opus->T));
5239566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(pch2opus->T, A, A));
5249566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->T, MATOP_MULT, (void (*)(void))MatMult_MAmI));
5259566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->T, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_MAmI));
5269566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(pch2opus->T, MATOP_NORM, (void (*)(void))MatNorm_H2OPUS));
52753022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
5289566063dSJacob Faibussowitsch     PetscCall(MatShellSetVecType(pch2opus->T, VECCUDA));
52953022affSStefano Zampini #endif
5309566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pch2opus->T, prefix));
5319566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(pch2opus->T, "pc_h2opus_est_"));
53253022affSStefano Zampini   }
5339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->A));
5349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATH2OPUS, &ish2opus));
53553022affSStefano Zampini   if (ish2opus) {
5369566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
53753022affSStefano Zampini     pch2opus->A = A;
53853022affSStefano Zampini   } else {
53953022affSStefano Zampini     const char *prefix;
5409566063dSJacob Faibussowitsch     PetscCall(MatCreateH2OpusFromMat(A, pch2opus->sdim, pch2opus->coords, PETSC_FALSE, pch2opus->eta, pch2opus->leafsize, pch2opus->max_rank, pch2opus->bs, pch2opus->mrtol, &pch2opus->A));
54153022affSStefano Zampini     /* XXX */
5429566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pch2opus->A, MAT_SYMMETRIC, PETSC_TRUE));
5439566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
5449566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pch2opus->A, prefix));
5459566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(pch2opus->A, "pc_h2opus_init_"));
5469566063dSJacob Faibussowitsch     PetscCall(MatSetFromOptions(pch2opus->A));
5479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(pch2opus->A, MAT_FINAL_ASSEMBLY));
5489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(pch2opus->A, MAT_FINAL_ASSEMBLY));
54953022affSStefano Zampini     /* XXX */
5509566063dSJacob Faibussowitsch     PetscCall(MatSetOption(pch2opus->A, MAT_SYMMETRIC, PETSC_TRUE));
5518db51263SStefano Zampini 
5528db51263SStefano Zampini     /* always perform construction on the GPU unless forcecpu is true */
5538db51263SStefano Zampini     PetscCall(MatBindToCPU(pch2opus->A, pch2opus->forcecpu));
55453022affSStefano Zampini   }
55553022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
5568db51263SStefano Zampini   pch2opus->boundtocpu = pch2opus->forcecpu ? PETSC_TRUE : pch2opus->A->boundtocpu;
55753022affSStefano Zampini #endif
5589566063dSJacob Faibussowitsch   PetscCall(MatBindToCPU(pch2opus->T, pch2opus->boundtocpu));
55953022affSStefano Zampini   if (pch2opus->M) { /* see if we can reuse M as initial guess */
56053022affSStefano Zampini     PetscReal reuse;
56153022affSStefano Zampini 
5629566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(pch2opus->M, pch2opus->boundtocpu));
5639566063dSJacob Faibussowitsch     PetscCall(MatNorm(pch2opus->T, norm, &reuse));
5649566063dSJacob Faibussowitsch     if (reuse >= 1.0) PetscCall(MatDestroy(&pch2opus->M));
56553022affSStefano Zampini   }
56653022affSStefano Zampini   if (!pch2opus->M) {
56753022affSStefano Zampini     const char *prefix;
5689566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(pch2opus->A, MAT_COPY_VALUES, &pch2opus->M));
5699566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
5709566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(pch2opus->M, prefix));
5719566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(pch2opus->M, "pc_h2opus_inv_"));
5729566063dSJacob Faibussowitsch     PetscCall(MatSetFromOptions(pch2opus->M));
5739566063dSJacob Faibussowitsch     PetscCall(PCH2OpusSetUpInit(pc));
5749566063dSJacob Faibussowitsch     PetscCall(MatScale(pch2opus->M, pch2opus->s0));
57553022affSStefano Zampini   }
57653022affSStefano Zampini   /* A and M have the same h2 matrix structure, save on reordering routines */
5779566063dSJacob Faibussowitsch   PetscCall(MatH2OpusSetNativeMult(pch2opus->A, PETSC_TRUE));
5789566063dSJacob Faibussowitsch   PetscCall(MatH2OpusSetNativeMult(pch2opus->M, PETSC_TRUE));
5798db51263SStefano Zampini   if (norm == NORM_1 || norm == NORM_2 || norm == NORM_INFINITY) PetscCall(MatNorm(pch2opus->T, norm, &initerr));
58053022affSStefano Zampini   if (PetscIsInfOrNanReal(initerr)) pc->failedreason = PC_SETUP_ERROR;
58153022affSStefano Zampini   err = initerr;
58248a46eb9SPierre Jolivet   if (pch2opus->monitor) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)pc), "%" PetscInt_FMT ": ||M*A - I|| NORM%s abs %g rel %g\n", 0, NormTypes[norm], (double)err, (double)(err / initerr)));
58353022affSStefano Zampini   if (initerr > pch2opus->atol && !pc->failedreason) {
58453022affSStefano Zampini     PetscInt i;
58553022affSStefano Zampini 
5869566063dSJacob Faibussowitsch     PetscCall(PCH2OpusSetUpSampler_Private(pc));
58753022affSStefano Zampini     for (i = 0; i < pch2opus->maxits; i++) {
58853022affSStefano Zampini       Mat         M;
58953022affSStefano Zampini       const char *prefix;
59053022affSStefano Zampini 
5919566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(pch2opus->M, MAT_SHARE_NONZERO_PATTERN, &M));
5929566063dSJacob Faibussowitsch       PetscCall(MatGetOptionsPrefix(pch2opus->M, &prefix));
5939566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(M, prefix));
5949566063dSJacob Faibussowitsch       PetscCall(MatH2OpusSetSamplingMat(M, pch2opus->S, PETSC_DECIDE, PETSC_DECIDE));
5959566063dSJacob Faibussowitsch       PetscCall(MatSetFromOptions(M));
5969566063dSJacob Faibussowitsch       PetscCall(MatH2OpusSetNativeMult(M, PETSC_TRUE));
5979566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY));
5989566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY));
5999566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&pch2opus->M));
60053022affSStefano Zampini       pch2opus->M = M;
6018db51263SStefano Zampini       if (norm == NORM_1 || norm == NORM_2 || norm == NORM_INFINITY) PetscCall(MatNorm(pch2opus->T, norm, &err));
60248a46eb9SPierre Jolivet       if (pch2opus->monitor) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)pc), "%" PetscInt_FMT ": ||M*A - I|| NORM%s abs %g rel %g\n", i + 1, NormTypes[norm], (double)err, (double)(err / initerr)));
60353022affSStefano Zampini       if (PetscIsInfOrNanReal(err)) pc->failedreason = PC_SETUP_ERROR;
60453022affSStefano Zampini       if (err < pch2opus->atol || err < pch2opus->rtol * initerr || pc->failedreason) break;
60553022affSStefano Zampini     }
60653022affSStefano Zampini   }
60753022affSStefano Zampini   /* cleanup setup workspace */
6089566063dSJacob Faibussowitsch   PetscCall(MatH2OpusSetNativeMult(pch2opus->A, PETSC_FALSE));
6099566063dSJacob Faibussowitsch   PetscCall(MatH2OpusSetNativeMult(pch2opus->M, PETSC_FALSE));
6109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[0]));
6119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[1]));
6129566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[2]));
6139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pch2opus->wns[3]));
6149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[0]));
6159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[1]));
6169566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[2]));
6179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&pch2opus->wnsmat[3]));
618*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61953022affSStefano Zampini }
62053022affSStefano Zampini 
621d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_H2OPUS(PC pc, PetscViewer viewer)
622d71ae5a4SJacob Faibussowitsch {
62353022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS *)pc->data;
62453022affSStefano Zampini   PetscBool  isascii;
62553022affSStefano Zampini 
62653022affSStefano Zampini   PetscFunctionBegin;
6279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
62853022affSStefano Zampini   if (isascii) {
62953022affSStefano Zampini     if (pch2opus->A && pch2opus->A != pc->mat && pch2opus->A != pc->pmat) {
6309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Initial approximation matrix\n"));
6319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
6329566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO_DETAIL));
6339566063dSJacob Faibussowitsch       PetscCall(MatView(pch2opus->A, viewer));
6349566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
6359566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
63653022affSStefano Zampini     }
63753022affSStefano Zampini     if (pch2opus->M) {
6389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Inner matrix constructed\n"));
6399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
6409566063dSJacob Faibussowitsch       PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO_DETAIL));
6419566063dSJacob Faibussowitsch       PetscCall(MatView(pch2opus->M, viewer));
6429566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
6439566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
64453022affSStefano Zampini     }
6459566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial scaling: %g\n", pch2opus->s0));
64653022affSStefano Zampini   }
647*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64853022affSStefano Zampini }
64953022affSStefano Zampini 
650f1580f4eSBarry Smith /*MC
651f1580f4eSBarry Smith      PCH2OPUS = "h2opus" - A preconditioner type for, `MATH2OPUS`, hierarchical matrices using the H2Opus package.
652f1580f4eSBarry Smith 
653f1580f4eSBarry Smith    Options Database Keys:
654f1580f4eSBarry Smith +   -pc_type h2opus - pc type to "h2opus" during a call to `PCSetFromOptions()`
655f1580f4eSBarry Smith .   -pc_h2opus_maxits - maximum number of iterations for Newton-Schultz
656f1580f4eSBarry Smith .   -pc_h2opus_monitor - monitor Newton-Schultz convergence
657f1580f4eSBarry Smith .   -pc_h2opus_atol - absolute tolerance
658f1580f4eSBarry Smith .   -pc_h2opus_rtol - relative tolerance
659f1580f4eSBarry Smith .   -pc_h2opus_norm_type - normtype
660f1580f4eSBarry Smith .   -pc_h2opus_hyperorder - Hyper power order of sampling
661f1580f4eSBarry Smith .   -pc_h2opus_leafsize - leaf size when constructed from kernel
662f1580f4eSBarry Smith .   -pc_h2opus_eta - admissibility condition tolerance
663f1580f4eSBarry Smith .   -pc_h2opus_maxrank - maximum rank when constructed from matvecs
664f1580f4eSBarry Smith .   -pc_h2opus_samples - number of samples to be taken concurrently when constructing from matvecs
665f1580f4eSBarry Smith .   -pc_h2opus_mrtol - relative tolerance for construction from sampling
666f1580f4eSBarry Smith -   -pc_h2opus_forcecpu - force construction of preconditioner on CPU
667f1580f4eSBarry Smith 
668f1580f4eSBarry Smith    Level: intermediate
669f1580f4eSBarry Smith 
670f1580f4eSBarry Smith .seealso: `MATH2OPUS`, `MATHTOOL`, `MATDENSE`, `MatCreateH2OpusFromKernel()`, `MatCreateH2OpusFromMat()`
671f1580f4eSBarry Smith M*/
672f1580f4eSBarry Smith 
673d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_H2OPUS(PC pc)
674d71ae5a4SJacob Faibussowitsch {
67553022affSStefano Zampini   PC_H2OPUS *pch2opus;
67653022affSStefano Zampini 
67753022affSStefano Zampini   PetscFunctionBegin;
6784dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pch2opus));
67953022affSStefano Zampini   pc->data = (void *)pch2opus;
68053022affSStefano Zampini 
68153022affSStefano Zampini   pch2opus->atol       = 1.e-2;
68253022affSStefano Zampini   pch2opus->rtol       = 1.e-6;
68353022affSStefano Zampini   pch2opus->maxits     = 50;
684f1580f4eSBarry Smith   pch2opus->hyperorder = 1; /* defaults to basic Newton-Schultz */
68553022affSStefano Zampini   pch2opus->normtype   = NORM_2;
68653022affSStefano Zampini 
68753022affSStefano Zampini   /* these are needed when we are sampling the pmat */
68853022affSStefano Zampini   pch2opus->eta      = PETSC_DECIDE;
68953022affSStefano Zampini   pch2opus->leafsize = PETSC_DECIDE;
69053022affSStefano Zampini   pch2opus->max_rank = PETSC_DECIDE;
69153022affSStefano Zampini   pch2opus->bs       = PETSC_DECIDE;
69253022affSStefano Zampini   pch2opus->mrtol    = PETSC_DECIDE;
69353022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
69453022affSStefano Zampini   pch2opus->boundtocpu = PETSC_FALSE;
69553022affSStefano Zampini #else
69653022affSStefano Zampini   pch2opus->boundtocpu = PETSC_TRUE;
69753022affSStefano Zampini #endif
69853022affSStefano Zampini   pc->ops->destroy        = PCDestroy_H2OPUS;
69953022affSStefano Zampini   pc->ops->setup          = PCSetUp_H2OPUS;
70053022affSStefano Zampini   pc->ops->apply          = PCApply_H2OPUS;
70153022affSStefano Zampini   pc->ops->matapply       = PCApplyMat_H2OPUS;
70253022affSStefano Zampini   pc->ops->applytranspose = PCApplyTranspose_H2OPUS;
70353022affSStefano Zampini   pc->ops->reset          = PCReset_H2OPUS;
70453022affSStefano Zampini   pc->ops->setfromoptions = PCSetFromOptions_H2OPUS;
70553022affSStefano Zampini   pc->ops->view           = PCView_H2OPUS;
70653022affSStefano Zampini 
7079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_H2OPUS));
708*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70953022affSStefano Zampini }
710