xref: /petsc/src/ksp/pc/impls/h2opus/pch2opus.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
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   PetscBool testMA;
2553022affSStefano Zampini 
2653022affSStefano Zampini   /* Support for PCSetCoordinates */
2753022affSStefano Zampini   PetscInt  sdim;
2853022affSStefano Zampini   PetscInt  nlocc;
2953022affSStefano Zampini   PetscReal *coords;
3053022affSStefano Zampini 
3153022affSStefano Zampini   /* Newton-Schultz customization */
3253022affSStefano Zampini   PetscInt  maxits;
3353022affSStefano Zampini   PetscReal rtol,atol;
3453022affSStefano Zampini   PetscBool monitor;
3553022affSStefano Zampini   PetscBool useapproximatenorms;
3653022affSStefano Zampini   NormType  normtype;
3753022affSStefano Zampini 
3853022affSStefano Zampini   /* Used when pmat != MATH2OPUS */
3953022affSStefano Zampini   PetscReal eta;
4053022affSStefano Zampini   PetscInt  leafsize;
4153022affSStefano Zampini   PetscInt  max_rank;
4253022affSStefano Zampini   PetscInt  bs;
4353022affSStefano Zampini   PetscReal mrtol;
4453022affSStefano Zampini 
4553022affSStefano Zampini   PetscBool boundtocpu;
4653022affSStefano Zampini } PC_H2OPUS;
4753022affSStefano Zampini 
4853022affSStefano Zampini PETSC_EXTERN PetscErrorCode MatNorm_H2OPUS(Mat,NormType,PetscReal*);
4953022affSStefano Zampini 
5053022affSStefano Zampini static PetscErrorCode PCReset_H2OPUS(PC pc)
5153022affSStefano Zampini {
5253022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
5353022affSStefano Zampini 
5453022affSStefano Zampini   PetscFunctionBegin;
5553022affSStefano Zampini   pch2opus->sdim  = 0;
5653022affSStefano Zampini   pch2opus->nlocc = 0;
57*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pch2opus->coords));
58*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->A));
59*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->M));
60*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->T));
61*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->w));
62*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->S));
63*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[0]));
64*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[1]));
65*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[2]));
66*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[3]));
67*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[0]));
68*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[1]));
69*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[2]));
70*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[3]));
7153022affSStefano Zampini   PetscFunctionReturn(0);
7253022affSStefano Zampini }
7353022affSStefano Zampini 
7453022affSStefano Zampini static PetscErrorCode PCSetCoordinates_H2OPUS(PC pc, PetscInt sdim, PetscInt nlocc, PetscReal *coords)
7553022affSStefano Zampini {
7653022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
7753022affSStefano Zampini   PetscBool  reset    = PETSC_TRUE;
7853022affSStefano Zampini 
7953022affSStefano Zampini   PetscFunctionBegin;
8053022affSStefano Zampini   if (pch2opus->sdim && sdim == pch2opus->sdim && nlocc == pch2opus->nlocc) {
81*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArraycmp(pch2opus->coords,coords,sdim*nlocc,&reset));
8253022affSStefano Zampini     reset = (PetscBool)!reset;
8353022affSStefano Zampini   }
84*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPIU_Allreduce(MPI_IN_PLACE,&reset,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc)));
8553022affSStefano Zampini   if (reset) {
86*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCReset_H2OPUS(pc));
87*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(sdim*nlocc,&pch2opus->coords));
88*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArraycpy(pch2opus->coords,coords,sdim*nlocc));
8953022affSStefano Zampini     pch2opus->sdim  = sdim;
9053022affSStefano Zampini     pch2opus->nlocc = nlocc;
9153022affSStefano Zampini   }
9253022affSStefano Zampini   PetscFunctionReturn(0);
9353022affSStefano Zampini }
9453022affSStefano Zampini 
9553022affSStefano Zampini static PetscErrorCode PCDestroy_H2OPUS(PC pc)
9653022affSStefano Zampini {
9753022affSStefano Zampini   PetscFunctionBegin;
98*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCReset_H2OPUS(pc));
99*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",NULL));
100*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pc->data));
10153022affSStefano Zampini   PetscFunctionReturn(0);
10253022affSStefano Zampini }
10353022affSStefano Zampini 
10453022affSStefano Zampini static PetscErrorCode PCSetFromOptions_H2OPUS(PetscOptionItems *PetscOptionsObject,PC pc)
10553022affSStefano Zampini {
10653022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
10753022affSStefano Zampini 
10853022affSStefano Zampini   PetscFunctionBegin;
109*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"H2OPUS options"));
110*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsInt("-pc_h2opus_maxits","Maximum number of iterations for Newton-Schultz",NULL,pch2opus->maxits,&pch2opus->maxits,NULL));
111*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-pc_h2opus_monitor","Monitor Newton-Schultz convergence",NULL,pch2opus->monitor,&pch2opus->monitor,NULL));
112*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsReal("-pc_h2opus_atol","Absolute tolerance",NULL,pch2opus->atol,&pch2opus->atol,NULL));
113*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsReal("-pc_h2opus_rtol","Relative tolerance",NULL,pch2opus->rtol,&pch2opus->rtol,NULL));
114*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsEnum("-pc_h2opus_norm_type","Norm type for convergence monitoring",NULL,NormTypes,(PetscEnum)pch2opus->normtype,(PetscEnum*)&pch2opus->normtype,NULL));
115*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsInt("-pc_h2opus_hyperorder","Hyper power order of sampling",NULL,pch2opus->hyperorder,&pch2opus->hyperorder,NULL));
116*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsInt("-pc_h2opus_leafsize","Leaf size when constructed from kernel",NULL,pch2opus->leafsize,&pch2opus->leafsize,NULL));
117*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsReal("-pc_h2opus_eta","Admissibility condition tolerance",NULL,pch2opus->eta,&pch2opus->eta,NULL));
118*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsInt("-pc_h2opus_maxrank","Maximum rank when constructed from matvecs",NULL,pch2opus->max_rank,&pch2opus->max_rank,NULL));
119*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsInt("-pc_h2opus_samples","Number of samples to be taken concurrently when constructing from matvecs",NULL,pch2opus->bs,&pch2opus->bs,NULL));
120*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsReal("-pc_h2opus_mrtol","Relative tolerance for construction from sampling",NULL,pch2opus->mrtol,&pch2opus->mrtol,NULL));
121*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsTail());
12253022affSStefano Zampini   PetscFunctionReturn(0);
12353022affSStefano Zampini }
12453022affSStefano Zampini 
12553022affSStefano Zampini typedef struct {
12653022affSStefano Zampini   Mat A;
12753022affSStefano Zampini   Mat M;
12853022affSStefano Zampini   Vec w;
12953022affSStefano Zampini } AAtCtx;
13053022affSStefano Zampini 
13153022affSStefano Zampini static PetscErrorCode MatMult_AAt(Mat A, Vec x, Vec y)
13253022affSStefano Zampini {
13353022affSStefano Zampini   AAtCtx *aat;
13453022affSStefano Zampini 
13553022affSStefano Zampini   PetscFunctionBegin;
136*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(A,(void*)&aat));
137*5f80ce2aSJacob Faibussowitsch   /* CHKERRQ(MatMultTranspose(aat->M,x,aat->w)); */
138*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultTranspose(aat->A,x,aat->w));
139*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMult(aat->A,aat->w,y));
14053022affSStefano Zampini   PetscFunctionReturn(0);
14153022affSStefano Zampini }
14253022affSStefano Zampini 
14353022affSStefano Zampini static PetscErrorCode PCH2OpusSetUpInit(PC pc)
14453022affSStefano Zampini {
14553022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
14653022affSStefano Zampini   Mat        A        = pc->useAmat ? pc->mat : pc->pmat, AAt;
14753022affSStefano Zampini   PetscInt   M,m;
14853022affSStefano Zampini   VecType    vtype;
14953022affSStefano Zampini   PetscReal  n;
15053022affSStefano Zampini   AAtCtx     aat;
15153022affSStefano Zampini 
15253022affSStefano Zampini   PetscFunctionBegin;
15353022affSStefano Zampini   aat.A = A;
15453022affSStefano Zampini   aat.M = pch2opus->M; /* unused so far */
155*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(A,NULL,&aat.w));
156*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetSize(A,&M,NULL));
157*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetLocalSize(A,&m,NULL));
158*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateShell(PetscObjectComm((PetscObject)A),m,m,M,M,&aat,&AAt));
159*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatBindToCPU(AAt,pch2opus->boundtocpu));
160*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetOperation(AAt,MATOP_MULT,(void (*)(void))MatMult_AAt));
161*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetOperation(AAt,MATOP_MULT_TRANSPOSE,(void (*)(void))MatMult_AAt));
162*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetOperation(AAt,MATOP_NORM,(void (*)(void))MatNorm_H2OPUS));
163*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetVecType(A,&vtype));
164*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetVecType(AAt,vtype));
165*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatNorm(AAt,NORM_1,&n));
16653022affSStefano Zampini   pch2opus->s0 = 1./n;
167*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&aat.w));
168*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&AAt));
16953022affSStefano Zampini   PetscFunctionReturn(0);
17053022affSStefano Zampini }
17153022affSStefano Zampini 
17253022affSStefano Zampini static PetscErrorCode PCApplyKernel_H2OPUS(PC pc, Vec x, Vec y, PetscBool t)
17353022affSStefano Zampini {
17453022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
17553022affSStefano Zampini 
17653022affSStefano Zampini   PetscFunctionBegin;
177*5f80ce2aSJacob Faibussowitsch   if (t) CHKERRQ(MatMultTranspose(pch2opus->M,x,y));
178*5f80ce2aSJacob Faibussowitsch   else  CHKERRQ(MatMult(pch2opus->M,x,y));
17953022affSStefano Zampini   PetscFunctionReturn(0);
18053022affSStefano Zampini }
18153022affSStefano Zampini 
18253022affSStefano Zampini static PetscErrorCode PCApplyMatKernel_H2OPUS(PC pc, Mat X, Mat Y, PetscBool t)
18353022affSStefano Zampini {
18453022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
18553022affSStefano Zampini 
18653022affSStefano Zampini   PetscFunctionBegin;
187*5f80ce2aSJacob Faibussowitsch   if (t) CHKERRQ(MatTransposeMatMult(pch2opus->M,X,MAT_REUSE_MATRIX,PETSC_DEFAULT,&Y));
188*5f80ce2aSJacob Faibussowitsch   else   CHKERRQ(MatMatMult(pch2opus->M,X,MAT_REUSE_MATRIX,PETSC_DEFAULT,&Y));
18953022affSStefano Zampini   PetscFunctionReturn(0);
19053022affSStefano Zampini }
19153022affSStefano Zampini 
19253022affSStefano Zampini static PetscErrorCode PCApplyMat_H2OPUS(PC pc, Mat X, Mat Y)
19353022affSStefano Zampini {
19453022affSStefano Zampini   PetscFunctionBegin;
195*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCApplyMatKernel_H2OPUS(pc,X,Y,PETSC_FALSE));
19653022affSStefano Zampini   PetscFunctionReturn(0);
19753022affSStefano Zampini }
19853022affSStefano Zampini 
19953022affSStefano Zampini static PetscErrorCode PCApplyTransposeMat_H2OPUS(PC pc, Mat X, Mat Y)
20053022affSStefano Zampini {
20153022affSStefano Zampini   PetscFunctionBegin;
202*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCApplyMatKernel_H2OPUS(pc,X,Y,PETSC_TRUE));
20353022affSStefano Zampini   PetscFunctionReturn(0);
20453022affSStefano Zampini }
20553022affSStefano Zampini 
20653022affSStefano Zampini static PetscErrorCode PCApply_H2OPUS(PC pc, Vec x, Vec y)
20753022affSStefano Zampini {
20853022affSStefano Zampini   PetscFunctionBegin;
209*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCApplyKernel_H2OPUS(pc,x,y,PETSC_FALSE));
21053022affSStefano Zampini   PetscFunctionReturn(0);
21153022affSStefano Zampini }
21253022affSStefano Zampini 
21353022affSStefano Zampini static PetscErrorCode PCApplyTranspose_H2OPUS(PC pc, Vec x, Vec y)
21453022affSStefano Zampini {
21553022affSStefano Zampini   PetscFunctionBegin;
216*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCApplyKernel_H2OPUS(pc,x,y,PETSC_TRUE));
21753022affSStefano Zampini   PetscFunctionReturn(0);
21853022affSStefano Zampini }
21953022affSStefano Zampini 
22053022affSStefano Zampini /* used to test the norm of (M^-1 A - I) */
22153022affSStefano Zampini static PetscErrorCode MatMultKernel_MAmI(Mat M, Vec x, Vec y, PetscBool t)
22253022affSStefano Zampini {
22353022affSStefano Zampini   PC         pc;
22453022affSStefano Zampini   Mat        A;
22553022affSStefano Zampini   PC_H2OPUS *pch2opus;
22653022affSStefano Zampini   PetscBool  sideleft = PETSC_TRUE;
22753022affSStefano Zampini 
22853022affSStefano Zampini   PetscFunctionBegin;
229*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(M,(void*)&pc));
23053022affSStefano Zampini   pch2opus = (PC_H2OPUS*)pc->data;
231*5f80ce2aSJacob Faibussowitsch   if (!pch2opus->w) CHKERRQ(MatCreateVecs(pch2opus->M,&pch2opus->w,NULL));
23253022affSStefano Zampini   A = pch2opus->A;
233*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->w,pch2opus->boundtocpu));
23453022affSStefano Zampini   if (t) {
23553022affSStefano Zampini     if (sideleft) {
236*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApplyTranspose_H2OPUS(pc,x,pch2opus->w));
237*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(A,pch2opus->w,y));
23853022affSStefano Zampini     } else {
239*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(A,x,pch2opus->w));
240*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApplyTranspose_H2OPUS(pc,pch2opus->w,y));
24153022affSStefano Zampini     }
24253022affSStefano Zampini   } else {
24353022affSStefano Zampini     if (sideleft) {
244*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMult(A,x,pch2opus->w));
245*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApply_H2OPUS(pc,pch2opus->w,y));
24653022affSStefano Zampini     } else {
247*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApply_H2OPUS(pc,x,pch2opus->w));
248*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMult(A,pch2opus->w,y));
24953022affSStefano Zampini     }
25053022affSStefano Zampini   }
251*5f80ce2aSJacob Faibussowitsch   if (!pch2opus->testMA) CHKERRQ(VecAXPY(y,-1.0,x));
25253022affSStefano Zampini   PetscFunctionReturn(0);
25353022affSStefano Zampini }
25453022affSStefano Zampini 
25553022affSStefano Zampini static PetscErrorCode MatMult_MAmI(Mat A, Vec x, Vec y)
25653022affSStefano Zampini {
25753022affSStefano Zampini   PetscFunctionBegin;
258*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_MAmI(A,x,y,PETSC_FALSE));
25953022affSStefano Zampini   PetscFunctionReturn(0);
26053022affSStefano Zampini }
26153022affSStefano Zampini 
26253022affSStefano Zampini static PetscErrorCode MatMultTranspose_MAmI(Mat A, Vec x, Vec y)
26353022affSStefano Zampini {
26453022affSStefano Zampini   PetscFunctionBegin;
265*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_MAmI(A,x,y,PETSC_TRUE));
26653022affSStefano Zampini   PetscFunctionReturn(0);
26753022affSStefano Zampini }
26853022affSStefano Zampini 
26953022affSStefano Zampini /* HyperPower kernel:
27053022affSStefano Zampini Y = R = x
27153022affSStefano Zampini for i = 1 . . . l - 1 do
27253022affSStefano Zampini   R = (I - A * Xk) * R
27353022affSStefano Zampini   Y = Y + R
27453022affSStefano Zampini Y = Xk * Y
27553022affSStefano Zampini */
27653022affSStefano Zampini static PetscErrorCode MatMultKernel_Hyper(Mat M, Vec x, Vec y, PetscBool t)
27753022affSStefano Zampini {
27853022affSStefano Zampini   PC         pc;
27953022affSStefano Zampini   Mat        A;
28053022affSStefano Zampini   PC_H2OPUS *pch2opus;
28153022affSStefano Zampini 
28253022affSStefano Zampini   PetscFunctionBegin;
283*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(M,(void*)&pc));
28453022affSStefano Zampini   pch2opus = (PC_H2OPUS*)pc->data;
28553022affSStefano Zampini   A = pch2opus->A;
286*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(pch2opus->M,pch2opus->wns[0] ? NULL : &pch2opus->wns[0],pch2opus->wns[1] ? NULL : &pch2opus->wns[1]));
287*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(pch2opus->M,pch2opus->wns[2] ? NULL : &pch2opus->wns[2],pch2opus->wns[3] ? NULL : &pch2opus->wns[3]));
288*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[0],pch2opus->boundtocpu));
289*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[1],pch2opus->boundtocpu));
290*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[2],pch2opus->boundtocpu));
291*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[3],pch2opus->boundtocpu));
292*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCopy(x,pch2opus->wns[0]));
293*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCopy(x,pch2opus->wns[3]));
29453022affSStefano Zampini   if (t) {
295*5f80ce2aSJacob Faibussowitsch     for (PetscInt i=0;i<pch2opus->hyperorder-1;i++) {
296*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(A,pch2opus->wns[0],pch2opus->wns[1]));
297*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApplyTranspose_H2OPUS(pc,pch2opus->wns[1],pch2opus->wns[2]));
298*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(pch2opus->wns[0],-1.,pch2opus->wns[2]));
299*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(pch2opus->wns[3], 1.,pch2opus->wns[0]));
30053022affSStefano Zampini     }
301*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTranspose_H2OPUS(pc,pch2opus->wns[3],y));
30253022affSStefano Zampini   } else {
303*5f80ce2aSJacob Faibussowitsch     for (PetscInt i=0;i<pch2opus->hyperorder-1;i++) {
304*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApply_H2OPUS(pc,pch2opus->wns[0],pch2opus->wns[1]));
305*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMult(A,pch2opus->wns[1],pch2opus->wns[2]));
306*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(pch2opus->wns[0],-1.,pch2opus->wns[2]));
307*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(pch2opus->wns[3], 1.,pch2opus->wns[0]));
30853022affSStefano Zampini     }
309*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApply_H2OPUS(pc,pch2opus->wns[3],y));
31053022affSStefano Zampini   }
31153022affSStefano Zampini   PetscFunctionReturn(0);
31253022affSStefano Zampini }
31353022affSStefano Zampini 
31453022affSStefano Zampini static PetscErrorCode MatMult_Hyper(Mat M, Vec x, Vec y)
31553022affSStefano Zampini {
31653022affSStefano Zampini   PetscFunctionBegin;
317*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_Hyper(M,x,y,PETSC_FALSE));
31853022affSStefano Zampini   PetscFunctionReturn(0);
31953022affSStefano Zampini }
32053022affSStefano Zampini 
32153022affSStefano Zampini static PetscErrorCode MatMultTranspose_Hyper(Mat M, Vec x, Vec y)
32253022affSStefano Zampini {
32353022affSStefano Zampini   PetscFunctionBegin;
324*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_Hyper(M,x,y,PETSC_TRUE));
32553022affSStefano Zampini   PetscFunctionReturn(0);
32653022affSStefano Zampini }
32753022affSStefano Zampini 
32853022affSStefano Zampini /* Hyper power kernel, MatMat version */
32953022affSStefano Zampini static PetscErrorCode MatMatMultKernel_Hyper(Mat M, Mat X, Mat Y, PetscBool t)
33053022affSStefano Zampini {
33153022affSStefano Zampini   PC         pc;
33253022affSStefano Zampini   Mat        A;
33353022affSStefano Zampini   PC_H2OPUS *pch2opus;
33453022affSStefano Zampini   PetscInt   i;
33553022affSStefano Zampini 
33653022affSStefano Zampini   PetscFunctionBegin;
337*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(M,(void*)&pc));
33853022affSStefano Zampini   pch2opus = (PC_H2OPUS*)pc->data;
33953022affSStefano Zampini   A = pch2opus->A;
34053022affSStefano Zampini   if (pch2opus->wnsmat[0] && pch2opus->wnsmat[0]->cmap->N != X->cmap->N) {
341*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[0]));
342*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[1]));
34353022affSStefano Zampini   }
34453022affSStefano Zampini   if (!pch2opus->wnsmat[0]) {
345*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(X,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[0]));
346*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(Y,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[1]));
34753022affSStefano Zampini   }
34853022affSStefano Zampini   if (pch2opus->wnsmat[2] && pch2opus->wnsmat[2]->cmap->N != X->cmap->N) {
349*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[2]));
350*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[3]));
35153022affSStefano Zampini   }
35253022affSStefano Zampini   if (!pch2opus->wnsmat[2]) {
353*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(X,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[2]));
354*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(Y,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[3]));
35553022affSStefano Zampini   }
356*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCopy(X,pch2opus->wnsmat[0],SAME_NONZERO_PATTERN));
357*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCopy(X,pch2opus->wnsmat[3],SAME_NONZERO_PATTERN));
35853022affSStefano Zampini   if (t) {
35953022affSStefano Zampini     for (i=0;i<pch2opus->hyperorder-1;i++) {
360*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatTransposeMatMult(A,pch2opus->wnsmat[0],MAT_REUSE_MATRIX,PETSC_DEFAULT,&pch2opus->wnsmat[1]));
361*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApplyTransposeMat_H2OPUS(pc,pch2opus->wnsmat[1],pch2opus->wnsmat[2]));
362*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(pch2opus->wnsmat[0],-1.,pch2opus->wnsmat[2],SAME_NONZERO_PATTERN));
363*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(pch2opus->wnsmat[3],1.,pch2opus->wnsmat[0],SAME_NONZERO_PATTERN));
36453022affSStefano Zampini     }
365*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTransposeMat_H2OPUS(pc,pch2opus->wnsmat[3],Y));
36653022affSStefano Zampini   } else {
36753022affSStefano Zampini     for (i=0;i<pch2opus->hyperorder-1;i++) {
368*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCApplyMat_H2OPUS(pc,pch2opus->wnsmat[0],pch2opus->wnsmat[1]));
369*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMatMult(A,pch2opus->wnsmat[1],MAT_REUSE_MATRIX,PETSC_DEFAULT,&pch2opus->wnsmat[2]));
370*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(pch2opus->wnsmat[0],-1.,pch2opus->wnsmat[2],SAME_NONZERO_PATTERN));
371*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(pch2opus->wnsmat[3],1.,pch2opus->wnsmat[0],SAME_NONZERO_PATTERN));
37253022affSStefano Zampini     }
373*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyMat_H2OPUS(pc,pch2opus->wnsmat[3],Y));
37453022affSStefano Zampini   }
37553022affSStefano Zampini   PetscFunctionReturn(0);
37653022affSStefano Zampini }
37753022affSStefano Zampini 
37853022affSStefano Zampini static PetscErrorCode MatMatMultNumeric_Hyper(Mat M, Mat X, Mat Y,void *ctx)
37953022affSStefano Zampini {
38053022affSStefano Zampini   PetscFunctionBegin;
381*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMatMultKernel_Hyper(M,X,Y,PETSC_FALSE));
38253022affSStefano Zampini   PetscFunctionReturn(0);
38353022affSStefano Zampini }
38453022affSStefano Zampini 
38553022affSStefano Zampini /* Basic Newton-Schultz sampler: (2 * I - M * A)*M */
38653022affSStefano Zampini static PetscErrorCode MatMultKernel_NS(Mat M, Vec x, Vec y, PetscBool t)
38753022affSStefano Zampini {
38853022affSStefano Zampini   PC         pc;
38953022affSStefano Zampini   Mat        A;
39053022affSStefano Zampini   PC_H2OPUS *pch2opus;
39153022affSStefano Zampini 
39253022affSStefano Zampini   PetscFunctionBegin;
393*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(M,(void*)&pc));
39453022affSStefano Zampini   pch2opus = (PC_H2OPUS*)pc->data;
39553022affSStefano Zampini   A = pch2opus->A;
396*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(pch2opus->M,pch2opus->wns[0] ? NULL : &pch2opus->wns[0],pch2opus->wns[1] ? NULL : &pch2opus->wns[1]));
397*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[0],pch2opus->boundtocpu));
398*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecBindToCPU(pch2opus->wns[1],pch2opus->boundtocpu));
39953022affSStefano Zampini   if (t) {
400*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTranspose_H2OPUS(pc,x,y));
401*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMultTranspose(A,y,pch2opus->wns[1]));
402*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTranspose_H2OPUS(pc,pch2opus->wns[1],pch2opus->wns[0]));
403*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPBY(y,-1.,2.,pch2opus->wns[0]));
40453022affSStefano Zampini   } else {
405*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApply_H2OPUS(pc,x,y));
406*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMult(A,y,pch2opus->wns[0]));
407*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApply_H2OPUS(pc,pch2opus->wns[0],pch2opus->wns[1]));
408*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPBY(y,-1.,2.,pch2opus->wns[1]));
40953022affSStefano Zampini   }
41053022affSStefano Zampini   PetscFunctionReturn(0);
41153022affSStefano Zampini }
41253022affSStefano Zampini 
41353022affSStefano Zampini static PetscErrorCode MatMult_NS(Mat M, Vec x, Vec y)
41453022affSStefano Zampini {
41553022affSStefano Zampini   PetscFunctionBegin;
416*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_NS(M,x,y,PETSC_FALSE));
41753022affSStefano Zampini   PetscFunctionReturn(0);
41853022affSStefano Zampini }
41953022affSStefano Zampini 
42053022affSStefano Zampini static PetscErrorCode MatMultTranspose_NS(Mat M, Vec x, Vec y)
42153022affSStefano Zampini {
42253022affSStefano Zampini   PetscFunctionBegin;
423*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMultKernel_NS(M,x,y,PETSC_TRUE));
42453022affSStefano Zampini   PetscFunctionReturn(0);
42553022affSStefano Zampini }
42653022affSStefano Zampini 
42753022affSStefano Zampini /* Basic Newton-Schultz sampler: (2 * I - M * A)*M, MatMat version */
42853022affSStefano Zampini static PetscErrorCode MatMatMultKernel_NS(Mat M, Mat X, Mat Y, PetscBool t)
42953022affSStefano Zampini {
43053022affSStefano Zampini   PC         pc;
43153022affSStefano Zampini   Mat        A;
43253022affSStefano Zampini   PC_H2OPUS *pch2opus;
43353022affSStefano Zampini 
43453022affSStefano Zampini   PetscFunctionBegin;
435*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(M,(void*)&pc));
43653022affSStefano Zampini   pch2opus = (PC_H2OPUS*)pc->data;
43753022affSStefano Zampini   A = pch2opus->A;
43853022affSStefano Zampini   if (pch2opus->wnsmat[0] && pch2opus->wnsmat[0]->cmap->N != X->cmap->N) {
439*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[0]));
440*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&pch2opus->wnsmat[1]));
44153022affSStefano Zampini   }
44253022affSStefano Zampini   if (!pch2opus->wnsmat[0]) {
443*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(X,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[0]));
444*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(Y,MAT_SHARE_NONZERO_PATTERN,&pch2opus->wnsmat[1]));
44553022affSStefano Zampini   }
44653022affSStefano Zampini   if (t) {
447*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTransposeMat_H2OPUS(pc,X,Y));
448*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatTransposeMatMult(A,Y,MAT_REUSE_MATRIX,PETSC_DEFAULT,&pch2opus->wnsmat[1]));
449*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyTransposeMat_H2OPUS(pc,pch2opus->wnsmat[1],pch2opus->wnsmat[0]));
450*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatScale(Y,2.));
451*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAXPY(Y,-1.,pch2opus->wnsmat[0],SAME_NONZERO_PATTERN));
45253022affSStefano Zampini   } else {
453*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyMat_H2OPUS(pc,X,Y));
454*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMatMult(A,Y,MAT_REUSE_MATRIX,PETSC_DEFAULT,&pch2opus->wnsmat[0]));
455*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCApplyMat_H2OPUS(pc,pch2opus->wnsmat[0],pch2opus->wnsmat[1]));
456*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatScale(Y,2.));
457*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAXPY(Y,-1.,pch2opus->wnsmat[1],SAME_NONZERO_PATTERN));
45853022affSStefano Zampini   }
45953022affSStefano Zampini   PetscFunctionReturn(0);
46053022affSStefano Zampini }
46153022affSStefano Zampini 
46253022affSStefano Zampini static PetscErrorCode MatMatMultNumeric_NS(Mat M, Mat X, Mat Y, void *ctx)
46353022affSStefano Zampini {
46453022affSStefano Zampini   PetscFunctionBegin;
465*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMatMultKernel_NS(M,X,Y,PETSC_FALSE));
46653022affSStefano Zampini   PetscFunctionReturn(0);
46753022affSStefano Zampini }
46853022affSStefano Zampini 
46953022affSStefano Zampini static PetscErrorCode PCH2OpusSetUpSampler_Private(PC pc)
47053022affSStefano Zampini {
47153022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
47253022affSStefano Zampini   Mat        A        = pc->useAmat ? pc->mat : pc->pmat;
47353022affSStefano Zampini 
47453022affSStefano Zampini   PetscFunctionBegin;
47553022affSStefano Zampini   if (!pch2opus->S) {
47653022affSStefano Zampini     PetscInt M,N,m,n;
47753022affSStefano Zampini 
478*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetSize(A,&M,&N));
479*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetLocalSize(A,&m,&n));
480*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateShell(PetscObjectComm((PetscObject)A),m,n,M,N,pc,&pch2opus->S));
481*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetBlockSizesFromMats(pch2opus->S,A,A));
48253022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
483*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetVecType(pch2opus->S,VECCUDA));
48453022affSStefano Zampini #endif
48553022affSStefano Zampini   }
48653022affSStefano Zampini   if (pch2opus->hyperorder >= 2) {
487*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->S,MATOP_MULT,(void (*)(void))MatMult_Hyper));
488*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->S,MATOP_MULT_TRANSPOSE,(void (*)(void))MatMultTranspose_Hyper));
489*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetMatProductOperation(pch2opus->S,MATPRODUCT_AB,NULL,MatMatMultNumeric_Hyper,NULL,MATDENSE,MATDENSE));
490*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetMatProductOperation(pch2opus->S,MATPRODUCT_AB,NULL,MatMatMultNumeric_Hyper,NULL,MATDENSECUDA,MATDENSECUDA));
49153022affSStefano Zampini   } else {
492*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->S,MATOP_MULT,(void (*)(void))MatMult_NS));
493*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->S,MATOP_MULT_TRANSPOSE,(void (*)(void))MatMultTranspose_NS));
494*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetMatProductOperation(pch2opus->S,MATPRODUCT_AB,NULL,MatMatMultNumeric_NS,NULL,MATDENSE,MATDENSE));
495*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetMatProductOperation(pch2opus->S,MATPRODUCT_AB,NULL,MatMatMultNumeric_NS,NULL,MATDENSECUDA,MATDENSECUDA));
49653022affSStefano Zampini   }
497*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatPropagateSymmetryOptions(A,pch2opus->S));
498*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatBindToCPU(pch2opus->S,pch2opus->boundtocpu));
49953022affSStefano Zampini   /* XXX */
500*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetOption(pch2opus->S,MAT_SYMMETRIC,PETSC_TRUE));
50153022affSStefano Zampini   PetscFunctionReturn(0);
50253022affSStefano Zampini }
50353022affSStefano Zampini 
50453022affSStefano Zampini static PetscErrorCode PCSetUp_H2OPUS(PC pc)
50553022affSStefano Zampini {
50653022affSStefano Zampini   PC_H2OPUS *pch2opus  = (PC_H2OPUS*)pc->data;
50753022affSStefano Zampini   Mat        A         = pc->useAmat ? pc->mat : pc->pmat;
50853022affSStefano Zampini   NormType   norm      = pch2opus->normtype;
50953022affSStefano Zampini   PetscReal  initerr   = 0.0,err;
51053022affSStefano Zampini   PetscReal  initerrMA = 0.0,errMA;
51153022affSStefano Zampini   PetscBool  ish2opus;
51253022affSStefano Zampini 
51353022affSStefano Zampini   PetscFunctionBegin;
51453022affSStefano Zampini   if (!pch2opus->T) {
51553022affSStefano Zampini     PetscInt    M,N,m,n;
51653022affSStefano Zampini     const char *prefix;
51753022affSStefano Zampini 
518*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCGetOptionsPrefix(pc,&prefix));
519*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetSize(A,&M,&N));
520*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetLocalSize(A,&m,&n));
521*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateShell(PetscObjectComm((PetscObject)pc->pmat),m,n,M,N,pc,&pch2opus->T));
522*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetBlockSizesFromMats(pch2opus->T,A,A));
523*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->T,MATOP_MULT,(void (*)(void))MatMult_MAmI));
524*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->T,MATOP_MULT_TRANSPOSE,(void (*)(void))MatMultTranspose_MAmI));
525*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetOperation(pch2opus->T,MATOP_NORM,(void (*)(void))MatNorm_H2OPUS));
52653022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
527*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatShellSetVecType(pch2opus->T,VECCUDA));
52853022affSStefano Zampini #endif
529*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLogObjectParent((PetscObject)pc,(PetscObject)pch2opus->T));
530*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetOptionsPrefix(pch2opus->T,prefix));
531*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAppendOptionsPrefix(pch2opus->T,"pc_h2opus_est_"));
53253022affSStefano Zampini   }
533*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->A));
534*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)A,MATH2OPUS,&ish2opus));
53553022affSStefano Zampini   if (ish2opus) {
536*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)A));
53753022affSStefano Zampini     pch2opus->A = A;
53853022affSStefano Zampini   } else {
53953022affSStefano Zampini     const char *prefix;
540*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateH2OpusFromMat(A,pch2opus->sdim,pch2opus->coords,PETSC_FALSE,pch2opus->eta,pch2opus->leafsize,pch2opus->max_rank,pch2opus->bs,pch2opus->mrtol,&pch2opus->A));
54153022affSStefano Zampini     /* XXX */
542*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetOption(pch2opus->A,MAT_SYMMETRIC,PETSC_TRUE));
543*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCGetOptionsPrefix(pc,&prefix));
544*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetOptionsPrefix(pch2opus->A,prefix));
545*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAppendOptionsPrefix(pch2opus->A,"pc_h2opus_init_"));
546*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetFromOptions(pch2opus->A));
547*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyBegin(pch2opus->A,MAT_FINAL_ASSEMBLY));
548*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyEnd(pch2opus->A,MAT_FINAL_ASSEMBLY));
54953022affSStefano Zampini     /* XXX */
550*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetOption(pch2opus->A,MAT_SYMMETRIC,PETSC_TRUE));
55153022affSStefano Zampini   }
55253022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
55353022affSStefano Zampini   pch2opus->boundtocpu = pch2opus->A->boundtocpu;
55453022affSStefano Zampini #endif
555*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatBindToCPU(pch2opus->T,pch2opus->boundtocpu));
55653022affSStefano Zampini   if (pch2opus->M) { /* see if we can reuse M as initial guess */
55753022affSStefano Zampini     PetscReal reuse;
55853022affSStefano Zampini 
559*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatBindToCPU(pch2opus->M,pch2opus->boundtocpu));
560*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatNorm(pch2opus->T,norm,&reuse));
561*5f80ce2aSJacob Faibussowitsch     if (reuse >= 1.0) CHKERRQ(MatDestroy(&pch2opus->M));
56253022affSStefano Zampini   }
56353022affSStefano Zampini   if (!pch2opus->M) {
56453022affSStefano Zampini     const char *prefix;
565*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(pch2opus->A,MAT_COPY_VALUES,&pch2opus->M));
566*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCGetOptionsPrefix(pc,&prefix));
567*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetOptionsPrefix(pch2opus->M,prefix));
568*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAppendOptionsPrefix(pch2opus->M,"pc_h2opus_inv_"));
569*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetFromOptions(pch2opus->M));
570*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCH2OpusSetUpInit(pc));
571*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatScale(pch2opus->M,pch2opus->s0));
57253022affSStefano Zampini   }
57353022affSStefano Zampini   /* A and M have the same h2 matrix structure, save on reordering routines */
574*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatH2OpusSetNativeMult(pch2opus->A,PETSC_TRUE));
575*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatH2OpusSetNativeMult(pch2opus->M,PETSC_TRUE));
57653022affSStefano Zampini   if (norm == NORM_1 || norm == NORM_2 || norm == NORM_INFINITY) {
577*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatNorm(pch2opus->T,norm,&initerr));
57853022affSStefano Zampini     pch2opus->testMA = PETSC_TRUE;
579*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatNorm(pch2opus->T,norm,&initerrMA));
58053022affSStefano Zampini     pch2opus->testMA = PETSC_FALSE;
58153022affSStefano Zampini   }
58253022affSStefano Zampini   if (PetscIsInfOrNanReal(initerr)) pc->failedreason = PC_SETUP_ERROR;
58353022affSStefano Zampini   err   = initerr;
58453022affSStefano Zampini   errMA = initerrMA;
58553022affSStefano Zampini   if (pch2opus->monitor) {
586*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPrintf(PetscObjectComm((PetscObject)pc),"%D: ||M*A - I|| NORM%s abs %g rel %g\n",0,NormTypes[norm],(double)err,(double)(err/initerr)));
587*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPrintf(PetscObjectComm((PetscObject)pc),"%D: ||M*A||     NORM%s abs %g rel %g\n",0,NormTypes[norm],(double)errMA,(double)(errMA/initerrMA)));
58853022affSStefano Zampini   }
58953022affSStefano Zampini   if (initerr > pch2opus->atol && !pc->failedreason) {
59053022affSStefano Zampini     PetscInt i;
59153022affSStefano Zampini 
592*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCH2OpusSetUpSampler_Private(pc));
59353022affSStefano Zampini     for (i = 0; i < pch2opus->maxits; i++) {
59453022affSStefano Zampini       Mat         M;
59553022affSStefano Zampini       const char* prefix;
59653022affSStefano Zampini 
597*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDuplicate(pch2opus->M,MAT_SHARE_NONZERO_PATTERN,&M));
598*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatGetOptionsPrefix(pch2opus->M,&prefix));
599*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetOptionsPrefix(M,prefix));
600*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatH2OpusSetSamplingMat(M,pch2opus->S,PETSC_DECIDE,PETSC_DECIDE));
601*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetFromOptions(M));
602*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatH2OpusSetNativeMult(M,PETSC_TRUE));
603*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAssemblyBegin(M,MAT_FINAL_ASSEMBLY));
604*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAssemblyEnd(M,MAT_FINAL_ASSEMBLY));
60553022affSStefano Zampini 
606*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDestroy(&pch2opus->M));
60753022affSStefano Zampini       pch2opus->M = M;
60853022affSStefano Zampini       if (norm == NORM_1 || norm == NORM_2 || norm == NORM_INFINITY) {
609*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatNorm(pch2opus->T,norm,&err));
61053022affSStefano Zampini         pch2opus->testMA = PETSC_TRUE;
611*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatNorm(pch2opus->T,norm,&errMA));
61253022affSStefano Zampini         pch2opus->testMA = PETSC_FALSE;
61353022affSStefano Zampini       }
61453022affSStefano Zampini       if (pch2opus->monitor) {
615*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscPrintf(PetscObjectComm((PetscObject)pc),"%D: ||M*A - I|| NORM%s abs %g rel %g\n",i+1,NormTypes[norm],(double)err,(double)(err/initerr)));
616*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscPrintf(PetscObjectComm((PetscObject)pc),"%D: ||M*A||     NORM%s abs %g rel %g\n",i+1,NormTypes[norm],(double)errMA,(double)(errMA/initerrMA)));
61753022affSStefano Zampini       }
61853022affSStefano Zampini       if (PetscIsInfOrNanReal(err)) pc->failedreason = PC_SETUP_ERROR;
61953022affSStefano Zampini       if (err < pch2opus->atol || err < pch2opus->rtol*initerr || pc->failedreason) break;
62053022affSStefano Zampini     }
62153022affSStefano Zampini   }
62253022affSStefano Zampini   /* cleanup setup workspace */
623*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatH2OpusSetNativeMult(pch2opus->A,PETSC_FALSE));
624*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatH2OpusSetNativeMult(pch2opus->M,PETSC_FALSE));
625*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[0]));
626*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[1]));
627*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[2]));
628*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pch2opus->wns[3]));
629*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[0]));
630*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[1]));
631*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[2]));
632*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&pch2opus->wnsmat[3]));
63353022affSStefano Zampini   PetscFunctionReturn(0);
63453022affSStefano Zampini }
63553022affSStefano Zampini 
63653022affSStefano Zampini static PetscErrorCode PCView_H2OPUS(PC pc, PetscViewer viewer)
63753022affSStefano Zampini {
63853022affSStefano Zampini   PC_H2OPUS *pch2opus = (PC_H2OPUS*)pc->data;
63953022affSStefano Zampini   PetscBool  isascii;
64053022affSStefano Zampini 
64153022affSStefano Zampini   PetscFunctionBegin;
642*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
64353022affSStefano Zampini   if (isascii) {
64453022affSStefano Zampini     if (pch2opus->A && pch2opus->A != pc->mat && pch2opus->A != pc->pmat) {
645*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPrintf(viewer,"Initial approximation matrix\n"));
646*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPushTab(viewer));
647*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO_DETAIL));
648*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatView(pch2opus->A,viewer));
649*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerPopFormat(viewer));
650*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPopTab(viewer));
65153022affSStefano Zampini     }
65253022affSStefano Zampini     if (pch2opus->M) {
653*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPrintf(viewer,"Inner matrix constructed\n"));
654*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPushTab(viewer));
655*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO_DETAIL));
656*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatView(pch2opus->M,viewer));
657*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerPopFormat(viewer));
658*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPopTab(viewer));
65953022affSStefano Zampini     }
660*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer,"Initial scaling: %g\n",pch2opus->s0));
66153022affSStefano Zampini   }
66253022affSStefano Zampini   PetscFunctionReturn(0);
66353022affSStefano Zampini }
66453022affSStefano Zampini 
66553022affSStefano Zampini PETSC_EXTERN PetscErrorCode PCCreate_H2OPUS(PC pc)
66653022affSStefano Zampini {
66753022affSStefano Zampini   PC_H2OPUS *pch2opus;
66853022affSStefano Zampini 
66953022affSStefano Zampini   PetscFunctionBegin;
670*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNewLog(pc,&pch2opus));
67153022affSStefano Zampini   pc->data = (void*)pch2opus;
67253022affSStefano Zampini 
67353022affSStefano Zampini   pch2opus->atol       = 1.e-2;
67453022affSStefano Zampini   pch2opus->rtol       = 1.e-6;
67553022affSStefano Zampini   pch2opus->maxits     = 50;
67653022affSStefano Zampini   pch2opus->hyperorder = 1; /* defaults to basic NewtonSchultz */
67753022affSStefano Zampini   pch2opus->normtype   = NORM_2;
67853022affSStefano Zampini 
67953022affSStefano Zampini   /* these are needed when we are sampling the pmat */
68053022affSStefano Zampini   pch2opus->eta        = PETSC_DECIDE;
68153022affSStefano Zampini   pch2opus->leafsize   = PETSC_DECIDE;
68253022affSStefano Zampini   pch2opus->max_rank   = PETSC_DECIDE;
68353022affSStefano Zampini   pch2opus->bs         = PETSC_DECIDE;
68453022affSStefano Zampini   pch2opus->mrtol      = PETSC_DECIDE;
68553022affSStefano Zampini #if defined(PETSC_H2OPUS_USE_GPU)
68653022affSStefano Zampini   pch2opus->boundtocpu = PETSC_FALSE;
68753022affSStefano Zampini #else
68853022affSStefano Zampini   pch2opus->boundtocpu = PETSC_TRUE;
68953022affSStefano Zampini #endif
69053022affSStefano Zampini   pc->ops->destroy        = PCDestroy_H2OPUS;
69153022affSStefano Zampini   pc->ops->setup          = PCSetUp_H2OPUS;
69253022affSStefano Zampini   pc->ops->apply          = PCApply_H2OPUS;
69353022affSStefano Zampini   pc->ops->matapply       = PCApplyMat_H2OPUS;
69453022affSStefano Zampini   pc->ops->applytranspose = PCApplyTranspose_H2OPUS;
69553022affSStefano Zampini   pc->ops->reset          = PCReset_H2OPUS;
69653022affSStefano Zampini   pc->ops->setfromoptions = PCSetFromOptions_H2OPUS;
69753022affSStefano Zampini   pc->ops->view           = PCView_H2OPUS;
69853022affSStefano Zampini 
699*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",PCSetCoordinates_H2OPUS));
70053022affSStefano Zampini   PetscFunctionReturn(0);
70153022affSStefano Zampini }
702