xref: /petsc/src/ksp/pc/impls/bjacobi/bjacobi.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith    Defines a block Jacobi preconditioner.
44b9ad928SBarry Smith */
500e125f8SBarry Smith 
600e125f8SBarry Smith #include <../src/ksp/pc/impls/bjacobi/bjacobi.h> /*I "petscpc.h" I*/
74b9ad928SBarry Smith 
86849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC, Mat, Mat);
96849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC, Mat, Mat);
105a7e1895SHong Zhang static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC);
114b9ad928SBarry Smith 
129371c9d4SSatish Balay static PetscErrorCode PCSetUp_BJacobi(PC pc) {
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));
285a7e1895SHong Zhang     PetscFunctionReturn(0);
295a7e1895SHong Zhang   }
305a7e1895SHong Zhang 
315a7e1895SHong Zhang   /* --------------------------------------------------------------------------
324b9ad928SBarry Smith       Determines the number of blocks assigned to each processor
335a7e1895SHong Zhang   -----------------------------------------------------------------------------*/
344b9ad928SBarry Smith 
354b9ad928SBarry Smith   /*   local block count  given */
364b9ad928SBarry Smith   if (jac->n_local > 0 && jac->n < 0) {
371c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&jac->n_local, &jac->n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
384b9ad928SBarry Smith     if (jac->l_lens) { /* check that user set these correctly */
394b9ad928SBarry Smith       sum = 0;
404b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
4108401ef6SPierre 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");
424b9ad928SBarry Smith         sum += jac->l_lens[i];
434b9ad928SBarry Smith       }
4408401ef6SPierre Jolivet       PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local lens set incorrectly");
454b9ad928SBarry Smith     } else {
469566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
472fa5cd67SKarl 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));
484b9ad928SBarry Smith     }
494b9ad928SBarry Smith   } else if (jac->n > 0 && jac->n_local < 0) { /* global block count given */
504b9ad928SBarry Smith     /* global blocks given: determine which ones are local */
514b9ad928SBarry Smith     if (jac->g_lens) {
524b9ad928SBarry Smith       /* check if the g_lens is has valid entries */
534b9ad928SBarry Smith       for (i = 0; i < jac->n; i++) {
547827d75bSBarry Smith         PetscCheck(jac->g_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Zero block not allowed");
5508401ef6SPierre 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");
564b9ad928SBarry Smith       }
574b9ad928SBarry Smith       if (size == 1) {
584b9ad928SBarry Smith         jac->n_local = jac->n;
599566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
609566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens, jac->n_local));
614b9ad928SBarry Smith         /* check that user set these correctly */
624b9ad928SBarry Smith         sum = 0;
634b9ad928SBarry Smith         for (i = 0; i < jac->n_local; i++) sum += jac->l_lens[i];
6408401ef6SPierre Jolivet         PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Global lens set incorrectly");
654b9ad928SBarry Smith       } else {
669566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->pmat, &start, &end));
674b9ad928SBarry Smith         /* loop over blocks determing first one owned by me */
684b9ad928SBarry Smith         sum = 0;
694b9ad928SBarry Smith         for (i = 0; i < jac->n + 1; i++) {
709371c9d4SSatish Balay           if (sum == start) {
719371c9d4SSatish Balay             i_start = i;
729371c9d4SSatish Balay             goto start_1;
739371c9d4SSatish Balay           }
744b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
754b9ad928SBarry Smith         }
76e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
774b9ad928SBarry Smith       start_1:
784b9ad928SBarry Smith         for (i = i_start; i < jac->n + 1; i++) {
799371c9d4SSatish Balay           if (sum == end) {
809371c9d4SSatish Balay             i_end = i;
819371c9d4SSatish Balay             goto end_1;
829371c9d4SSatish Balay           }
834b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
844b9ad928SBarry Smith         }
85e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
864b9ad928SBarry Smith       end_1:
874b9ad928SBarry Smith         jac->n_local = i_end - i_start;
889566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
899566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens + i_start, jac->n_local));
904b9ad928SBarry Smith       }
914b9ad928SBarry Smith     } else { /* no global blocks given, determine then using default layout */
924b9ad928SBarry Smith       jac->n_local = jac->n / size + ((jac->n % size) > rank);
939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
944b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
954b9ad928SBarry Smith         jac->l_lens[i] = ((M / bs) / jac->n_local + (((M / bs) % jac->n_local) > i)) * bs;
967827d75bSBarry Smith         PetscCheck(jac->l_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Too many blocks given");
974b9ad928SBarry Smith       }
984b9ad928SBarry Smith     }
994b9ad928SBarry Smith   } else if (jac->n < 0 && jac->n_local < 0) { /* no blocks given */
1004b9ad928SBarry Smith     jac->n       = size;
1014b9ad928SBarry Smith     jac->n_local = 1;
1029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->l_lens));
1034b9ad928SBarry Smith     jac->l_lens[0] = M;
1047271b979SBarry Smith   } else { /* jac->n > 0 && jac->n_local > 0 */
1057271b979SBarry Smith     if (!jac->l_lens) {
1069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
1072fa5cd67SKarl 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));
1087271b979SBarry Smith     }
1094b9ad928SBarry Smith   }
11008401ef6SPierre Jolivet   PetscCheck(jac->n_local >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of blocks is less than number of processors");
1114b9ad928SBarry Smith 
1125a7e1895SHong Zhang   /* -------------------------
1135a7e1895SHong Zhang       Determines mat and pmat
1145a7e1895SHong Zhang   ---------------------------*/
1159566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(pc->mat, MATOP_GET_DIAGONAL_BLOCK, &hasop));
116976e8c5aSLisandro Dalcin   if (!hasop && size == 1) {
1174b9ad928SBarry Smith     mat  = pc->mat;
1184b9ad928SBarry Smith     pmat = pc->pmat;
1194b9ad928SBarry Smith   } else {
12049517cdeSBarry Smith     if (pc->useAmat) {
12149517cdeSBarry Smith       /* use block from Amat matrix, not Pmat for local MatMult() */
1229566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->mat, &mat));
1234b9ad928SBarry Smith     }
12449517cdeSBarry Smith     if (pc->pmat != pc->mat || !pc->useAmat) {
1259566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->pmat, &pmat));
1262fa5cd67SKarl Rupp     } else pmat = mat;
1274b9ad928SBarry Smith   }
1284b9ad928SBarry Smith 
1294b9ad928SBarry Smith   /* ------
1304b9ad928SBarry Smith      Setup code depends on the number of blocks
1314b9ad928SBarry Smith   */
132cc1d6079SHong Zhang   if (jac->n_local == 1) {
1339566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Singleblock(pc, mat, pmat));
1344b9ad928SBarry Smith   } else {
1359566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiblock(pc, mat, pmat));
1364b9ad928SBarry Smith   }
1374b9ad928SBarry Smith   PetscFunctionReturn(0);
1384b9ad928SBarry Smith }
1394b9ad928SBarry Smith 
1404b9ad928SBarry Smith /* Default destroy, if it has never been setup */
1419371c9d4SSatish Balay static PetscErrorCode PCDestroy_BJacobi(PC pc) {
1424b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
1434b9ad928SBarry Smith 
1444b9ad928SBarry Smith   PetscFunctionBegin;
1459566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
1469566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
1472e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetSubKSP_C", NULL));
1482e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetTotalBlocks_C", NULL));
1492e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetTotalBlocks_C", NULL));
1502e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetLocalBlocks_C", NULL));
1512e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetLocalBlocks_C", NULL));
1529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1534b9ad928SBarry Smith   PetscFunctionReturn(0);
1544b9ad928SBarry Smith }
1554b9ad928SBarry Smith 
1569371c9d4SSatish Balay static PetscErrorCode PCSetFromOptions_BJacobi(PC pc, PetscOptionItems *PetscOptionsObject) {
1574b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
158248bfaf0SJed Brown   PetscInt    blocks, i;
159ace3abfcSBarry Smith   PetscBool   flg;
1604b9ad928SBarry Smith 
1614b9ad928SBarry Smith   PetscFunctionBegin;
162d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Block Jacobi options");
1639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_blocks", "Total number of blocks", "PCBJacobiSetTotalBlocks", jac->n, &blocks, &flg));
1649566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetTotalBlocks(pc, blocks, NULL));
1659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_local_blocks", "Local number of blocks", "PCBJacobiSetLocalBlocks", jac->n_local, &blocks, &flg));
1669566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetLocalBlocks(pc, blocks, NULL));
167248bfaf0SJed Brown   if (jac->ksp) {
168248bfaf0SJed Brown     /* The sub-KSP has already been set up (e.g., PCSetUp_BJacobi_Singleblock), but KSPSetFromOptions was not called
169248bfaf0SJed Brown      * unless we had already been called. */
170*48a46eb9SPierre Jolivet     for (i = 0; i < jac->n_local; i++) PetscCall(KSPSetFromOptions(jac->ksp[i]));
171248bfaf0SJed Brown   }
172d0609cedSBarry Smith   PetscOptionsHeadEnd();
1734b9ad928SBarry Smith   PetscFunctionReturn(0);
1744b9ad928SBarry Smith }
1754b9ad928SBarry Smith 
1769804daf3SBarry Smith #include <petscdraw.h>
1779371c9d4SSatish Balay static PetscErrorCode PCView_BJacobi(PC pc, PetscViewer viewer) {
1784b9ad928SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
179cbe18068SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
18069a612a9SBarry Smith   PetscMPIInt           rank;
18169a612a9SBarry Smith   PetscInt              i;
182d9884438SBarry Smith   PetscBool             iascii, isstring, isdraw;
1834b9ad928SBarry Smith   PetscViewer           sviewer;
184020d6619SPierre Jolivet   PetscViewerFormat     format;
185020d6619SPierre Jolivet   const char           *prefix;
1864b9ad928SBarry Smith 
1874b9ad928SBarry Smith   PetscFunctionBegin;
1889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1909566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19132077d6dSBarry Smith   if (iascii) {
192*48a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat local matrix, number of blocks = %" PetscInt_FMT "\n", jac->n));
19363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  number of blocks = %" PetscInt_FMT "\n", jac->n));
1949566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
1959566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
196020d6619SPierre Jolivet     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
1979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for first block is in the following KSP and PC objects on rank 0:\n"));
1989566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
1999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Use -%sksp_view ::ascii_info_detail to display information for all blocks\n", prefix ? prefix : ""));
200933995ecSHong Zhang       if (jac->ksp && !jac->psubcomm) {
2019566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
202dd400576SPatrick Sanan         if (rank == 0) {
2039566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2049566063dSJacob Faibussowitsch           PetscCall(KSPView(jac->ksp[0], sviewer));
2059566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
2064b9ad928SBarry Smith         }
2079566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2089566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2099566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
210e4de9e1dSBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2119566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
212e4fa1014SBarry Smith       } else if (mpjac && jac->ksp && mpjac->psubcomm) {
2139566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
214e4fa1014SBarry Smith         if (!mpjac->psubcomm->color) {
2159566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2169566063dSJacob Faibussowitsch           PetscCall(KSPView(*(jac->ksp), sviewer));
2179566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
218cbe18068SHong Zhang         }
2199566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2209566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
2219566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
2229530cbd7SBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2239566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2244b9ad928SBarry Smith       } else {
2259566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
226e4de9e1dSBarry Smith       }
227e4de9e1dSBarry Smith     } else {
2284814766eSBarry Smith       PetscInt n_global;
2291c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&jac->n_local, &n_global, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
2309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for each block is in the following KSP and PC objects:\n"));
2329371c9d4SSatish Balay       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] number of local blocks = %" PetscInt_FMT ", first local block number = %" PetscInt_FMT "\n", rank, jac->n_local, jac->first_local));
2339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2349566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
235dd2fa690SBarry Smith       for (i = 0; i < jac->n_local; i++) {
23663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] local block number %" PetscInt_FMT "\n", rank, i));
2379566063dSJacob Faibussowitsch         PetscCall(KSPView(jac->ksp[i], sviewer));
2389566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "- - - - - - - - - - - - - - - - - -\n"));
2394b9ad928SBarry Smith       }
2409566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
2429566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
2439566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2444b9ad928SBarry Smith     }
2454b9ad928SBarry Smith   } else if (isstring) {
24663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer, " blks=%" PetscInt_FMT, jac->n));
2479566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2489566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], sviewer));
2499566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
250d9884438SBarry Smith   } else if (isdraw) {
251d9884438SBarry Smith     PetscDraw draw;
252d9884438SBarry Smith     char      str[25];
253d9884438SBarry Smith     PetscReal x, y, bottom, h;
254d9884438SBarry Smith 
2559566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2569566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
25763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str, 25, "Number blocks %" PetscInt_FMT, jac->n));
2589566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
259d9884438SBarry Smith     bottom = y - h;
2609566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
261d9884438SBarry Smith     /* warning the communicator on viewer is different then on ksp in parallel */
2629566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], viewer));
2639566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2644b9ad928SBarry Smith   }
2654b9ad928SBarry Smith   PetscFunctionReturn(0);
2664b9ad928SBarry Smith }
2674b9ad928SBarry Smith 
2684b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
2694b9ad928SBarry Smith 
2709371c9d4SSatish Balay static PetscErrorCode PCBJacobiGetSubKSP_BJacobi(PC pc, PetscInt *n_local, PetscInt *first_local, KSP **ksp) {
271feb237baSPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2724b9ad928SBarry Smith 
2734b9ad928SBarry Smith   PetscFunctionBegin;
27428b400f6SJacob Faibussowitsch   PetscCheck(pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() first");
2754b9ad928SBarry Smith 
2764b9ad928SBarry Smith   if (n_local) *n_local = jac->n_local;
2774b9ad928SBarry Smith   if (first_local) *first_local = jac->first_local;
278020d6619SPierre Jolivet   if (ksp) *ksp = jac->ksp;
2794b9ad928SBarry Smith   PetscFunctionReturn(0);
2804b9ad928SBarry Smith }
2814b9ad928SBarry Smith 
2829371c9d4SSatish Balay static PetscErrorCode PCBJacobiSetTotalBlocks_BJacobi(PC pc, PetscInt blocks, PetscInt *lens) {
2834b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2844b9ad928SBarry Smith 
2854b9ad928SBarry Smith   PetscFunctionBegin;
2862472a847SBarry Smith   PetscCheck(pc->setupcalled <= 0 || jac->n == blocks, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Cannot alter number of blocks after PCSetUp()/KSPSetUp() has been called");
2874b9ad928SBarry Smith   jac->n = blocks;
2880a545947SLisandro Dalcin   if (!lens) jac->g_lens = NULL;
2892fa5cd67SKarl Rupp   else {
2909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks, &jac->g_lens));
2919566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject)pc, blocks * sizeof(PetscInt)));
2929566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->g_lens, lens, blocks));
2934b9ad928SBarry Smith   }
2944b9ad928SBarry Smith   PetscFunctionReturn(0);
2954b9ad928SBarry Smith }
2964b9ad928SBarry Smith 
2979371c9d4SSatish Balay static PetscErrorCode PCBJacobiGetTotalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[]) {
2984b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2994b9ad928SBarry Smith 
3004b9ad928SBarry Smith   PetscFunctionBegin;
3014b9ad928SBarry Smith   *blocks = jac->n;
3024b9ad928SBarry Smith   if (lens) *lens = jac->g_lens;
3034b9ad928SBarry Smith   PetscFunctionReturn(0);
3044b9ad928SBarry Smith }
3054b9ad928SBarry Smith 
3069371c9d4SSatish Balay static PetscErrorCode PCBJacobiSetLocalBlocks_BJacobi(PC pc, PetscInt blocks, const PetscInt lens[]) {
3074b9ad928SBarry Smith   PC_BJacobi *jac;
3084b9ad928SBarry Smith 
3094b9ad928SBarry Smith   PetscFunctionBegin;
3104b9ad928SBarry Smith   jac = (PC_BJacobi *)pc->data;
3114b9ad928SBarry Smith 
3124b9ad928SBarry Smith   jac->n_local = blocks;
3130a545947SLisandro Dalcin   if (!lens) jac->l_lens = NULL;
3142fa5cd67SKarl Rupp   else {
3159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks, &jac->l_lens));
3169566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject)pc, blocks * sizeof(PetscInt)));
3179566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->l_lens, lens, blocks));
3184b9ad928SBarry Smith   }
3194b9ad928SBarry Smith   PetscFunctionReturn(0);
3204b9ad928SBarry Smith }
3214b9ad928SBarry Smith 
3229371c9d4SSatish Balay static PetscErrorCode PCBJacobiGetLocalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[]) {
3234b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
3244b9ad928SBarry Smith 
3254b9ad928SBarry Smith   PetscFunctionBegin;
3264b9ad928SBarry Smith   *blocks = jac->n_local;
3274b9ad928SBarry Smith   if (lens) *lens = jac->l_lens;
3284b9ad928SBarry Smith   PetscFunctionReturn(0);
3294b9ad928SBarry Smith }
3304b9ad928SBarry Smith 
3314b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
3324b9ad928SBarry Smith 
3334b9ad928SBarry Smith /*@C
3344b9ad928SBarry Smith    PCBJacobiGetSubKSP - Gets the local KSP contexts for all blocks on
3354b9ad928SBarry Smith    this processor.
3364b9ad928SBarry Smith 
3376da92b7fSHong Zhang    Not Collective
3384b9ad928SBarry Smith 
3394b9ad928SBarry Smith    Input Parameter:
3404b9ad928SBarry Smith .  pc - the preconditioner context
3414b9ad928SBarry Smith 
3424b9ad928SBarry Smith    Output Parameters:
3430298fd71SBarry Smith +  n_local - the number of blocks on this processor, or NULL
3440298fd71SBarry Smith .  first_local - the global number of the first block on this processor, or NULL
3454b9ad928SBarry Smith -  ksp - the array of KSP contexts
3464b9ad928SBarry Smith 
3474b9ad928SBarry Smith    Notes:
3484b9ad928SBarry Smith    After PCBJacobiGetSubKSP() the array of KSP contexts is not to be freed.
3494b9ad928SBarry Smith 
3504b9ad928SBarry Smith    Currently for some matrix implementations only 1 block per processor
3514b9ad928SBarry Smith    is supported.
3524b9ad928SBarry Smith 
3534b9ad928SBarry Smith    You must call KSPSetUp() or PCSetUp() before calling PCBJacobiGetSubKSP().
3544b9ad928SBarry Smith 
355196cc216SBarry Smith    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
3562bf68e3eSBarry Smith       You can call PCBJacobiGetSubKSP(pc,nlocal,firstlocal,PETSC_NULL_KSP,ierr) to determine how large the
357196cc216SBarry Smith       KSP array must be.
358196cc216SBarry Smith 
3594b9ad928SBarry Smith    Level: advanced
3604b9ad928SBarry Smith 
361db781477SPatrick Sanan .seealso: `PCASMGetSubKSP()`
3624b9ad928SBarry Smith @*/
3639371c9d4SSatish Balay PetscErrorCode PCBJacobiGetSubKSP(PC pc, PetscInt *n_local, PetscInt *first_local, KSP *ksp[]) {
3644b9ad928SBarry Smith   PetscFunctionBegin;
3650700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
366cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetSubKSP_C", (PC, PetscInt *, PetscInt *, KSP **), (pc, n_local, first_local, ksp));
3674b9ad928SBarry Smith   PetscFunctionReturn(0);
3684b9ad928SBarry Smith }
3694b9ad928SBarry Smith 
3704b9ad928SBarry Smith /*@
3714b9ad928SBarry Smith    PCBJacobiSetTotalBlocks - Sets the global number of blocks for the block
3724b9ad928SBarry Smith    Jacobi preconditioner.
3734b9ad928SBarry Smith 
3744b9ad928SBarry Smith    Collective on PC
3754b9ad928SBarry Smith 
3764b9ad928SBarry Smith    Input Parameters:
3774b9ad928SBarry Smith +  pc - the preconditioner context
3784b9ad928SBarry Smith .  blocks - the number of blocks
3794b9ad928SBarry Smith -  lens - [optional] integer array containing the size of each block
3804b9ad928SBarry Smith 
3814b9ad928SBarry Smith    Options Database Key:
3824b9ad928SBarry Smith .  -pc_bjacobi_blocks <blocks> - Sets the number of global blocks
3834b9ad928SBarry Smith 
3844b9ad928SBarry Smith    Notes:
3854b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
3864b9ad928SBarry Smith    All processors sharing the PC must call this routine with the same data.
3874b9ad928SBarry Smith 
3884b9ad928SBarry Smith    Level: intermediate
3894b9ad928SBarry Smith 
390db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiSetLocalBlocks()`
3914b9ad928SBarry Smith @*/
3929371c9d4SSatish Balay PetscErrorCode PCBJacobiSetTotalBlocks(PC pc, PetscInt blocks, const PetscInt lens[]) {
3934b9ad928SBarry Smith   PetscFunctionBegin;
3940700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
39508401ef6SPierre Jolivet   PetscCheck(blocks > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Must have positive blocks");
396cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetTotalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
3974b9ad928SBarry Smith   PetscFunctionReturn(0);
3984b9ad928SBarry Smith }
3994b9ad928SBarry Smith 
4004b9ad928SBarry Smith /*@C
4014b9ad928SBarry Smith    PCBJacobiGetTotalBlocks - Gets the global number of blocks for the block
4024b9ad928SBarry Smith    Jacobi preconditioner.
4034b9ad928SBarry Smith 
404ad4df100SBarry Smith    Not Collective
4054b9ad928SBarry Smith 
4064b9ad928SBarry Smith    Input Parameter:
4074b9ad928SBarry Smith .  pc - the preconditioner context
4084b9ad928SBarry Smith 
4094b9ad928SBarry Smith    Output parameters:
4104b9ad928SBarry Smith +  blocks - the number of blocks
4114b9ad928SBarry Smith -  lens - integer array containing the size of each block
4124b9ad928SBarry Smith 
4134b9ad928SBarry Smith    Level: intermediate
4144b9ad928SBarry Smith 
415db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiGetLocalBlocks()`
4164b9ad928SBarry Smith @*/
4179371c9d4SSatish Balay PetscErrorCode PCBJacobiGetTotalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[]) {
4184b9ad928SBarry Smith   PetscFunctionBegin;
4190700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4204482741eSBarry Smith   PetscValidIntPointer(blocks, 2);
421cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetTotalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4224b9ad928SBarry Smith   PetscFunctionReturn(0);
4234b9ad928SBarry Smith }
4244b9ad928SBarry Smith 
4254b9ad928SBarry Smith /*@
4264b9ad928SBarry Smith    PCBJacobiSetLocalBlocks - Sets the local number of blocks for the block
4274b9ad928SBarry Smith    Jacobi preconditioner.
4284b9ad928SBarry Smith 
4294b9ad928SBarry Smith    Not Collective
4304b9ad928SBarry Smith 
4314b9ad928SBarry Smith    Input Parameters:
4324b9ad928SBarry Smith +  pc - the preconditioner context
4334b9ad928SBarry Smith .  blocks - the number of blocks
4344b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4354b9ad928SBarry Smith 
436342c94f9SMatthew G. Knepley    Options Database Key:
437342c94f9SMatthew G. Knepley .  -pc_bjacobi_local_blocks <blocks> - Sets the number of local blocks
438342c94f9SMatthew G. Knepley 
4394b9ad928SBarry Smith    Note:
4404b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4414b9ad928SBarry Smith 
4424b9ad928SBarry Smith    Level: intermediate
4434b9ad928SBarry Smith 
444db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiSetTotalBlocks()`
4454b9ad928SBarry Smith @*/
4469371c9d4SSatish Balay PetscErrorCode PCBJacobiSetLocalBlocks(PC pc, PetscInt blocks, const PetscInt lens[]) {
4474b9ad928SBarry Smith   PetscFunctionBegin;
4480700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
44908401ef6SPierre Jolivet   PetscCheck(blocks >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have nonegative blocks");
450cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetLocalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
4514b9ad928SBarry Smith   PetscFunctionReturn(0);
4524b9ad928SBarry Smith }
4534b9ad928SBarry Smith 
4544b9ad928SBarry Smith /*@C
4554b9ad928SBarry Smith    PCBJacobiGetLocalBlocks - Gets the local number of blocks for the block
4564b9ad928SBarry Smith    Jacobi preconditioner.
4574b9ad928SBarry Smith 
4584b9ad928SBarry Smith    Not Collective
4594b9ad928SBarry Smith 
4604b9ad928SBarry Smith    Input Parameters:
4614b9ad928SBarry Smith +  pc - the preconditioner context
4624b9ad928SBarry Smith .  blocks - the number of blocks
4634b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4644b9ad928SBarry Smith 
4654b9ad928SBarry Smith    Note:
4664b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4674b9ad928SBarry Smith 
4684b9ad928SBarry Smith    Level: intermediate
4694b9ad928SBarry Smith 
470db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiGetTotalBlocks()`
4714b9ad928SBarry Smith @*/
4729371c9d4SSatish Balay PetscErrorCode PCBJacobiGetLocalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[]) {
4734b9ad928SBarry Smith   PetscFunctionBegin;
4740700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4754482741eSBarry Smith   PetscValidIntPointer(blocks, 2);
476cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetLocalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4774b9ad928SBarry Smith   PetscFunctionReturn(0);
4784b9ad928SBarry Smith }
4794b9ad928SBarry Smith 
4804b9ad928SBarry Smith /* -----------------------------------------------------------------------------------*/
4814b9ad928SBarry Smith 
4824b9ad928SBarry Smith /*MC
4834b9ad928SBarry Smith    PCBJACOBI - Use block Jacobi preconditioning, each block is (approximately) solved with
4844b9ad928SBarry Smith            its own KSP object.
4854b9ad928SBarry Smith 
4864b9ad928SBarry Smith    Options Database Keys:
487011ea8aeSBarry Smith +  -pc_use_amat - use Amat to apply block of operator in inner Krylov method
488011ea8aeSBarry Smith -  -pc_bjacobi_blocks <n> - use n total blocks
4894b9ad928SBarry Smith 
49095452b02SPatrick Sanan    Notes:
491468ae2e8SBarry Smith     See PCJACOBI for diagonal Jacobi, PCVPBJACOBI for variable point block, and PCPBJACOBI for fixed size point block
492468ae2e8SBarry Smith 
49395452b02SPatrick 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.
4944b9ad928SBarry Smith 
4954b9ad928SBarry Smith      To set options on the solvers for each block append -sub_ to all the KSP, KSP, and PC
496d7ee0231SBarry Smith         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
4974b9ad928SBarry Smith 
498a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCBJacobiGetSubKSP()
4994b9ad928SBarry Smith          and set the options directly on the resulting KSP object (you can access its PC
5004b9ad928SBarry Smith          KSPGetPC())
5014b9ad928SBarry Smith 
502e9e886b6SKarl Rupp      For GPU-based vectors (CUDA, ViennaCL) it is recommended to use exactly one block per MPI process for best
5032210c163SDominic Meiser          performance.  Different block partitioning may lead to additional data transfers
5042210c163SDominic Meiser          between host and GPU that lead to degraded performance.
5052210c163SDominic Meiser 
506011ea8aeSBarry Smith      The options prefix for each block is sub_, for example -sub_pc_type lu.
507011ea8aeSBarry Smith 
508011ea8aeSBarry Smith      When multiple processes share a single block, each block encompasses exactly all the unknowns owned its set of processes.
509011ea8aeSBarry Smith 
51090dfcc32SBarry Smith      See PCJACOBI for point Jacobi preconditioning, PCVPBJACOBI for variable size point block Jacobi and PCPBJACOBI for large blocks
51190dfcc32SBarry Smith 
5124b9ad928SBarry Smith    Level: beginner
5134b9ad928SBarry Smith 
514db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
515db781477SPatrick Sanan           `PCASM`, `PCSetUseAmat()`, `PCGetUseAmat()`, `PCBJacobiGetSubKSP()`, `PCBJacobiSetTotalBlocks()`,
516db781477SPatrick Sanan           `PCBJacobiSetLocalBlocks()`, `PCSetModifySubMatrices()`, `PCJACOBI`, `PCVPBJACOBI`, `PCPBJACOBI`
5174b9ad928SBarry Smith M*/
5184b9ad928SBarry Smith 
5199371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_BJacobi(PC pc) {
52069a612a9SBarry Smith   PetscMPIInt rank;
5214b9ad928SBarry Smith   PC_BJacobi *jac;
5224b9ad928SBarry Smith 
5234b9ad928SBarry Smith   PetscFunctionBegin;
5249566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &jac));
5259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
5262fa5cd67SKarl Rupp 
5270a545947SLisandro Dalcin   pc->ops->apply           = NULL;
5287b6e2003SPierre Jolivet   pc->ops->matapply        = NULL;
5290a545947SLisandro Dalcin   pc->ops->applytranspose  = NULL;
5304b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_BJacobi;
5314b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_BJacobi;
5324b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_BJacobi;
5334b9ad928SBarry Smith   pc->ops->view            = PCView_BJacobi;
5340a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5354b9ad928SBarry Smith 
5364b9ad928SBarry Smith   pc->data         = (void *)jac;
5374b9ad928SBarry Smith   jac->n           = -1;
5384b9ad928SBarry Smith   jac->n_local     = -1;
5394b9ad928SBarry Smith   jac->first_local = rank;
5400a545947SLisandro Dalcin   jac->ksp         = NULL;
5410a545947SLisandro Dalcin   jac->g_lens      = NULL;
5420a545947SLisandro Dalcin   jac->l_lens      = NULL;
5430a545947SLisandro Dalcin   jac->psubcomm    = NULL;
5444b9ad928SBarry Smith 
5459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetSubKSP_C", PCBJacobiGetSubKSP_BJacobi));
5469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetTotalBlocks_C", PCBJacobiSetTotalBlocks_BJacobi));
5479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetTotalBlocks_C", PCBJacobiGetTotalBlocks_BJacobi));
5489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetLocalBlocks_C", PCBJacobiSetLocalBlocks_BJacobi));
5499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetLocalBlocks_C", PCBJacobiGetLocalBlocks_BJacobi));
5504b9ad928SBarry Smith   PetscFunctionReturn(0);
5514b9ad928SBarry Smith }
5524b9ad928SBarry Smith 
5534b9ad928SBarry Smith /* --------------------------------------------------------------------------------------------*/
5544b9ad928SBarry Smith /*
5554b9ad928SBarry Smith         These are for a single block per processor; works for AIJ, BAIJ; Seq and MPI
5564b9ad928SBarry Smith */
5579371c9d4SSatish Balay static PetscErrorCode PCReset_BJacobi_Singleblock(PC pc) {
5584b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
5594b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
5604b9ad928SBarry Smith 
5614b9ad928SBarry Smith   PetscFunctionBegin;
5629566063dSJacob Faibussowitsch   PetscCall(KSPReset(jac->ksp[0]));
5639566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->x));
5649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->y));
565e91c6855SBarry Smith   PetscFunctionReturn(0);
566e91c6855SBarry Smith }
567e91c6855SBarry Smith 
5689371c9d4SSatish Balay static PetscErrorCode PCDestroy_BJacobi_Singleblock(PC pc) {
569e91c6855SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
570e91c6855SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
571e91c6855SBarry Smith 
572e91c6855SBarry Smith   PetscFunctionBegin;
5739566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Singleblock(pc));
5749566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
5759566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
5769566063dSJacob Faibussowitsch   PetscCall(PetscFree(bjac));
5772e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
5784b9ad928SBarry Smith   PetscFunctionReturn(0);
5794b9ad928SBarry Smith }
5804b9ad928SBarry Smith 
5819371c9d4SSatish Balay static PetscErrorCode PCSetUpOnBlocks_BJacobi_Singleblock(PC pc) {
5824b9ad928SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
5832295b7c8SHong Zhang   KSP                subksp = jac->ksp[0];
584539c167fSBarry Smith   KSPConvergedReason reason;
5854b9ad928SBarry Smith 
5864b9ad928SBarry Smith   PetscFunctionBegin;
5879566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
5889566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
5899371c9d4SSatish Balay   if (reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
5904b9ad928SBarry Smith   PetscFunctionReturn(0);
5914b9ad928SBarry Smith }
5924b9ad928SBarry Smith 
5939371c9d4SSatish Balay static PetscErrorCode PCApply_BJacobi_Singleblock(PC pc, Vec x, Vec y) {
5944b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
5954b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
5966e111a19SKarl Rupp 
5974b9ad928SBarry Smith   PetscFunctionBegin;
5989566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVectorRead(x, bjac->x));
5999566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVector(y, bjac->y));
600bba28a21SBarry Smith   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
601910cf402Sprj-      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
602910cf402Sprj-      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6039566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
6049566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], bjac->x, bjac->y));
6059566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
6069566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVectorRead(x, bjac->x));
6079566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVector(y, bjac->y));
6084b9ad928SBarry Smith   PetscFunctionReturn(0);
6094b9ad928SBarry Smith }
6104b9ad928SBarry Smith 
6119371c9d4SSatish Balay static PetscErrorCode PCMatApply_BJacobi_Singleblock(PC pc, Mat X, Mat Y) {
6127b6e2003SPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
6137b6e2003SPierre Jolivet   Mat         sX, sY;
6147b6e2003SPierre Jolivet 
6157b6e2003SPierre Jolivet   PetscFunctionBegin;
6167b6e2003SPierre Jolivet   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
6177b6e2003SPierre Jolivet      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
6187b6e2003SPierre Jolivet      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6199566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
6209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(X, &sX));
6219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Y, &sY));
6229566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
6237b6e2003SPierre Jolivet   PetscFunctionReturn(0);
6247b6e2003SPierre Jolivet }
6257b6e2003SPierre Jolivet 
6269371c9d4SSatish Balay static PetscErrorCode PCApplySymmetricLeft_BJacobi_Singleblock(PC pc, Vec x, Vec y) {
6274b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6284b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
629d9ca1df4SBarry Smith   PetscScalar            *y_array;
630d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6314b9ad928SBarry Smith   PC                      subpc;
6324b9ad928SBarry Smith 
6334b9ad928SBarry Smith   PetscFunctionBegin;
6344b9ad928SBarry Smith   /*
6354b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6364b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6374b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6384b9ad928SBarry Smith     for the sequential solve.
6394b9ad928SBarry Smith   */
6409566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6419566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6429566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6439566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6444b9ad928SBarry Smith   /* apply the symmetric left portion of the inner PC operator */
6454b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6469566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6479566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricLeft(subpc, bjac->x, bjac->y));
6489566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
6499566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
6509566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
6519566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
6524b9ad928SBarry Smith   PetscFunctionReturn(0);
6534b9ad928SBarry Smith }
6544b9ad928SBarry Smith 
6559371c9d4SSatish Balay static PetscErrorCode PCApplySymmetricRight_BJacobi_Singleblock(PC pc, Vec x, Vec y) {
6564b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6574b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
658d9ca1df4SBarry Smith   PetscScalar            *y_array;
659d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6604b9ad928SBarry Smith   PC                      subpc;
6614b9ad928SBarry Smith 
6624b9ad928SBarry Smith   PetscFunctionBegin;
6634b9ad928SBarry Smith   /*
6644b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6654b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6664b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6674b9ad928SBarry Smith     for the sequential solve.
6684b9ad928SBarry Smith   */
6699566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6709566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6719566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6729566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6734b9ad928SBarry Smith 
6744b9ad928SBarry Smith   /* apply the symmetric right portion of the inner PC operator */
6754b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6764b9ad928SBarry Smith 
6779566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6789566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricRight(subpc, bjac->x, bjac->y));
6794b9ad928SBarry Smith 
6809566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
6819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
6824b9ad928SBarry Smith   PetscFunctionReturn(0);
6834b9ad928SBarry Smith }
6844b9ad928SBarry Smith 
6859371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_BJacobi_Singleblock(PC pc, Vec x, Vec y) {
6864b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6874b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
688d9ca1df4SBarry Smith   PetscScalar            *y_array;
689d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6904b9ad928SBarry Smith 
6914b9ad928SBarry Smith   PetscFunctionBegin;
6924b9ad928SBarry Smith   /*
6934b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6944b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6954b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6964b9ad928SBarry Smith     for the sequential solve.
6974b9ad928SBarry Smith   */
6989566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6999566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
7009566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
7019566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
7029566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(jac->ksp[0], bjac->x, bjac->y));
7039566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
7049566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
7059566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
7069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
7079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
7084b9ad928SBarry Smith   PetscFunctionReturn(0);
7094b9ad928SBarry Smith }
7104b9ad928SBarry Smith 
7119371c9d4SSatish Balay static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC pc, Mat mat, Mat pmat) {
7124b9ad928SBarry Smith   PC_BJacobi             *jac = (PC_BJacobi *)pc->data;
71369a612a9SBarry Smith   PetscInt                m;
7144b9ad928SBarry Smith   KSP                     ksp;
7154b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac;
716de0953f6SBarry Smith   PetscBool               wasSetup = PETSC_TRUE;
7173f6dc190SJunchao Zhang   VecType                 vectype;
718ea41da7aSPierre Jolivet   const char             *prefix;
7194b9ad928SBarry Smith 
7204b9ad928SBarry Smith   PetscFunctionBegin;
7214b9ad928SBarry Smith   if (!pc->setupcalled) {
722c2efdce3SBarry Smith     if (!jac->ksp) {
723302a9ddcSMatthew Knepley       wasSetup = PETSC_FALSE;
7242fa5cd67SKarl Rupp 
7259566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
7269566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
7279566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
7289566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ksp));
7299566063dSJacob Faibussowitsch       PetscCall(KSPSetType(ksp, KSPPREONLY));
7309566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
7319566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp, prefix));
7329566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
7334b9ad928SBarry Smith 
734e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Singleblock;
7354b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Singleblock;
7364b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Singleblock;
7377b6e2003SPierre Jolivet       pc->ops->matapply            = PCMatApply_BJacobi_Singleblock;
7384b9ad928SBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Singleblock;
7394b9ad928SBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Singleblock;
7404b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Singleblock;
7414b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Singleblock;
7424b9ad928SBarry Smith 
7439566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, &jac->ksp));
7444b9ad928SBarry Smith       jac->ksp[0] = ksp;
745c2efdce3SBarry Smith 
7469566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc, &bjac));
7474b9ad928SBarry Smith       jac->data = (void *)bjac;
7484b9ad928SBarry Smith     } else {
749c2efdce3SBarry Smith       ksp  = jac->ksp[0];
750c2efdce3SBarry Smith       bjac = (PC_BJacobi_Singleblock *)jac->data;
751c2efdce3SBarry Smith     }
752c2efdce3SBarry Smith 
753c2efdce3SBarry Smith     /*
754c2efdce3SBarry Smith       The reason we need to generate these vectors is to serve
755c2efdce3SBarry Smith       as the right-hand side and solution vector for the solve on the
756c2efdce3SBarry Smith       block. We do not need to allocate space for the vectors since
757c2efdce3SBarry Smith       that is provided via VecPlaceArray() just before the call to
758c2efdce3SBarry Smith       KSPSolve() on the block.
759c2efdce3SBarry Smith     */
7609566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pmat, &m, &m));
7619566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->x));
7629566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->y));
7639566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
7649566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->x, vectype));
7659566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->y, vectype));
7669566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)bjac->x));
7679566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)bjac->y));
768c2efdce3SBarry Smith   } else {
7694b9ad928SBarry Smith     ksp  = jac->ksp[0];
7704b9ad928SBarry Smith     bjac = (PC_BJacobi_Singleblock *)jac->data;
7714b9ad928SBarry Smith   }
7729566063dSJacob Faibussowitsch   PetscCall(KSPGetOptionsPrefix(ksp, &prefix));
77349517cdeSBarry Smith   if (pc->useAmat) {
7749566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, mat, pmat));
7759566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mat, prefix));
7764b9ad928SBarry Smith   } else {
7779566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, pmat, pmat));
7784b9ad928SBarry Smith   }
7799566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(pmat, prefix));
78090f1c854SHong Zhang   if (!wasSetup && pc->setfromoptionscalled) {
781248bfaf0SJed Brown     /* If PCSetFromOptions_BJacobi is called later, KSPSetFromOptions will be called at that time. */
7829566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ksp));
783302a9ddcSMatthew Knepley   }
7844b9ad928SBarry Smith   PetscFunctionReturn(0);
7854b9ad928SBarry Smith }
7864b9ad928SBarry Smith 
7874b9ad928SBarry Smith /* ---------------------------------------------------------------------------------------------*/
7889371c9d4SSatish Balay static PetscErrorCode PCReset_BJacobi_Multiblock(PC pc) {
7894b9ad928SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
7904b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
79169a612a9SBarry Smith   PetscInt               i;
7924b9ad928SBarry Smith 
7934b9ad928SBarry Smith   PetscFunctionBegin;
794e91c6855SBarry Smith   if (bjac && bjac->pmat) {
7959566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->n_local, &bjac->pmat));
796*48a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(MatDestroyMatrices(jac->n_local, &bjac->mat));
797e91c6855SBarry Smith   }
7984b9ad928SBarry Smith 
7994b9ad928SBarry Smith   for (i = 0; i < jac->n_local; i++) {
8009566063dSJacob Faibussowitsch     PetscCall(KSPReset(jac->ksp[i]));
801e91c6855SBarry Smith     if (bjac && bjac->x) {
8029566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->x[i]));
8039566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->y[i]));
8049566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&bjac->is[i]));
8054b9ad928SBarry Smith     }
806e91c6855SBarry Smith   }
8079566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
8089566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
809e91c6855SBarry Smith   PetscFunctionReturn(0);
810e91c6855SBarry Smith }
811e91c6855SBarry Smith 
8129371c9d4SSatish Balay static PetscErrorCode PCDestroy_BJacobi_Multiblock(PC pc) {
813e91c6855SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
814c2efdce3SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
815e91c6855SBarry Smith   PetscInt               i;
816e91c6855SBarry Smith 
817e91c6855SBarry Smith   PetscFunctionBegin;
8189566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiblock(pc));
819c2efdce3SBarry Smith   if (bjac) {
8209566063dSJacob Faibussowitsch     PetscCall(PetscFree2(bjac->x, bjac->y));
8219566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->starts));
8229566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->is));
823c2efdce3SBarry Smith   }
8249566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->data));
825*48a46eb9SPierre Jolivet   for (i = 0; i < jac->n_local; i++) PetscCall(KSPDestroy(&jac->ksp[i]));
8269566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
8272e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
8284b9ad928SBarry Smith   PetscFunctionReturn(0);
8294b9ad928SBarry Smith }
8304b9ad928SBarry Smith 
8319371c9d4SSatish Balay static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiblock(PC pc) {
8324b9ad928SBarry Smith   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
83369a612a9SBarry Smith   PetscInt           i, n_local = jac->n_local;
834539c167fSBarry Smith   KSPConvergedReason reason;
8354b9ad928SBarry Smith 
8364b9ad928SBarry Smith   PetscFunctionBegin;
8374b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8389566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(jac->ksp[i]));
8399566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(jac->ksp[i], &reason));
8409371c9d4SSatish Balay     if (reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
8414b9ad928SBarry Smith   }
8424b9ad928SBarry Smith   PetscFunctionReturn(0);
8434b9ad928SBarry Smith }
8444b9ad928SBarry Smith 
8454b9ad928SBarry Smith /*
8464b9ad928SBarry Smith       Preconditioner for block Jacobi
8474b9ad928SBarry Smith */
8489371c9d4SSatish Balay static PetscErrorCode PCApply_BJacobi_Multiblock(PC pc, Vec x, Vec y) {
8494b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
85069a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
8514b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
852d9ca1df4SBarry Smith   PetscScalar           *yin;
853d9ca1df4SBarry Smith   const PetscScalar     *xin;
85458ebbce7SBarry Smith 
8554b9ad928SBarry Smith   PetscFunctionBegin;
8569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
8579566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
8584b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8594b9ad928SBarry Smith     /*
8604b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
8614b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
8624b9ad928SBarry Smith        the global vector.
8634b9ad928SBarry Smith     */
8649566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
8659566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
8664b9ad928SBarry Smith 
8679566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
8689566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->ksp[i], bjac->x[i], bjac->y[i]));
8699566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
8709566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
871d11f3a42SBarry Smith 
8729566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
8739566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
8744b9ad928SBarry Smith   }
8759566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
8769566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
8774b9ad928SBarry Smith   PetscFunctionReturn(0);
8784b9ad928SBarry Smith }
8794b9ad928SBarry Smith 
8804b9ad928SBarry Smith /*
8814b9ad928SBarry Smith       Preconditioner for block Jacobi
8824b9ad928SBarry Smith */
8839371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_BJacobi_Multiblock(PC pc, Vec x, Vec y) {
8844b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
88569a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
8864b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
887d9ca1df4SBarry Smith   PetscScalar           *yin;
888d9ca1df4SBarry Smith   const PetscScalar     *xin;
8894b9ad928SBarry Smith 
8904b9ad928SBarry Smith   PetscFunctionBegin;
8919566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
8929566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
8934b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8944b9ad928SBarry Smith     /*
8954b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
8964b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
8974b9ad928SBarry Smith        the global vector.
8984b9ad928SBarry Smith     */
8999566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
9009566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
9014b9ad928SBarry Smith 
9029566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
9039566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(jac->ksp[i], bjac->x[i], bjac->y[i]));
9049566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
9059566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
906a7ff49e8SJed Brown 
9079566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9089566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9094b9ad928SBarry Smith   }
9109566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
9119566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
9124b9ad928SBarry Smith   PetscFunctionReturn(0);
9134b9ad928SBarry Smith }
9144b9ad928SBarry Smith 
9159371c9d4SSatish Balay static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC pc, Mat mat, Mat pmat) {
9164b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
91769a612a9SBarry Smith   PetscInt               m, n_local, N, M, start, i;
918ea41da7aSPierre Jolivet   const char            *prefix;
9194b9ad928SBarry Smith   KSP                    ksp;
9204b9ad928SBarry Smith   Vec                    x, y;
9214b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
9224b9ad928SBarry Smith   PC                     subpc;
9234b9ad928SBarry Smith   IS                     is;
924434a97beSBrad Aagaard   MatReuse               scall;
9253f6dc190SJunchao Zhang   VecType                vectype;
9264b9ad928SBarry Smith 
9274b9ad928SBarry Smith   PetscFunctionBegin;
9289566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &M, &N));
9294b9ad928SBarry Smith 
9304b9ad928SBarry Smith   n_local = jac->n_local;
9314b9ad928SBarry Smith 
93249517cdeSBarry Smith   if (pc->useAmat) {
933ace3abfcSBarry Smith     PetscBool same;
9349566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat, ((PetscObject)pmat)->type_name, &same));
93528b400f6SJacob Faibussowitsch     PetscCheck(same, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Matrices not of same type");
9364b9ad928SBarry Smith   }
9374b9ad928SBarry Smith 
9384b9ad928SBarry Smith   if (!pc->setupcalled) {
9394b9ad928SBarry Smith     scall = MAT_INITIAL_MATRIX;
940c2efdce3SBarry Smith 
941c2efdce3SBarry Smith     if (!jac->ksp) {
942e91c6855SBarry Smith       pc->ops->reset          = PCReset_BJacobi_Multiblock;
9434b9ad928SBarry Smith       pc->ops->destroy        = PCDestroy_BJacobi_Multiblock;
9444b9ad928SBarry Smith       pc->ops->apply          = PCApply_BJacobi_Multiblock;
9457b6e2003SPierre Jolivet       pc->ops->matapply       = NULL;
9464b9ad928SBarry Smith       pc->ops->applytranspose = PCApplyTranspose_BJacobi_Multiblock;
9474b9ad928SBarry Smith       pc->ops->setuponblocks  = PCSetUpOnBlocks_BJacobi_Multiblock;
9484b9ad928SBarry Smith 
9499566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc, &bjac));
9509566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &jac->ksp));
9519566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc, sizeof(n_local * sizeof(KSP))));
9529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n_local, &bjac->x, n_local, &bjac->y));
9539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->starts));
9549566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc, sizeof(n_local * sizeof(PetscScalar))));
9554b9ad928SBarry Smith 
9564b9ad928SBarry Smith       jac->data = (void *)bjac;
9579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->is));
9589566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc, sizeof(n_local * sizeof(IS))));
9594b9ad928SBarry Smith 
9604b9ad928SBarry Smith       for (i = 0; i < n_local; i++) {
9619566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
9629566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
9639566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
9649566063dSJacob Faibussowitsch         PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ksp));
9659566063dSJacob Faibussowitsch         PetscCall(KSPSetType(ksp, KSPPREONLY));
9669566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp, &subpc));
9679566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc, &prefix));
9689566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp, prefix));
9699566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
9702fa5cd67SKarl Rupp 
971c2efdce3SBarry Smith         jac->ksp[i] = ksp;
972c2efdce3SBarry Smith       }
973c2efdce3SBarry Smith     } else {
974c2efdce3SBarry Smith       bjac = (PC_BJacobi_Multiblock *)jac->data;
975c2efdce3SBarry Smith     }
9764b9ad928SBarry Smith 
977c2efdce3SBarry Smith     start = 0;
9789566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
979c2efdce3SBarry Smith     for (i = 0; i < n_local; i++) {
9804b9ad928SBarry Smith       m = jac->l_lens[i];
9814b9ad928SBarry Smith       /*
9824b9ad928SBarry Smith       The reason we need to generate these vectors is to serve
9834b9ad928SBarry Smith       as the right-hand side and solution vector for the solve on the
9844b9ad928SBarry Smith       block. We do not need to allocate space for the vectors since
9854b9ad928SBarry Smith       that is provided via VecPlaceArray() just before the call to
9864b9ad928SBarry Smith       KSPSolve() on the block.
9874b9ad928SBarry Smith 
9884b9ad928SBarry Smith       */
9899566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, m, &x));
9909566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &y));
9919566063dSJacob Faibussowitsch       PetscCall(VecSetType(x, vectype));
9929566063dSJacob Faibussowitsch       PetscCall(VecSetType(y, vectype));
9939566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)x));
9949566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)y));
9952fa5cd67SKarl Rupp 
9964b9ad928SBarry Smith       bjac->x[i]      = x;
9974b9ad928SBarry Smith       bjac->y[i]      = y;
9984b9ad928SBarry Smith       bjac->starts[i] = start;
9994b9ad928SBarry Smith 
10009566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, m, start, 1, &is));
10014b9ad928SBarry Smith       bjac->is[i] = is;
10029566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)is));
10034b9ad928SBarry Smith 
10044b9ad928SBarry Smith       start += m;
10054b9ad928SBarry Smith     }
10064b9ad928SBarry Smith   } else {
10074b9ad928SBarry Smith     bjac = (PC_BJacobi_Multiblock *)jac->data;
10084b9ad928SBarry Smith     /*
10094b9ad928SBarry Smith        Destroy the blocks from the previous iteration
10104b9ad928SBarry Smith     */
10114b9ad928SBarry Smith     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
10129566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(n_local, &bjac->pmat));
1013*48a46eb9SPierre Jolivet       if (pc->useAmat) PetscCall(MatDestroyMatrices(n_local, &bjac->mat));
10144b9ad928SBarry Smith       scall = MAT_INITIAL_MATRIX;
10152fa5cd67SKarl Rupp     } else scall = MAT_REUSE_MATRIX;
10164b9ad928SBarry Smith   }
10174b9ad928SBarry Smith 
10189566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(pmat, n_local, bjac->is, bjac->is, scall, &bjac->pmat));
1019*48a46eb9SPierre Jolivet   if (pc->useAmat) PetscCall(MatCreateSubMatrices(mat, n_local, bjac->is, bjac->is, scall, &bjac->mat));
10204b9ad928SBarry Smith   /* Return control to the user so that the submatrices can be modified (e.g., to apply
10214b9ad928SBarry Smith      different boundary conditions for the submatrices than for the global problem) */
10229566063dSJacob Faibussowitsch   PetscCall(PCModifySubMatrices(pc, n_local, bjac->is, bjac->is, bjac->pmat, pc->modifysubmatricesP));
10234b9ad928SBarry Smith 
10244b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
10259566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)bjac->pmat[i]));
10269566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[i], &prefix));
102749517cdeSBarry Smith     if (pc->useAmat) {
10289566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)bjac->mat[i]));
10299566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->mat[i], bjac->pmat[i]));
10309566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(bjac->mat[i], prefix));
10314b9ad928SBarry Smith     } else {
10329566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->pmat[i], bjac->pmat[i]));
10334b9ad928SBarry Smith     }
10349566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(bjac->pmat[i], prefix));
1035*48a46eb9SPierre Jolivet     if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[i]));
103690f1c854SHong Zhang   }
10374b9ad928SBarry Smith   PetscFunctionReturn(0);
10384b9ad928SBarry Smith }
10395a7e1895SHong Zhang 
10405a7e1895SHong Zhang /* ---------------------------------------------------------------------------------------------*/
10415a7e1895SHong Zhang /*
1042fd0b8932SBarry Smith       These are for a single block with multiple processes
10435a7e1895SHong Zhang */
10449371c9d4SSatish Balay static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiproc(PC pc) {
1045fd0b8932SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
1046fd0b8932SBarry Smith   KSP                subksp = jac->ksp[0];
1047fd0b8932SBarry Smith   KSPConvergedReason reason;
1048fd0b8932SBarry Smith 
1049fd0b8932SBarry Smith   PetscFunctionBegin;
10509566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
10519566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
10529371c9d4SSatish Balay   if (reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
1053fd0b8932SBarry Smith   PetscFunctionReturn(0);
1054fd0b8932SBarry Smith }
1055fd0b8932SBarry Smith 
10569371c9d4SSatish Balay static PetscErrorCode PCReset_BJacobi_Multiproc(PC pc) {
10575a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
10585a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
10595a7e1895SHong Zhang 
10605a7e1895SHong Zhang   PetscFunctionBegin;
10619566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->ysub));
10629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->xsub));
10639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mpjac->submats));
10649566063dSJacob Faibussowitsch   if (jac->ksp) PetscCall(KSPReset(jac->ksp[0]));
1065e91c6855SBarry Smith   PetscFunctionReturn(0);
1066e91c6855SBarry Smith }
1067e91c6855SBarry Smith 
10689371c9d4SSatish Balay static PetscErrorCode PCDestroy_BJacobi_Multiproc(PC pc) {
1069e91c6855SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
1070e91c6855SBarry Smith   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1071e91c6855SBarry Smith 
1072e91c6855SBarry Smith   PetscFunctionBegin;
10739566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiproc(pc));
10749566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
10759566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
10769566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&mpjac->psubcomm));
10775a7e1895SHong Zhang 
10789566063dSJacob Faibussowitsch   PetscCall(PetscFree(mpjac));
10792e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
10805a7e1895SHong Zhang   PetscFunctionReturn(0);
10815a7e1895SHong Zhang }
10825a7e1895SHong Zhang 
10839371c9d4SSatish Balay static PetscErrorCode PCApply_BJacobi_Multiproc(PC pc, Vec x, Vec y) {
10845a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
10855a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1086d9ca1df4SBarry Smith   PetscScalar          *yarray;
1087d9ca1df4SBarry Smith   const PetscScalar    *xarray;
1088539c167fSBarry Smith   KSPConvergedReason    reason;
10895a7e1895SHong Zhang 
10905a7e1895SHong Zhang   PetscFunctionBegin;
10915a7e1895SHong Zhang   /* place x's and y's local arrays into xsub and ysub */
10929566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xarray));
10939566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yarray));
10949566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->xsub, xarray));
10959566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->ysub, yarray));
10965a7e1895SHong Zhang 
10975a7e1895SHong Zhang   /* apply preconditioner on each matrix block */
10989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
10999566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], mpjac->xsub, mpjac->ysub));
11009566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, mpjac->ysub));
11019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
11029566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
11039371c9d4SSatish Balay   if (reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
1104250cf88bSHong Zhang 
11059566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->xsub));
11069566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->ysub));
11079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xarray));
11089566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yarray));
11095a7e1895SHong Zhang   PetscFunctionReturn(0);
11105a7e1895SHong Zhang }
11115a7e1895SHong Zhang 
11129371c9d4SSatish Balay static PetscErrorCode PCMatApply_BJacobi_Multiproc(PC pc, Mat X, Mat Y) {
11137b6e2003SPierre Jolivet   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
11147b6e2003SPierre Jolivet   KSPConvergedReason reason;
11157b6e2003SPierre Jolivet   Mat                sX, sY;
11167b6e2003SPierre Jolivet   const PetscScalar *x;
11177b6e2003SPierre Jolivet   PetscScalar       *y;
11187b6e2003SPierre Jolivet   PetscInt           m, N, lda, ldb;
11197b6e2003SPierre Jolivet 
11207b6e2003SPierre Jolivet   PetscFunctionBegin;
11217b6e2003SPierre Jolivet   /* apply preconditioner on each matrix block */
11229566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m, NULL));
11239566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, NULL, &N));
11249566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
11259566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(Y, &ldb));
11269566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(X, &x));
11279566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(Y, &y));
11289566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, (PetscScalar *)x, &sX));
11299566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, y, &sY));
11309566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sX, lda));
11319566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sY, ldb));
11329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
11339566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
11349566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, NULL));
11359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
11369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sY));
11379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sX));
11389566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(Y, &y));
11399566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(X, &x));
11409566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
11419371c9d4SSatish Balay   if (reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
11427b6e2003SPierre Jolivet   PetscFunctionReturn(0);
11437b6e2003SPierre Jolivet }
11447b6e2003SPierre Jolivet 
11459371c9d4SSatish Balay static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC pc) {
11465a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
11475a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
11485a7e1895SHong Zhang   PetscInt              m, n;
1149ce94432eSBarry Smith   MPI_Comm              comm, subcomm = 0;
11505a7e1895SHong Zhang   const char           *prefix;
1151de0953f6SBarry Smith   PetscBool             wasSetup = PETSC_TRUE;
11523f6dc190SJunchao Zhang   VecType               vectype;
11531f62890fSKarl Rupp 
11545a7e1895SHong Zhang   PetscFunctionBegin;
11559566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
115608401ef6SPierre Jolivet   PetscCheck(jac->n_local <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Only a single block in a subcommunicator is supported");
11575a7e1895SHong Zhang   jac->n_local = 1; /* currently only a single block is supported for a subcommunicator */
11585a7e1895SHong Zhang   if (!pc->setupcalled) {
1159de0953f6SBarry Smith     wasSetup = PETSC_FALSE;
11609566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(pc, &mpjac));
11615a7e1895SHong Zhang     jac->data = (void *)mpjac;
11625a7e1895SHong Zhang 
11635a7e1895SHong Zhang     /* initialize datastructure mpjac */
11645a7e1895SHong Zhang     if (!jac->psubcomm) {
11655a7e1895SHong Zhang       /* Create default contiguous subcommunicatiors if user does not provide them */
11669566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &jac->psubcomm));
11679566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(jac->psubcomm, jac->n));
11689566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetType(jac->psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
11699566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc, sizeof(PetscSubcomm)));
11705a7e1895SHong Zhang     }
11715a7e1895SHong Zhang     mpjac->psubcomm = jac->psubcomm;
1172306c2d5bSBarry Smith     subcomm         = PetscSubcommChild(mpjac->psubcomm);
11735a7e1895SHong Zhang 
11745a7e1895SHong Zhang     /* Get matrix blocks of pmat */
11759566063dSJacob Faibussowitsch     PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
11765a7e1895SHong Zhang 
11775a7e1895SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
11789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->ksp));
11799566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm, &jac->ksp[0]));
11809566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(jac->ksp[0], pc->erroriffailure));
11819566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp[0], (PetscObject)pc, 1));
11829566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)jac->ksp[0]));
11839566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
11849566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(jac->ksp[0], &mpjac->pc));
11855a7e1895SHong Zhang 
11869566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
11879566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(jac->ksp[0], prefix));
11889566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(jac->ksp[0], "sub_"));
11899566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[0], &prefix));
11909566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mpjac->submats, prefix));
11915a7e1895SHong Zhang 
11925a7e1895SHong Zhang     /* create dummy vectors xsub and ysub */
11939566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mpjac->submats, &m, &n));
11949566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, n, PETSC_DECIDE, NULL, &mpjac->xsub));
11959566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, m, PETSC_DECIDE, NULL, &mpjac->ysub));
11969566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(mpjac->submats, &vectype));
11979566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->xsub, vectype));
11989566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->ysub, vectype));
11999566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mpjac->xsub));
12009566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mpjac->ysub));
12015a7e1895SHong Zhang 
1202fd0b8932SBarry Smith     pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiproc;
1203e91c6855SBarry Smith     pc->ops->reset         = PCReset_BJacobi_Multiproc;
12045a7e1895SHong Zhang     pc->ops->destroy       = PCDestroy_BJacobi_Multiproc;
12055a7e1895SHong Zhang     pc->ops->apply         = PCApply_BJacobi_Multiproc;
12067b6e2003SPierre Jolivet     pc->ops->matapply      = PCMatApply_BJacobi_Multiproc;
1207fc08c53fSHong Zhang   } else { /* pc->setupcalled */
1208306c2d5bSBarry Smith     subcomm = PetscSubcommChild(mpjac->psubcomm);
12099e0ae222SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
12105a7e1895SHong Zhang       /* destroy old matrix blocks, then get new matrix blocks */
12119566063dSJacob Faibussowitsch       if (mpjac->submats) PetscCall(MatDestroy(&mpjac->submats));
12129566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
1213fc08c53fSHong Zhang     } else {
12149566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_REUSE_MATRIX, &mpjac->submats));
12155a7e1895SHong Zhang     }
12169566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
12175a7e1895SHong Zhang   }
12185a7e1895SHong Zhang 
1219*48a46eb9SPierre Jolivet   if (!wasSetup && pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[0]));
12205a7e1895SHong Zhang   PetscFunctionReturn(0);
12215a7e1895SHong Zhang }
1222