xref: /petsc/src/ksp/pc/impls/bjacobi/bjacobi.c (revision 9f196a0264fbaf0568fead3a30c861c7ae4cf663)
14b9ad928SBarry Smith /*
24b9ad928SBarry Smith    Defines a block Jacobi preconditioner.
34b9ad928SBarry Smith */
400e125f8SBarry Smith 
500e125f8SBarry Smith #include <../src/ksp/pc/impls/bjacobi/bjacobi.h> /*I "petscpc.h" I*/
64b9ad928SBarry Smith 
76849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC, Mat, Mat);
86849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC, Mat, Mat);
95a7e1895SHong Zhang static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC);
104b9ad928SBarry Smith 
11d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi(PC pc)
12d71ae5a4SJacob Faibussowitsch {
134b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
144b9ad928SBarry Smith   Mat         mat = pc->mat, pmat = pc->pmat;
15976e8c5aSLisandro Dalcin   PetscBool   hasop;
1669a612a9SBarry Smith   PetscInt    N, M, start, i, sum, end;
1769a612a9SBarry Smith   PetscInt    bs, i_start = -1, i_end = -1;
1869a612a9SBarry Smith   PetscMPIInt rank, size;
194b9ad928SBarry Smith 
204b9ad928SBarry Smith   PetscFunctionBegin;
219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
239566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &M, &N));
249566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pc->pmat, &bs));
254b9ad928SBarry Smith 
265a7e1895SHong Zhang   if (jac->n > 0 && jac->n < size) {
279566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiproc(pc));
283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
295a7e1895SHong Zhang   }
305a7e1895SHong Zhang 
31f1580f4eSBarry Smith   /*    Determines the number of blocks assigned to each processor */
324b9ad928SBarry Smith   /*   local block count  given */
334b9ad928SBarry Smith   if (jac->n_local > 0 && jac->n < 0) {
34462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&jac->n_local, &jac->n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
354b9ad928SBarry Smith     if (jac->l_lens) { /* check that user set these correctly */
364b9ad928SBarry Smith       sum = 0;
374b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
3808401ef6SPierre Jolivet         PetscCheck(jac->l_lens[i] / bs * bs == jac->l_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat blocksize doesn't match block Jacobi layout");
394b9ad928SBarry Smith         sum += jac->l_lens[i];
404b9ad928SBarry Smith       }
4108401ef6SPierre Jolivet       PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local lens set incorrectly");
424b9ad928SBarry Smith     } else {
439566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
442fa5cd67SKarl Rupp       for (i = 0; i < jac->n_local; i++) jac->l_lens[i] = bs * ((M / bs) / jac->n_local + (((M / bs) % jac->n_local) > i));
454b9ad928SBarry Smith     }
464b9ad928SBarry Smith   } else if (jac->n > 0 && jac->n_local < 0) { /* global block count given */
474b9ad928SBarry Smith     /* global blocks given: determine which ones are local */
484b9ad928SBarry Smith     if (jac->g_lens) {
494b9ad928SBarry Smith       /* check if the g_lens is has valid entries */
504b9ad928SBarry Smith       for (i = 0; i < jac->n; i++) {
517827d75bSBarry Smith         PetscCheck(jac->g_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Zero block not allowed");
5208401ef6SPierre Jolivet         PetscCheck(jac->g_lens[i] / bs * bs == jac->g_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat blocksize doesn't match block Jacobi layout");
534b9ad928SBarry Smith       }
544b9ad928SBarry Smith       if (size == 1) {
554b9ad928SBarry Smith         jac->n_local = jac->n;
569566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
579566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens, jac->n_local));
584b9ad928SBarry Smith         /* check that user set these correctly */
594b9ad928SBarry Smith         sum = 0;
604b9ad928SBarry Smith         for (i = 0; i < jac->n_local; i++) sum += jac->l_lens[i];
6108401ef6SPierre Jolivet         PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Global lens set incorrectly");
624b9ad928SBarry Smith       } else {
639566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->pmat, &start, &end));
64aaa8cc7dSPierre Jolivet         /* loop over blocks determining first one owned by me */
654b9ad928SBarry Smith         sum = 0;
664b9ad928SBarry Smith         for (i = 0; i < jac->n + 1; i++) {
679371c9d4SSatish Balay           if (sum == start) {
689371c9d4SSatish Balay             i_start = i;
699371c9d4SSatish Balay             goto start_1;
709371c9d4SSatish Balay           }
714b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
724b9ad928SBarry Smith         }
73e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
744b9ad928SBarry Smith       start_1:
754b9ad928SBarry Smith         for (i = i_start; i < jac->n + 1; i++) {
769371c9d4SSatish Balay           if (sum == end) {
779371c9d4SSatish Balay             i_end = i;
789371c9d4SSatish Balay             goto end_1;
799371c9d4SSatish Balay           }
804b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
814b9ad928SBarry Smith         }
82e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
834b9ad928SBarry Smith       end_1:
844b9ad928SBarry Smith         jac->n_local = i_end - i_start;
859566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
869566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens + i_start, jac->n_local));
874b9ad928SBarry Smith       }
884b9ad928SBarry Smith     } else { /* no global blocks given, determine then using default layout */
894b9ad928SBarry Smith       jac->n_local = jac->n / size + ((jac->n % size) > rank);
909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
914b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
924b9ad928SBarry Smith         jac->l_lens[i] = ((M / bs) / jac->n_local + (((M / bs) % jac->n_local) > i)) * bs;
937827d75bSBarry Smith         PetscCheck(jac->l_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Too many blocks given");
944b9ad928SBarry Smith       }
954b9ad928SBarry Smith     }
964b9ad928SBarry Smith   } else if (jac->n < 0 && jac->n_local < 0) { /* no blocks given */
974b9ad928SBarry Smith     jac->n       = size;
984b9ad928SBarry Smith     jac->n_local = 1;
999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->l_lens));
1004b9ad928SBarry Smith     jac->l_lens[0] = M;
1017271b979SBarry Smith   } else { /* jac->n > 0 && jac->n_local > 0 */
1027271b979SBarry Smith     if (!jac->l_lens) {
1039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
1042fa5cd67SKarl Rupp       for (i = 0; i < jac->n_local; i++) jac->l_lens[i] = bs * ((M / bs) / jac->n_local + (((M / bs) % jac->n_local) > i));
1057271b979SBarry Smith     }
1064b9ad928SBarry Smith   }
10708401ef6SPierre Jolivet   PetscCheck(jac->n_local >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of blocks is less than number of processors");
1084b9ad928SBarry Smith 
109f1580f4eSBarry Smith   /*    Determines mat and pmat */
1109566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(pc->mat, MATOP_GET_DIAGONAL_BLOCK, &hasop));
111976e8c5aSLisandro Dalcin   if (!hasop && size == 1) {
1124b9ad928SBarry Smith     mat  = pc->mat;
1134b9ad928SBarry Smith     pmat = pc->pmat;
1144b9ad928SBarry Smith   } else {
11549517cdeSBarry Smith     if (pc->useAmat) {
11649517cdeSBarry Smith       /* use block from Amat matrix, not Pmat for local MatMult() */
1179566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->mat, &mat));
1184b9ad928SBarry Smith     }
11949517cdeSBarry Smith     if (pc->pmat != pc->mat || !pc->useAmat) {
1209566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->pmat, &pmat));
1212fa5cd67SKarl Rupp     } else pmat = mat;
1224b9ad928SBarry Smith   }
1234b9ad928SBarry Smith 
124f1580f4eSBarry Smith   /*
1254b9ad928SBarry Smith      Setup code depends on the number of blocks
1264b9ad928SBarry Smith   */
127cc1d6079SHong Zhang   if (jac->n_local == 1) {
1289566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Singleblock(pc, mat, pmat));
1294b9ad928SBarry Smith   } else {
1309566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiblock(pc, mat, pmat));
1314b9ad928SBarry Smith   }
1323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1334b9ad928SBarry Smith }
1344b9ad928SBarry Smith 
1354b9ad928SBarry Smith /* Default destroy, if it has never been setup */
136d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi(PC pc)
137d71ae5a4SJacob Faibussowitsch {
1384b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
1394b9ad928SBarry Smith 
1404b9ad928SBarry Smith   PetscFunctionBegin;
1419566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
1429566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
1432e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetSubKSP_C", NULL));
1442e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetTotalBlocks_C", NULL));
1452e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetTotalBlocks_C", NULL));
1462e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetLocalBlocks_C", NULL));
1472e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetLocalBlocks_C", NULL));
1489566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1504b9ad928SBarry Smith }
1514b9ad928SBarry Smith 
152ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_BJacobi(PC pc, PetscOptionItems PetscOptionsObject)
153d71ae5a4SJacob Faibussowitsch {
1544b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
155248bfaf0SJed Brown   PetscInt    blocks, i;
156ace3abfcSBarry Smith   PetscBool   flg;
1574b9ad928SBarry Smith 
1584b9ad928SBarry Smith   PetscFunctionBegin;
159d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Block Jacobi options");
1609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_blocks", "Total number of blocks", "PCBJacobiSetTotalBlocks", jac->n, &blocks, &flg));
1619566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetTotalBlocks(pc, blocks, NULL));
1629566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_local_blocks", "Local number of blocks", "PCBJacobiSetLocalBlocks", jac->n_local, &blocks, &flg));
1639566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetLocalBlocks(pc, blocks, NULL));
164248bfaf0SJed Brown   if (jac->ksp) {
165248bfaf0SJed Brown     /* The sub-KSP has already been set up (e.g., PCSetUp_BJacobi_Singleblock), but KSPSetFromOptions was not called
166248bfaf0SJed Brown      * unless we had already been called. */
16748a46eb9SPierre Jolivet     for (i = 0; i < jac->n_local; i++) PetscCall(KSPSetFromOptions(jac->ksp[i]));
168248bfaf0SJed Brown   }
169d0609cedSBarry Smith   PetscOptionsHeadEnd();
1703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1714b9ad928SBarry Smith }
1724b9ad928SBarry Smith 
1739804daf3SBarry Smith #include <petscdraw.h>
174d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_BJacobi(PC pc, PetscViewer viewer)
175d71ae5a4SJacob Faibussowitsch {
1764b9ad928SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
177cbe18068SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
17869a612a9SBarry Smith   PetscMPIInt           rank;
17969a612a9SBarry Smith   PetscInt              i;
180*9f196a02SMartin Diehl   PetscBool             isascii, isstring, isdraw;
1814b9ad928SBarry Smith   PetscViewer           sviewer;
182020d6619SPierre Jolivet   PetscViewerFormat     format;
183020d6619SPierre Jolivet   const char           *prefix;
1844b9ad928SBarry Smith 
1854b9ad928SBarry Smith   PetscFunctionBegin;
186*9f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
189*9f196a02SMartin Diehl   if (isascii) {
19048a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat local matrix, number of blocks = %" PetscInt_FMT "\n", jac->n));
19163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  number of blocks = %" PetscInt_FMT "\n", jac->n));
1929566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
1939566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
194020d6619SPierre Jolivet     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
1959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for first block is in the following KSP and PC objects on rank 0:\n"));
1969566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
1979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Use -%sksp_view ::ascii_info_detail to display information for all blocks\n", prefix ? prefix : ""));
198933995ecSHong Zhang       if (jac->ksp && !jac->psubcomm) {
1999566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
200dd400576SPatrick Sanan         if (rank == 0) {
201b4025f61SBarry Smith           PetscCall(PetscViewerASCIIPushTab(sviewer));
2029566063dSJacob Faibussowitsch           PetscCall(KSPView(jac->ksp[0], sviewer));
203b4025f61SBarry Smith           PetscCall(PetscViewerASCIIPopTab(sviewer));
2044b9ad928SBarry Smith         }
2059566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
206e4de9e1dSBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2079566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
208e4fa1014SBarry Smith       } else if (mpjac && jac->ksp && mpjac->psubcomm) {
2099566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
210e4fa1014SBarry Smith         if (!mpjac->psubcomm->color) {
211b4025f61SBarry Smith           PetscCall(PetscViewerASCIIPushTab(sviewer));
212f4f49eeaSPierre Jolivet           PetscCall(KSPView(*jac->ksp, sviewer));
213b4025f61SBarry Smith           PetscCall(PetscViewerASCIIPopTab(sviewer));
214cbe18068SHong Zhang         }
2159566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
2169530cbd7SBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2179566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
218e4de9e1dSBarry Smith       }
219e4de9e1dSBarry Smith     } else {
2204814766eSBarry Smith       PetscInt n_global;
221462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&jac->n_local, &n_global, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
2229566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for each block is in the following KSP and PC objects:\n"));
2249566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2259566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
226b4025f61SBarry Smith       PetscCall(PetscViewerASCIIPrintf(sviewer, "[%d] number of local blocks = %" PetscInt_FMT ", first local block number = %" PetscInt_FMT "\n", rank, jac->n_local, jac->first_local));
227dd2fa690SBarry Smith       for (i = 0; i < jac->n_local; i++) {
228b4025f61SBarry Smith         PetscCall(PetscViewerASCIIPrintf(sviewer, "[%d] local block number %" PetscInt_FMT "\n", rank, i));
2299566063dSJacob Faibussowitsch         PetscCall(KSPView(jac->ksp[i], sviewer));
230b4025f61SBarry Smith         PetscCall(PetscViewerASCIIPrintf(sviewer, "- - - - - - - - - - - - - - - - - -\n"));
2314b9ad928SBarry Smith       }
2329566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
2349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2354b9ad928SBarry Smith     }
2364b9ad928SBarry Smith   } else if (isstring) {
23763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer, " blks=%" PetscInt_FMT, jac->n));
2389566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2399566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], sviewer));
2409566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
241d9884438SBarry Smith   } else if (isdraw) {
242d9884438SBarry Smith     PetscDraw draw;
243d9884438SBarry Smith     char      str[25];
244d9884438SBarry Smith     PetscReal x, y, bottom, h;
245d9884438SBarry Smith 
2469566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2479566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
24863a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str, 25, "Number blocks %" PetscInt_FMT, jac->n));
2499566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
250d9884438SBarry Smith     bottom = y - h;
2519566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
252d9884438SBarry Smith     /* warning the communicator on viewer is different then on ksp in parallel */
2539566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], viewer));
2549566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2554b9ad928SBarry Smith   }
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2574b9ad928SBarry Smith }
2584b9ad928SBarry Smith 
259d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetSubKSP_BJacobi(PC pc, PetscInt *n_local, PetscInt *first_local, KSP **ksp)
260d71ae5a4SJacob Faibussowitsch {
261feb237baSPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2624b9ad928SBarry Smith 
2634b9ad928SBarry Smith   PetscFunctionBegin;
26428b400f6SJacob Faibussowitsch   PetscCheck(pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() first");
2654b9ad928SBarry Smith 
2664b9ad928SBarry Smith   if (n_local) *n_local = jac->n_local;
2674b9ad928SBarry Smith   if (first_local) *first_local = jac->first_local;
268020d6619SPierre Jolivet   if (ksp) *ksp = jac->ksp;
2693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2704b9ad928SBarry Smith }
2714b9ad928SBarry Smith 
272f9663b93SPierre Jolivet static PetscErrorCode PCBJacobiSetTotalBlocks_BJacobi(PC pc, PetscInt blocks, const PetscInt *lens)
273d71ae5a4SJacob Faibussowitsch {
2744b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2754b9ad928SBarry Smith 
2764b9ad928SBarry Smith   PetscFunctionBegin;
277371d2eb7SMartin Diehl   PetscCheck(!pc->setupcalled || jac->n == blocks, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Cannot alter number of blocks after PCSetUp()/KSPSetUp() has been called");
2784b9ad928SBarry Smith   jac->n = blocks;
2790a545947SLisandro Dalcin   if (!lens) jac->g_lens = NULL;
2802fa5cd67SKarl Rupp   else {
2819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks, &jac->g_lens));
2829566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->g_lens, lens, blocks));
2834b9ad928SBarry Smith   }
2843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2854b9ad928SBarry Smith }
2864b9ad928SBarry Smith 
287d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetTotalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
288d71ae5a4SJacob Faibussowitsch {
2894b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2904b9ad928SBarry Smith 
2914b9ad928SBarry Smith   PetscFunctionBegin;
2924b9ad928SBarry Smith   *blocks = jac->n;
2934b9ad928SBarry Smith   if (lens) *lens = jac->g_lens;
2943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2954b9ad928SBarry Smith }
2964b9ad928SBarry Smith 
297d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiSetLocalBlocks_BJacobi(PC pc, PetscInt blocks, const PetscInt lens[])
298d71ae5a4SJacob Faibussowitsch {
2994b9ad928SBarry Smith   PC_BJacobi *jac;
3004b9ad928SBarry Smith 
3014b9ad928SBarry Smith   PetscFunctionBegin;
3024b9ad928SBarry Smith   jac = (PC_BJacobi *)pc->data;
3034b9ad928SBarry Smith 
3044b9ad928SBarry Smith   jac->n_local = blocks;
3050a545947SLisandro Dalcin   if (!lens) jac->l_lens = NULL;
3062fa5cd67SKarl Rupp   else {
3079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks, &jac->l_lens));
3089566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->l_lens, lens, blocks));
3094b9ad928SBarry Smith   }
3103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3114b9ad928SBarry Smith }
3124b9ad928SBarry Smith 
313d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetLocalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
314d71ae5a4SJacob Faibussowitsch {
3154b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
3164b9ad928SBarry Smith 
3174b9ad928SBarry Smith   PetscFunctionBegin;
3184b9ad928SBarry Smith   *blocks = jac->n_local;
3194b9ad928SBarry Smith   if (lens) *lens = jac->l_lens;
3203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3214b9ad928SBarry Smith }
3224b9ad928SBarry Smith 
3234b9ad928SBarry Smith /*@C
324f1580f4eSBarry Smith   PCBJacobiGetSubKSP - Gets the local `KSP` contexts for all blocks on
3254b9ad928SBarry Smith   this processor.
3264b9ad928SBarry Smith 
3276da92b7fSHong Zhang   Not Collective
3284b9ad928SBarry Smith 
3294b9ad928SBarry Smith   Input Parameter:
3304b9ad928SBarry Smith . pc - the preconditioner context
3314b9ad928SBarry Smith 
3324b9ad928SBarry Smith   Output Parameters:
3330298fd71SBarry Smith + n_local     - the number of blocks on this processor, or NULL
3340298fd71SBarry Smith . first_local - the global number of the first block on this processor, or NULL
3354b9ad928SBarry Smith - ksp         - the array of KSP contexts
3364b9ad928SBarry Smith 
337ce78bad3SBarry Smith   Level: advanced
338ce78bad3SBarry Smith 
3394b9ad928SBarry Smith   Notes:
340f1580f4eSBarry Smith   After `PCBJacobiGetSubKSP()` the array of `KSP` contexts is not to be freed.
3414b9ad928SBarry Smith 
3424b9ad928SBarry Smith   Currently for some matrix implementations only 1 block per processor
3434b9ad928SBarry Smith   is supported.
3444b9ad928SBarry Smith 
345f1580f4eSBarry Smith   You must call `KSPSetUp()` or `PCSetUp()` before calling `PCBJacobiGetSubKSP()`.
3464b9ad928SBarry Smith 
34736083efbSBarry Smith   Fortran Note:
34836083efbSBarry Smith   Call `PCBJacobiRestoreSubKSP()` when you no longer need access to the array of `KSP`
34936083efbSBarry Smith 
350562efe2eSBarry Smith .seealso: [](ch_ksp), `PCBJACOBI`, `PCASM`, `PCASMGetSubKSP()`
3514b9ad928SBarry Smith @*/
352d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetSubKSP(PC pc, PetscInt *n_local, PetscInt *first_local, KSP *ksp[])
353d71ae5a4SJacob Faibussowitsch {
3544b9ad928SBarry Smith   PetscFunctionBegin;
3550700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
356cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetSubKSP_C", (PC, PetscInt *, PetscInt *, KSP **), (pc, n_local, first_local, ksp));
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3584b9ad928SBarry Smith }
3594b9ad928SBarry Smith 
3604b9ad928SBarry Smith /*@
3614b9ad928SBarry Smith   PCBJacobiSetTotalBlocks - Sets the global number of blocks for the block
3624b9ad928SBarry Smith   Jacobi preconditioner.
3634b9ad928SBarry Smith 
364c3339decSBarry Smith   Collective
3654b9ad928SBarry Smith 
3664b9ad928SBarry Smith   Input Parameters:
3674b9ad928SBarry Smith + pc     - the preconditioner context
3684b9ad928SBarry Smith . blocks - the number of blocks
3694b9ad928SBarry Smith - lens   - [optional] integer array containing the size of each block
3704b9ad928SBarry Smith 
3714b9ad928SBarry Smith   Options Database Key:
3724b9ad928SBarry Smith . -pc_bjacobi_blocks <blocks> - Sets the number of global blocks
3734b9ad928SBarry Smith 
374ce78bad3SBarry Smith   Level: intermediate
375ce78bad3SBarry Smith 
376f1580f4eSBarry Smith   Note:
3774b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
378f1580f4eSBarry Smith   All processors sharing the `PC` must call this routine with the same data.
3794b9ad928SBarry Smith 
380562efe2eSBarry Smith .seealso: [](ch_ksp), `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiSetLocalBlocks()`
3814b9ad928SBarry Smith @*/
382d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiSetTotalBlocks(PC pc, PetscInt blocks, const PetscInt lens[])
383d71ae5a4SJacob Faibussowitsch {
3844b9ad928SBarry Smith   PetscFunctionBegin;
3850700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
38608401ef6SPierre Jolivet   PetscCheck(blocks > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Must have positive blocks");
387cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetTotalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
3883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3894b9ad928SBarry Smith }
3904b9ad928SBarry Smith 
3914b9ad928SBarry Smith /*@C
3924b9ad928SBarry Smith   PCBJacobiGetTotalBlocks - Gets the global number of blocks for the block
393f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`, preconditioner.
3944b9ad928SBarry Smith 
395ad4df100SBarry Smith   Not Collective
3964b9ad928SBarry Smith 
3974b9ad928SBarry Smith   Input Parameter:
3984b9ad928SBarry Smith . pc - the preconditioner context
3994b9ad928SBarry Smith 
400feefa0e1SJacob Faibussowitsch   Output Parameters:
4014b9ad928SBarry Smith + blocks - the number of blocks
4024b9ad928SBarry Smith - lens   - integer array containing the size of each block
4034b9ad928SBarry Smith 
4044b9ad928SBarry Smith   Level: intermediate
4054b9ad928SBarry Smith 
406562efe2eSBarry Smith .seealso: [](ch_ksp), `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiGetLocalBlocks()`
4074b9ad928SBarry Smith @*/
408d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetTotalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
409d71ae5a4SJacob Faibussowitsch {
4104b9ad928SBarry Smith   PetscFunctionBegin;
4110700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4124f572ea9SToby Isaac   PetscAssertPointer(blocks, 2);
413cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetTotalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4154b9ad928SBarry Smith }
4164b9ad928SBarry Smith 
4174b9ad928SBarry Smith /*@
4184b9ad928SBarry Smith   PCBJacobiSetLocalBlocks - Sets the local number of blocks for the block
419f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`,  preconditioner.
4204b9ad928SBarry Smith 
4214b9ad928SBarry Smith   Not Collective
4224b9ad928SBarry Smith 
4234b9ad928SBarry Smith   Input Parameters:
4244b9ad928SBarry Smith + pc     - the preconditioner context
4254b9ad928SBarry Smith . blocks - the number of blocks
4264b9ad928SBarry Smith - lens   - [optional] integer array containing size of each block
4274b9ad928SBarry Smith 
428342c94f9SMatthew G. Knepley   Options Database Key:
429342c94f9SMatthew G. Knepley . -pc_bjacobi_local_blocks <blocks> - Sets the number of local blocks
430342c94f9SMatthew G. Knepley 
431ce78bad3SBarry Smith   Level: intermediate
432ce78bad3SBarry Smith 
4334b9ad928SBarry Smith   Note:
4344b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
4354b9ad928SBarry Smith 
436562efe2eSBarry Smith .seealso: [](ch_ksp), `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiSetTotalBlocks()`
4374b9ad928SBarry Smith @*/
438d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiSetLocalBlocks(PC pc, PetscInt blocks, const PetscInt lens[])
439d71ae5a4SJacob Faibussowitsch {
4404b9ad928SBarry Smith   PetscFunctionBegin;
4410700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
44208401ef6SPierre Jolivet   PetscCheck(blocks >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have nonegative blocks");
443cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetLocalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4454b9ad928SBarry Smith }
4464b9ad928SBarry Smith 
4474b9ad928SBarry Smith /*@C
4484b9ad928SBarry Smith   PCBJacobiGetLocalBlocks - Gets the local number of blocks for the block
449f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`, preconditioner.
4504b9ad928SBarry Smith 
4514b9ad928SBarry Smith   Not Collective
4524b9ad928SBarry Smith 
4534b9ad928SBarry Smith   Input Parameters:
4544b9ad928SBarry Smith + pc     - the preconditioner context
4554b9ad928SBarry Smith . blocks - the number of blocks
4564b9ad928SBarry Smith - lens   - [optional] integer array containing size of each block
4574b9ad928SBarry Smith 
458ce78bad3SBarry Smith   Level: intermediate
459ce78bad3SBarry Smith 
4604b9ad928SBarry Smith   Note:
4614b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
4624b9ad928SBarry Smith 
463562efe2eSBarry Smith .seealso: [](ch_ksp), `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiGetTotalBlocks()`
4644b9ad928SBarry Smith @*/
465d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetLocalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
466d71ae5a4SJacob Faibussowitsch {
4674b9ad928SBarry Smith   PetscFunctionBegin;
4680700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4694f572ea9SToby Isaac   PetscAssertPointer(blocks, 2);
470cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetLocalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4724b9ad928SBarry Smith }
4734b9ad928SBarry Smith 
4744b9ad928SBarry Smith /*MC
4754b9ad928SBarry Smith    PCBJACOBI - Use block Jacobi preconditioning, each block is (approximately) solved with
476f1580f4eSBarry Smith            its own `KSP` object.
4774b9ad928SBarry Smith 
4784b9ad928SBarry Smith    Options Database Keys:
479011ea8aeSBarry Smith +  -pc_use_amat - use Amat to apply block of operator in inner Krylov method
480011ea8aeSBarry Smith -  -pc_bjacobi_blocks <n> - use n total blocks
4814b9ad928SBarry Smith 
482ce78bad3SBarry Smith    Level: beginner
483ce78bad3SBarry Smith 
48495452b02SPatrick Sanan    Notes:
485f1580f4eSBarry Smith     See `PCJACOBI` for diagonal Jacobi, `PCVPBJACOBI` for variable point block, and `PCPBJACOBI` for fixed size point block
486468ae2e8SBarry Smith 
48795452b02SPatrick Sanan     Each processor can have one or more blocks, or a single block can be shared by several processes. Defaults to one block per processor.
4884b9ad928SBarry Smith 
489f1580f4eSBarry Smith      To set options on the solvers for each block append -sub_ to all the `KSP` and `PC`
490d7ee0231SBarry Smith         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
4914b9ad928SBarry Smith 
492f1580f4eSBarry Smith      To set the options on the solvers separate for each block call `PCBJacobiGetSubKSP()`
493f1580f4eSBarry Smith          and set the options directly on the resulting `KSP` object (you can access its `PC`
4940462cc06SPierre Jolivet          `KSPGetPC()`)
4954b9ad928SBarry Smith 
496f1580f4eSBarry Smith      For GPU-based vectors (`VECCUDA`, `VECViennaCL`) it is recommended to use exactly one block per MPI process for best
4972210c163SDominic Meiser          performance.  Different block partitioning may lead to additional data transfers
4982210c163SDominic Meiser          between host and GPU that lead to degraded performance.
4992210c163SDominic Meiser 
500011ea8aeSBarry Smith      When multiple processes share a single block, each block encompasses exactly all the unknowns owned its set of processes.
501011ea8aeSBarry Smith 
502562efe2eSBarry Smith .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCType`,
503db781477SPatrick Sanan           `PCASM`, `PCSetUseAmat()`, `PCGetUseAmat()`, `PCBJacobiGetSubKSP()`, `PCBJacobiSetTotalBlocks()`,
504db781477SPatrick Sanan           `PCBJacobiSetLocalBlocks()`, `PCSetModifySubMatrices()`, `PCJACOBI`, `PCVPBJACOBI`, `PCPBJACOBI`
5054b9ad928SBarry Smith M*/
5064b9ad928SBarry Smith 
507d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_BJacobi(PC pc)
508d71ae5a4SJacob Faibussowitsch {
50969a612a9SBarry Smith   PetscMPIInt rank;
5104b9ad928SBarry Smith   PC_BJacobi *jac;
5114b9ad928SBarry Smith 
5124b9ad928SBarry Smith   PetscFunctionBegin;
5134dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&jac));
5149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
5152fa5cd67SKarl Rupp 
5160a545947SLisandro Dalcin   pc->ops->apply             = NULL;
5177b6e2003SPierre Jolivet   pc->ops->matapply          = NULL;
5180a545947SLisandro Dalcin   pc->ops->applytranspose    = NULL;
5194dbf25a8SPierre Jolivet   pc->ops->matapplytranspose = NULL;
5204b9ad928SBarry Smith   pc->ops->setup             = PCSetUp_BJacobi;
5214b9ad928SBarry Smith   pc->ops->destroy           = PCDestroy_BJacobi;
5224b9ad928SBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_BJacobi;
5234b9ad928SBarry Smith   pc->ops->view              = PCView_BJacobi;
5240a545947SLisandro Dalcin   pc->ops->applyrichardson   = NULL;
5254b9ad928SBarry Smith 
5264b9ad928SBarry Smith   pc->data         = (void *)jac;
5274b9ad928SBarry Smith   jac->n           = -1;
5284b9ad928SBarry Smith   jac->n_local     = -1;
5294b9ad928SBarry Smith   jac->first_local = rank;
5300a545947SLisandro Dalcin   jac->ksp         = NULL;
5310a545947SLisandro Dalcin   jac->g_lens      = NULL;
5320a545947SLisandro Dalcin   jac->l_lens      = NULL;
5330a545947SLisandro Dalcin   jac->psubcomm    = NULL;
5344b9ad928SBarry Smith 
5359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetSubKSP_C", PCBJacobiGetSubKSP_BJacobi));
5369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetTotalBlocks_C", PCBJacobiSetTotalBlocks_BJacobi));
5379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetTotalBlocks_C", PCBJacobiGetTotalBlocks_BJacobi));
5389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetLocalBlocks_C", PCBJacobiSetLocalBlocks_BJacobi));
5399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetLocalBlocks_C", PCBJacobiGetLocalBlocks_BJacobi));
5403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5414b9ad928SBarry Smith }
5424b9ad928SBarry Smith 
5434b9ad928SBarry Smith /*
5444b9ad928SBarry Smith         These are for a single block per processor; works for AIJ, BAIJ; Seq and MPI
5454b9ad928SBarry Smith */
546d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Singleblock(PC pc)
547d71ae5a4SJacob Faibussowitsch {
5484b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
5494b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
5504b9ad928SBarry Smith 
5514b9ad928SBarry Smith   PetscFunctionBegin;
5529566063dSJacob Faibussowitsch   PetscCall(KSPReset(jac->ksp[0]));
5539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->x));
5549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->y));
5553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
556e91c6855SBarry Smith }
557e91c6855SBarry Smith 
558d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Singleblock(PC pc)
559d71ae5a4SJacob Faibussowitsch {
560e91c6855SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
561e91c6855SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
562e91c6855SBarry Smith 
563e91c6855SBarry Smith   PetscFunctionBegin;
5649566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Singleblock(pc));
5659566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
5669566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
5679566063dSJacob Faibussowitsch   PetscCall(PetscFree(bjac));
5682e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
5693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5704b9ad928SBarry Smith }
5714b9ad928SBarry Smith 
572d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Singleblock(PC pc)
573d71ae5a4SJacob Faibussowitsch {
5744b9ad928SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
5752295b7c8SHong Zhang   KSP                subksp = jac->ksp[0];
576539c167fSBarry Smith   KSPConvergedReason reason;
5774b9ad928SBarry Smith 
5784b9ad928SBarry Smith   PetscFunctionBegin;
5799566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
5809566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
581ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
5823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5834b9ad928SBarry Smith }
5844b9ad928SBarry Smith 
585d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Singleblock(PC pc, Vec x, Vec y)
586d71ae5a4SJacob Faibussowitsch {
5874b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
5884b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
5896e111a19SKarl Rupp 
5904b9ad928SBarry Smith   PetscFunctionBegin;
5919566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVectorRead(x, bjac->x));
5929566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVector(y, bjac->y));
593bba28a21SBarry Smith   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
594910cf402Sprj-      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
595910cf402Sprj-      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
5969566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
597a9db3dc1SPierre Jolivet   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], bjac->x, bjac->y, 0));
5989566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], bjac->x, bjac->y));
5999566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
600a9db3dc1SPierre Jolivet   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], bjac->x, bjac->y, 0));
6019566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVectorRead(x, bjac->x));
6029566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVector(y, bjac->y));
6033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6044b9ad928SBarry Smith }
6054b9ad928SBarry Smith 
6064dbf25a8SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Singleblock_Private(PC pc, Mat X, Mat Y, PetscBool transpose)
607d71ae5a4SJacob Faibussowitsch {
6087b6e2003SPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
6097b6e2003SPierre Jolivet   Mat         sX, sY;
6107b6e2003SPierre Jolivet 
6117b6e2003SPierre Jolivet   PetscFunctionBegin;
6127b6e2003SPierre Jolivet   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
6137b6e2003SPierre Jolivet      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
6147b6e2003SPierre Jolivet      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6159566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
6169566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(X, &sX));
6179566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Y, &sY));
61878d05565SPierre Jolivet   if (!transpose) {
61978d05565SPierre Jolivet     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], sX, sY, 0));
62078d05565SPierre Jolivet     PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
62178d05565SPierre Jolivet     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], sX, sY, 0));
62278d05565SPierre Jolivet   } else {
62378d05565SPierre Jolivet     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks, jac->ksp[0], sX, sY, 0));
62478d05565SPierre Jolivet     PetscCall(KSPMatSolveTranspose(jac->ksp[0], sX, sY));
62578d05565SPierre Jolivet     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks, jac->ksp[0], sX, sY, 0));
62678d05565SPierre Jolivet   }
6274dbf25a8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
6284dbf25a8SPierre Jolivet }
6294dbf25a8SPierre Jolivet 
6304dbf25a8SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Singleblock(PC pc, Mat X, Mat Y)
6314dbf25a8SPierre Jolivet {
6324dbf25a8SPierre Jolivet   PetscFunctionBegin;
6334dbf25a8SPierre Jolivet   PetscCall(PCMatApply_BJacobi_Singleblock_Private(pc, X, Y, PETSC_FALSE));
6344dbf25a8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
6354dbf25a8SPierre Jolivet }
6364dbf25a8SPierre Jolivet 
6374dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_BJacobi_Singleblock(PC pc, Mat X, Mat Y)
6384dbf25a8SPierre Jolivet {
6394dbf25a8SPierre Jolivet   PetscFunctionBegin;
6404dbf25a8SPierre Jolivet   PetscCall(PCMatApply_BJacobi_Singleblock_Private(pc, X, Y, PETSC_TRUE));
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6427b6e2003SPierre Jolivet }
6437b6e2003SPierre Jolivet 
644d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplySymmetricLeft_BJacobi_Singleblock(PC pc, Vec x, Vec y)
645d71ae5a4SJacob Faibussowitsch {
6464b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6474b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
648d9ca1df4SBarry Smith   PetscScalar            *y_array;
649d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6504b9ad928SBarry Smith   PC                      subpc;
6514b9ad928SBarry Smith 
6524b9ad928SBarry Smith   PetscFunctionBegin;
6534b9ad928SBarry Smith   /*
6544b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6554b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6564b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6574b9ad928SBarry Smith     for the sequential solve.
6584b9ad928SBarry Smith   */
6599566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6609566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6619566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6629566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6634b9ad928SBarry Smith   /* apply the symmetric left portion of the inner PC operator */
664c3f9dca2SPierre Jolivet   /* note this bypasses the inner KSP and its options completely */
6659566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6669566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricLeft(subpc, bjac->x, bjac->y));
6679566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
6689566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
6699566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
6709566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
6713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6724b9ad928SBarry Smith }
6734b9ad928SBarry Smith 
674d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplySymmetricRight_BJacobi_Singleblock(PC pc, Vec x, Vec y)
675d71ae5a4SJacob Faibussowitsch {
6764b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6774b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
678d9ca1df4SBarry Smith   PetscScalar            *y_array;
679d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6804b9ad928SBarry Smith   PC                      subpc;
6814b9ad928SBarry Smith 
6824b9ad928SBarry Smith   PetscFunctionBegin;
6834b9ad928SBarry Smith   /*
6844b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6854b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6864b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6874b9ad928SBarry Smith     for the sequential solve.
6884b9ad928SBarry Smith   */
6899566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6909566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6919566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6929566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6934b9ad928SBarry Smith 
6944b9ad928SBarry Smith   /* apply the symmetric right portion of the inner PC operator */
695c3f9dca2SPierre Jolivet   /* note this bypasses the inner KSP and its options completely */
6964b9ad928SBarry Smith 
6979566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6989566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricRight(subpc, bjac->x, bjac->y));
6994b9ad928SBarry Smith 
70011e4f71cSBarry Smith   PetscCall(VecResetArray(bjac->x));
70111e4f71cSBarry Smith   PetscCall(VecResetArray(bjac->y));
7029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
7039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
7043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7054b9ad928SBarry Smith }
7064b9ad928SBarry Smith 
707d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_BJacobi_Singleblock(PC pc, Vec x, Vec y)
708d71ae5a4SJacob Faibussowitsch {
7094b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
7104b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
711d9ca1df4SBarry Smith   PetscScalar            *y_array;
712d9ca1df4SBarry Smith   const PetscScalar      *x_array;
7134b9ad928SBarry Smith 
7144b9ad928SBarry Smith   PetscFunctionBegin;
7154b9ad928SBarry Smith   /*
7164b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
7174b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
7184b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
7194b9ad928SBarry Smith     for the sequential solve.
7204b9ad928SBarry Smith   */
7219566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
7229566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
7239566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
7249566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
725a9db3dc1SPierre Jolivet   PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks, jac->ksp[0], bjac->x, bjac->y, 0));
7269566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(jac->ksp[0], bjac->x, bjac->y));
7279566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
728a9db3dc1SPierre Jolivet   PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks, jac->ksp[0], bjac->x, bjac->y, 0));
7299566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
7309566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
7319566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
7329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
7333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7344b9ad928SBarry Smith }
7354b9ad928SBarry Smith 
736d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC pc, Mat mat, Mat pmat)
737d71ae5a4SJacob Faibussowitsch {
7384b9ad928SBarry Smith   PC_BJacobi             *jac = (PC_BJacobi *)pc->data;
73969a612a9SBarry Smith   PetscInt                m;
7404b9ad928SBarry Smith   KSP                     ksp;
7414b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac;
742de0953f6SBarry Smith   PetscBool               wasSetup = PETSC_TRUE;
7433f6dc190SJunchao Zhang   VecType                 vectype;
744ea41da7aSPierre Jolivet   const char             *prefix;
7454b9ad928SBarry Smith 
7464b9ad928SBarry Smith   PetscFunctionBegin;
7474b9ad928SBarry Smith   if (!pc->setupcalled) {
748c2efdce3SBarry Smith     if (!jac->ksp) {
7493821be0aSBarry Smith       PetscInt nestlevel;
7503821be0aSBarry Smith 
751302a9ddcSMatthew Knepley       wasSetup = PETSC_FALSE;
7522fa5cd67SKarl Rupp 
7539566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
7543821be0aSBarry Smith       PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
7553821be0aSBarry Smith       PetscCall(KSPSetNestLevel(ksp, nestlevel + 1));
7569566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
7579566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
7589566063dSJacob Faibussowitsch       PetscCall(KSPSetType(ksp, KSPPREONLY));
7599566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
7609566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp, prefix));
7619566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
7624b9ad928SBarry Smith 
763e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Singleblock;
7644b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Singleblock;
7654b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Singleblock;
7667b6e2003SPierre Jolivet       pc->ops->matapply            = PCMatApply_BJacobi_Singleblock;
7674dbf25a8SPierre Jolivet       pc->ops->matapplytranspose   = PCMatApplyTranspose_BJacobi_Singleblock;
7684b9ad928SBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Singleblock;
7694b9ad928SBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Singleblock;
7704b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Singleblock;
7714b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Singleblock;
7724b9ad928SBarry Smith 
7739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, &jac->ksp));
7744b9ad928SBarry Smith       jac->ksp[0] = ksp;
775c2efdce3SBarry Smith 
7764dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&bjac));
7774b9ad928SBarry Smith       jac->data = (void *)bjac;
7784b9ad928SBarry Smith     } else {
779c2efdce3SBarry Smith       ksp  = jac->ksp[0];
780c2efdce3SBarry Smith       bjac = (PC_BJacobi_Singleblock *)jac->data;
781c2efdce3SBarry Smith     }
782c2efdce3SBarry Smith 
783c2efdce3SBarry Smith     /*
784c2efdce3SBarry Smith       The reason we need to generate these vectors is to serve
785c2efdce3SBarry Smith       as the right-hand side and solution vector for the solve on the
786c2efdce3SBarry Smith       block. We do not need to allocate space for the vectors since
787c2efdce3SBarry Smith       that is provided via VecPlaceArray() just before the call to
788c2efdce3SBarry Smith       KSPSolve() on the block.
789c2efdce3SBarry Smith     */
7909566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pmat, &m, &m));
7919566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->x));
7929566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->y));
7939566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
7949566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->x, vectype));
7959566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->y, vectype));
796c2efdce3SBarry Smith   } else {
7974b9ad928SBarry Smith     ksp  = jac->ksp[0];
7984b9ad928SBarry Smith     bjac = (PC_BJacobi_Singleblock *)jac->data;
7994b9ad928SBarry Smith   }
8009566063dSJacob Faibussowitsch   PetscCall(KSPGetOptionsPrefix(ksp, &prefix));
80149517cdeSBarry Smith   if (pc->useAmat) {
8029566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, mat, pmat));
8039566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mat, prefix));
8044b9ad928SBarry Smith   } else {
8059566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, pmat, pmat));
8064b9ad928SBarry Smith   }
8079566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(pmat, prefix));
80890f1c854SHong Zhang   if (!wasSetup && pc->setfromoptionscalled) {
809248bfaf0SJed Brown     /* If PCSetFromOptions_BJacobi is called later, KSPSetFromOptions will be called at that time. */
8109566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ksp));
811302a9ddcSMatthew Knepley   }
8123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8134b9ad928SBarry Smith }
8144b9ad928SBarry Smith 
815d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Multiblock(PC pc)
816d71ae5a4SJacob Faibussowitsch {
8174b9ad928SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
8184b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
81969a612a9SBarry Smith   PetscInt               i;
8204b9ad928SBarry Smith 
8214b9ad928SBarry Smith   PetscFunctionBegin;
822e91c6855SBarry Smith   if (bjac && bjac->pmat) {
8239566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->n_local, &bjac->pmat));
82448a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(MatDestroyMatrices(jac->n_local, &bjac->mat));
825e91c6855SBarry Smith   }
8264b9ad928SBarry Smith 
8274b9ad928SBarry Smith   for (i = 0; i < jac->n_local; i++) {
8289566063dSJacob Faibussowitsch     PetscCall(KSPReset(jac->ksp[i]));
829e91c6855SBarry Smith     if (bjac && bjac->x) {
8309566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->x[i]));
8319566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->y[i]));
8329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&bjac->is[i]));
8334b9ad928SBarry Smith     }
834e91c6855SBarry Smith   }
8359566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
8369566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
8373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
838e91c6855SBarry Smith }
839e91c6855SBarry Smith 
840d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Multiblock(PC pc)
841d71ae5a4SJacob Faibussowitsch {
842e91c6855SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
843c2efdce3SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
844e91c6855SBarry Smith   PetscInt               i;
845e91c6855SBarry Smith 
846e91c6855SBarry Smith   PetscFunctionBegin;
8479566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiblock(pc));
848c2efdce3SBarry Smith   if (bjac) {
8499566063dSJacob Faibussowitsch     PetscCall(PetscFree2(bjac->x, bjac->y));
8509566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->starts));
8519566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->is));
852c2efdce3SBarry Smith   }
8539566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->data));
85448a46eb9SPierre Jolivet   for (i = 0; i < jac->n_local; i++) PetscCall(KSPDestroy(&jac->ksp[i]));
8559566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
8562e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
8573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8584b9ad928SBarry Smith }
8594b9ad928SBarry Smith 
860d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiblock(PC pc)
861d71ae5a4SJacob Faibussowitsch {
8624b9ad928SBarry Smith   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
86369a612a9SBarry Smith   PetscInt           i, n_local = jac->n_local;
864539c167fSBarry Smith   KSPConvergedReason reason;
8654b9ad928SBarry Smith 
8664b9ad928SBarry Smith   PetscFunctionBegin;
8674b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8689566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(jac->ksp[i]));
8699566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(jac->ksp[i], &reason));
870ad540459SPierre Jolivet     if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
8714b9ad928SBarry Smith   }
8723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8734b9ad928SBarry Smith }
8744b9ad928SBarry Smith 
875d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Multiblock(PC pc, Vec x, Vec y)
876d71ae5a4SJacob Faibussowitsch {
8774b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
87869a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
8794b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
880d9ca1df4SBarry Smith   PetscScalar           *yin;
881d9ca1df4SBarry Smith   const PetscScalar     *xin;
88258ebbce7SBarry Smith 
8834b9ad928SBarry Smith   PetscFunctionBegin;
8849566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
8859566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
8864b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8874b9ad928SBarry Smith     /*
8884b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
8894b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
8904b9ad928SBarry Smith        the global vector.
8914b9ad928SBarry Smith     */
8929566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
8939566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
8944b9ad928SBarry Smith 
8959566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
8969566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->ksp[i], bjac->x[i], bjac->y[i]));
8979566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
8989566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
899d11f3a42SBarry Smith 
9009566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9019566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9024b9ad928SBarry Smith   }
9039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
9049566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
9053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9064b9ad928SBarry Smith }
9074b9ad928SBarry Smith 
908f4d694ddSBarry Smith static PetscErrorCode PCApplySymmetricLeft_BJacobi_Multiblock(PC pc, Vec x, Vec y)
909f4d694ddSBarry Smith {
910f4d694ddSBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
911f4d694ddSBarry Smith   PetscInt               i, n_local = jac->n_local;
912f4d694ddSBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
913f4d694ddSBarry Smith   PetscScalar           *yin;
914f4d694ddSBarry Smith   const PetscScalar     *xin;
915f4d694ddSBarry Smith   PC                     subpc;
916f4d694ddSBarry Smith 
917f4d694ddSBarry Smith   PetscFunctionBegin;
918f4d694ddSBarry Smith   PetscCall(VecGetArrayRead(x, &xin));
919f4d694ddSBarry Smith   PetscCall(VecGetArray(y, &yin));
920f4d694ddSBarry Smith   for (i = 0; i < n_local; i++) {
9214b9ad928SBarry Smith     /*
922f4d694ddSBarry Smith        To avoid copying the subvector from x into a workspace we instead
923f4d694ddSBarry Smith        make the workspace vector array point to the subpart of the array of
924f4d694ddSBarry Smith        the global vector.
9254b9ad928SBarry Smith     */
926f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
927f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
928f4d694ddSBarry Smith 
929f4d694ddSBarry Smith     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
930f4d694ddSBarry Smith     /* apply the symmetric left portion of the inner PC operator */
931c3f9dca2SPierre Jolivet     /* note this bypasses the inner KSP and its options completely */
932f4d694ddSBarry Smith     PetscCall(KSPGetPC(jac->ksp[i], &subpc));
933f4d694ddSBarry Smith     PetscCall(PCApplySymmetricLeft(subpc, bjac->x[i], bjac->y[i]));
934f4d694ddSBarry Smith     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
935f4d694ddSBarry Smith 
936f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->x[i]));
937f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->y[i]));
938f4d694ddSBarry Smith   }
939f4d694ddSBarry Smith   PetscCall(VecRestoreArrayRead(x, &xin));
940f4d694ddSBarry Smith   PetscCall(VecRestoreArray(y, &yin));
9413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
942f4d694ddSBarry Smith }
943f4d694ddSBarry Smith 
944f4d694ddSBarry Smith static PetscErrorCode PCApplySymmetricRight_BJacobi_Multiblock(PC pc, Vec x, Vec y)
945f4d694ddSBarry Smith {
946f4d694ddSBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
947f4d694ddSBarry Smith   PetscInt               i, n_local = jac->n_local;
948f4d694ddSBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
949f4d694ddSBarry Smith   PetscScalar           *yin;
950f4d694ddSBarry Smith   const PetscScalar     *xin;
951f4d694ddSBarry Smith   PC                     subpc;
952f4d694ddSBarry Smith 
953f4d694ddSBarry Smith   PetscFunctionBegin;
954f4d694ddSBarry Smith   PetscCall(VecGetArrayRead(x, &xin));
955f4d694ddSBarry Smith   PetscCall(VecGetArray(y, &yin));
956f4d694ddSBarry Smith   for (i = 0; i < n_local; i++) {
957f4d694ddSBarry Smith     /*
958f4d694ddSBarry Smith        To avoid copying the subvector from x into a workspace we instead
959f4d694ddSBarry Smith        make the workspace vector array point to the subpart of the array of
960f4d694ddSBarry Smith        the global vector.
961f4d694ddSBarry Smith     */
962f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
963f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
964f4d694ddSBarry Smith 
965f4d694ddSBarry Smith     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
966f4d694ddSBarry Smith     /* apply the symmetric left portion of the inner PC operator */
967c3f9dca2SPierre Jolivet     /* note this bypasses the inner KSP and its options completely */
968f4d694ddSBarry Smith     PetscCall(KSPGetPC(jac->ksp[i], &subpc));
969f4d694ddSBarry Smith     PetscCall(PCApplySymmetricRight(subpc, bjac->x[i], bjac->y[i]));
970f4d694ddSBarry Smith     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
971f4d694ddSBarry Smith 
972f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->x[i]));
973f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->y[i]));
974f4d694ddSBarry Smith   }
975f4d694ddSBarry Smith   PetscCall(VecRestoreArrayRead(x, &xin));
976f4d694ddSBarry Smith   PetscCall(VecRestoreArray(y, &yin));
9773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
978f4d694ddSBarry Smith }
979f4d694ddSBarry Smith 
980d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_BJacobi_Multiblock(PC pc, Vec x, Vec y)
981d71ae5a4SJacob Faibussowitsch {
9824b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
98369a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
9844b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
985d9ca1df4SBarry Smith   PetscScalar           *yin;
986d9ca1df4SBarry Smith   const PetscScalar     *xin;
9874b9ad928SBarry Smith 
9884b9ad928SBarry Smith   PetscFunctionBegin;
9899566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
9909566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
9914b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
9924b9ad928SBarry Smith     /*
9934b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
9944b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
9954b9ad928SBarry Smith        the global vector.
9964b9ad928SBarry Smith     */
9979566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
9989566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
9994b9ad928SBarry Smith 
10009566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
10019566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(jac->ksp[i], bjac->x[i], bjac->y[i]));
10029566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
10039566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
1004a7ff49e8SJed Brown 
10059566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
10069566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
10074b9ad928SBarry Smith   }
10089566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
10099566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
10103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10114b9ad928SBarry Smith }
10124b9ad928SBarry Smith 
1013d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC pc, Mat mat, Mat pmat)
1014d71ae5a4SJacob Faibussowitsch {
10154b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
101669a612a9SBarry Smith   PetscInt               m, n_local, N, M, start, i;
1017ea41da7aSPierre Jolivet   const char            *prefix;
10184b9ad928SBarry Smith   KSP                    ksp;
10194b9ad928SBarry Smith   Vec                    x, y;
10204b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
10214b9ad928SBarry Smith   PC                     subpc;
10224b9ad928SBarry Smith   IS                     is;
1023434a97beSBrad Aagaard   MatReuse               scall;
10243f6dc190SJunchao Zhang   VecType                vectype;
10254849c82aSBarry Smith   MatNullSpace          *nullsp_mat = NULL, *nullsp_pmat = NULL;
10264b9ad928SBarry Smith 
10274b9ad928SBarry Smith   PetscFunctionBegin;
10289566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &M, &N));
10294b9ad928SBarry Smith 
10304b9ad928SBarry Smith   n_local = jac->n_local;
10314b9ad928SBarry Smith 
103249517cdeSBarry Smith   if (pc->useAmat) {
1033ace3abfcSBarry Smith     PetscBool same;
10349566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat, ((PetscObject)pmat)->type_name, &same));
103528b400f6SJacob Faibussowitsch     PetscCheck(same, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Matrices not of same type");
10364b9ad928SBarry Smith   }
10374b9ad928SBarry Smith 
10384b9ad928SBarry Smith   if (!pc->setupcalled) {
10393821be0aSBarry Smith     PetscInt nestlevel;
10403821be0aSBarry Smith 
10414b9ad928SBarry Smith     scall = MAT_INITIAL_MATRIX;
1042c2efdce3SBarry Smith 
1043c2efdce3SBarry Smith     if (!jac->ksp) {
1044e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Multiblock;
10454b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Multiblock;
10464b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Multiblock;
10477b6e2003SPierre Jolivet       pc->ops->matapply            = NULL;
10484dbf25a8SPierre Jolivet       pc->ops->matapplytranspose   = NULL;
1049f4d694ddSBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Multiblock;
1050f4d694ddSBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Multiblock;
10514b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Multiblock;
10524b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Multiblock;
10534b9ad928SBarry Smith 
10544dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&bjac));
10559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &jac->ksp));
10569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n_local, &bjac->x, n_local, &bjac->y));
10579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->starts));
10584b9ad928SBarry Smith 
10594b9ad928SBarry Smith       jac->data = (void *)bjac;
10609566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->is));
10614b9ad928SBarry Smith 
10624b9ad928SBarry Smith       for (i = 0; i < n_local; i++) {
10639566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
10643821be0aSBarry Smith         PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
10653821be0aSBarry Smith         PetscCall(KSPSetNestLevel(ksp, nestlevel + 1));
10669566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
10679566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
10689566063dSJacob Faibussowitsch         PetscCall(KSPSetType(ksp, KSPPREONLY));
10699566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp, &subpc));
10709566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc, &prefix));
10719566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp, prefix));
10729566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
10732fa5cd67SKarl Rupp 
1074c2efdce3SBarry Smith         jac->ksp[i] = ksp;
1075c2efdce3SBarry Smith       }
1076c2efdce3SBarry Smith     } else {
1077c2efdce3SBarry Smith       bjac = (PC_BJacobi_Multiblock *)jac->data;
1078c2efdce3SBarry Smith     }
10794b9ad928SBarry Smith 
1080c2efdce3SBarry Smith     start = 0;
10819566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
1082c2efdce3SBarry Smith     for (i = 0; i < n_local; i++) {
10834b9ad928SBarry Smith       m = jac->l_lens[i];
10844b9ad928SBarry Smith       /*
10854b9ad928SBarry Smith       The reason we need to generate these vectors is to serve
10864b9ad928SBarry Smith       as the right-hand side and solution vector for the solve on the
10874b9ad928SBarry Smith       block. We do not need to allocate space for the vectors since
10884b9ad928SBarry Smith       that is provided via VecPlaceArray() just before the call to
10894b9ad928SBarry Smith       KSPSolve() on the block.
10904b9ad928SBarry Smith 
10914b9ad928SBarry Smith       */
10929566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, m, &x));
10939566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &y));
10949566063dSJacob Faibussowitsch       PetscCall(VecSetType(x, vectype));
10959566063dSJacob Faibussowitsch       PetscCall(VecSetType(y, vectype));
10962fa5cd67SKarl Rupp 
10974b9ad928SBarry Smith       bjac->x[i]      = x;
10984b9ad928SBarry Smith       bjac->y[i]      = y;
10994b9ad928SBarry Smith       bjac->starts[i] = start;
11004b9ad928SBarry Smith 
11019566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, m, start, 1, &is));
11024b9ad928SBarry Smith       bjac->is[i] = is;
11034b9ad928SBarry Smith 
11044b9ad928SBarry Smith       start += m;
11054b9ad928SBarry Smith     }
11064b9ad928SBarry Smith   } else {
11074b9ad928SBarry Smith     bjac = (PC_BJacobi_Multiblock *)jac->data;
11084b9ad928SBarry Smith     /*
11094b9ad928SBarry Smith        Destroy the blocks from the previous iteration
11104b9ad928SBarry Smith     */
11114b9ad928SBarry Smith     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
11124849c82aSBarry Smith       PetscCall(MatGetNullSpaces(n_local, bjac->pmat, &nullsp_pmat));
11139566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(n_local, &bjac->pmat));
11144849c82aSBarry Smith       if (pc->useAmat) {
11154849c82aSBarry Smith         PetscCall(MatGetNullSpaces(n_local, bjac->mat, &nullsp_mat));
11164849c82aSBarry Smith         PetscCall(MatDestroyMatrices(n_local, &bjac->mat));
11174849c82aSBarry Smith       }
11184b9ad928SBarry Smith       scall = MAT_INITIAL_MATRIX;
11192fa5cd67SKarl Rupp     } else scall = MAT_REUSE_MATRIX;
11204b9ad928SBarry Smith   }
11214b9ad928SBarry Smith 
11229566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(pmat, n_local, bjac->is, bjac->is, scall, &bjac->pmat));
11234849c82aSBarry Smith   if (nullsp_pmat) PetscCall(MatRestoreNullSpaces(n_local, bjac->pmat, &nullsp_pmat));
11244849c82aSBarry Smith   if (pc->useAmat) {
11254849c82aSBarry Smith     PetscCall(MatCreateSubMatrices(mat, n_local, bjac->is, bjac->is, scall, &bjac->mat));
11264849c82aSBarry Smith     if (nullsp_mat) PetscCall(MatRestoreNullSpaces(n_local, bjac->mat, &nullsp_mat));
11274849c82aSBarry Smith   }
11284b9ad928SBarry Smith   /* Return control to the user so that the submatrices can be modified (e.g., to apply
11294b9ad928SBarry Smith      different boundary conditions for the submatrices than for the global problem) */
11309566063dSJacob Faibussowitsch   PetscCall(PCModifySubMatrices(pc, n_local, bjac->is, bjac->is, bjac->pmat, pc->modifysubmatricesP));
11314b9ad928SBarry Smith 
11324b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
11339566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[i], &prefix));
113449517cdeSBarry Smith     if (pc->useAmat) {
11359566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->mat[i], bjac->pmat[i]));
11369566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(bjac->mat[i], prefix));
11374b9ad928SBarry Smith     } else {
11389566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->pmat[i], bjac->pmat[i]));
11394b9ad928SBarry Smith     }
11409566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(bjac->pmat[i], prefix));
114148a46eb9SPierre Jolivet     if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[i]));
114290f1c854SHong Zhang   }
11433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11444b9ad928SBarry Smith }
11455a7e1895SHong Zhang 
11465a7e1895SHong Zhang /*
1147fd0b8932SBarry Smith       These are for a single block with multiple processes
11485a7e1895SHong Zhang */
1149d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiproc(PC pc)
1150d71ae5a4SJacob Faibussowitsch {
1151fd0b8932SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
1152fd0b8932SBarry Smith   KSP                subksp = jac->ksp[0];
1153fd0b8932SBarry Smith   KSPConvergedReason reason;
1154fd0b8932SBarry Smith 
1155fd0b8932SBarry Smith   PetscFunctionBegin;
11569566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
11579566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
1158ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1160fd0b8932SBarry Smith }
1161fd0b8932SBarry Smith 
1162d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Multiproc(PC pc)
1163d71ae5a4SJacob Faibussowitsch {
11645a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
11655a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
11665a7e1895SHong Zhang 
11675a7e1895SHong Zhang   PetscFunctionBegin;
11689566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->ysub));
11699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->xsub));
11709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mpjac->submats));
11719566063dSJacob Faibussowitsch   if (jac->ksp) PetscCall(KSPReset(jac->ksp[0]));
11723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1173e91c6855SBarry Smith }
1174e91c6855SBarry Smith 
1175d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Multiproc(PC pc)
1176d71ae5a4SJacob Faibussowitsch {
1177e91c6855SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
1178e91c6855SBarry Smith   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1179e91c6855SBarry Smith 
1180e91c6855SBarry Smith   PetscFunctionBegin;
11819566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiproc(pc));
11829566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
11839566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
11849566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&mpjac->psubcomm));
11855a7e1895SHong Zhang 
11869566063dSJacob Faibussowitsch   PetscCall(PetscFree(mpjac));
11872e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
11883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11895a7e1895SHong Zhang }
11905a7e1895SHong Zhang 
1191d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Multiproc(PC pc, Vec x, Vec y)
1192d71ae5a4SJacob Faibussowitsch {
11935a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
11945a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1195d9ca1df4SBarry Smith   PetscScalar          *yarray;
1196d9ca1df4SBarry Smith   const PetscScalar    *xarray;
1197539c167fSBarry Smith   KSPConvergedReason    reason;
11985a7e1895SHong Zhang 
11995a7e1895SHong Zhang   PetscFunctionBegin;
12005a7e1895SHong Zhang   /* place x's and y's local arrays into xsub and ysub */
12019566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xarray));
12029566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yarray));
12039566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->xsub, xarray));
12049566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->ysub, yarray));
12055a7e1895SHong Zhang 
12065a7e1895SHong Zhang   /* apply preconditioner on each matrix block */
12079566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
12089566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], mpjac->xsub, mpjac->ysub));
12099566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, mpjac->ysub));
12109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
12119566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
1212ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
1213250cf88bSHong Zhang 
12149566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->xsub));
12159566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->ysub));
12169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xarray));
12179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yarray));
12183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12195a7e1895SHong Zhang }
12205a7e1895SHong Zhang 
1221d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_BJacobi_Multiproc(PC pc, Mat X, Mat Y)
1222d71ae5a4SJacob Faibussowitsch {
12237b6e2003SPierre Jolivet   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
12247b6e2003SPierre Jolivet   KSPConvergedReason reason;
12257b6e2003SPierre Jolivet   Mat                sX, sY;
12267b6e2003SPierre Jolivet   const PetscScalar *x;
12277b6e2003SPierre Jolivet   PetscScalar       *y;
12287b6e2003SPierre Jolivet   PetscInt           m, N, lda, ldb;
12297b6e2003SPierre Jolivet 
12307b6e2003SPierre Jolivet   PetscFunctionBegin;
12317b6e2003SPierre Jolivet   /* apply preconditioner on each matrix block */
12329566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m, NULL));
12339566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, NULL, &N));
12349566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
12359566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(Y, &ldb));
12369566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(X, &x));
12379566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(Y, &y));
12389566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, (PetscScalar *)x, &sX));
12399566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, y, &sY));
12409566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sX, lda));
12419566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sY, ldb));
12429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
12439566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
12449566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, NULL));
12459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
12469566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sY));
12479566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sX));
12489566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(Y, &y));
12499566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(X, &x));
12509566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
1251ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
12523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12537b6e2003SPierre Jolivet }
12547b6e2003SPierre Jolivet 
1255d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC pc)
1256d71ae5a4SJacob Faibussowitsch {
12575a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
12585a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
12595a7e1895SHong Zhang   PetscInt              m, n;
1260ce94432eSBarry Smith   MPI_Comm              comm, subcomm = 0;
12615a7e1895SHong Zhang   const char           *prefix;
1262de0953f6SBarry Smith   PetscBool             wasSetup = PETSC_TRUE;
12633f6dc190SJunchao Zhang   VecType               vectype;
12641f62890fSKarl Rupp 
12655a7e1895SHong Zhang   PetscFunctionBegin;
12669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
126708401ef6SPierre Jolivet   PetscCheck(jac->n_local <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Only a single block in a subcommunicator is supported");
12685a7e1895SHong Zhang   jac->n_local = 1; /* currently only a single block is supported for a subcommunicator */
12695a7e1895SHong Zhang   if (!pc->setupcalled) {
12703821be0aSBarry Smith     PetscInt nestlevel;
12713821be0aSBarry Smith 
1272de0953f6SBarry Smith     wasSetup = PETSC_FALSE;
12734dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mpjac));
12745a7e1895SHong Zhang     jac->data = (void *)mpjac;
12755a7e1895SHong Zhang 
12765a7e1895SHong Zhang     /* initialize datastructure mpjac */
12775a7e1895SHong Zhang     if (!jac->psubcomm) {
12785a7e1895SHong Zhang       /* Create default contiguous subcommunicatiors if user does not provide them */
12799566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &jac->psubcomm));
12809566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(jac->psubcomm, jac->n));
12819566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetType(jac->psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
12825a7e1895SHong Zhang     }
12835a7e1895SHong Zhang     mpjac->psubcomm = jac->psubcomm;
1284306c2d5bSBarry Smith     subcomm         = PetscSubcommChild(mpjac->psubcomm);
12855a7e1895SHong Zhang 
12865a7e1895SHong Zhang     /* Get matrix blocks of pmat */
12879566063dSJacob Faibussowitsch     PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
12885a7e1895SHong Zhang 
12895a7e1895SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
12909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->ksp));
12919566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm, &jac->ksp[0]));
12923821be0aSBarry Smith     PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
12933821be0aSBarry Smith     PetscCall(KSPSetNestLevel(jac->ksp[0], nestlevel + 1));
12949566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(jac->ksp[0], pc->erroriffailure));
12959566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp[0], (PetscObject)pc, 1));
12969566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
12979566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(jac->ksp[0], &mpjac->pc));
12985a7e1895SHong Zhang 
12999566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
13009566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(jac->ksp[0], prefix));
13019566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(jac->ksp[0], "sub_"));
13029566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[0], &prefix));
13039566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mpjac->submats, prefix));
13045a7e1895SHong Zhang 
13055a7e1895SHong Zhang     /* create dummy vectors xsub and ysub */
13069566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mpjac->submats, &m, &n));
13079566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, n, PETSC_DECIDE, NULL, &mpjac->xsub));
13089566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, m, PETSC_DECIDE, NULL, &mpjac->ysub));
13099566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(mpjac->submats, &vectype));
13109566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->xsub, vectype));
13119566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->ysub, vectype));
13125a7e1895SHong Zhang 
1313fd0b8932SBarry Smith     pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiproc;
1314e91c6855SBarry Smith     pc->ops->reset         = PCReset_BJacobi_Multiproc;
13155a7e1895SHong Zhang     pc->ops->destroy       = PCDestroy_BJacobi_Multiproc;
13165a7e1895SHong Zhang     pc->ops->apply         = PCApply_BJacobi_Multiproc;
13177b6e2003SPierre Jolivet     pc->ops->matapply      = PCMatApply_BJacobi_Multiproc;
1318fc08c53fSHong Zhang   } else { /* pc->setupcalled */
1319306c2d5bSBarry Smith     subcomm = PetscSubcommChild(mpjac->psubcomm);
13209e0ae222SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
13215a7e1895SHong Zhang       /* destroy old matrix blocks, then get new matrix blocks */
13229566063dSJacob Faibussowitsch       if (mpjac->submats) PetscCall(MatDestroy(&mpjac->submats));
13239566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
1324fc08c53fSHong Zhang     } else {
13259566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_REUSE_MATRIX, &mpjac->submats));
13265a7e1895SHong Zhang     }
13279566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
13285a7e1895SHong Zhang   }
13295a7e1895SHong Zhang 
133048a46eb9SPierre Jolivet   if (!wasSetup && pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[0]));
13313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13325a7e1895SHong Zhang }
1333