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