xref: /petsc/src/ksp/pc/impls/bjacobi/bjacobi.c (revision f9663b93ddca5ef47eb7ea337a18d9144e6b1e51)
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 
12d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi(PC pc)
13d71ae5a4SJacob Faibussowitsch {
144b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
154b9ad928SBarry Smith   Mat         mat = pc->mat, pmat = pc->pmat;
16976e8c5aSLisandro Dalcin   PetscBool   hasop;
1769a612a9SBarry Smith   PetscInt    N, M, start, i, sum, end;
1869a612a9SBarry Smith   PetscInt    bs, i_start = -1, i_end = -1;
1969a612a9SBarry Smith   PetscMPIInt rank, size;
204b9ad928SBarry Smith 
214b9ad928SBarry Smith   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
249566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &M, &N));
259566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(pc->pmat, &bs));
264b9ad928SBarry Smith 
275a7e1895SHong Zhang   if (jac->n > 0 && jac->n < size) {
289566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiproc(pc));
293ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
305a7e1895SHong Zhang   }
315a7e1895SHong Zhang 
32f1580f4eSBarry Smith   /*    Determines the number of blocks assigned to each processor */
334b9ad928SBarry Smith   /*   local block count  given */
344b9ad928SBarry Smith   if (jac->n_local > 0 && jac->n < 0) {
351c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&jac->n_local, &jac->n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc)));
364b9ad928SBarry Smith     if (jac->l_lens) { /* check that user set these correctly */
374b9ad928SBarry Smith       sum = 0;
384b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
3908401ef6SPierre 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");
404b9ad928SBarry Smith         sum += jac->l_lens[i];
414b9ad928SBarry Smith       }
4208401ef6SPierre Jolivet       PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local lens set incorrectly");
434b9ad928SBarry Smith     } else {
449566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
452fa5cd67SKarl 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));
464b9ad928SBarry Smith     }
474b9ad928SBarry Smith   } else if (jac->n > 0 && jac->n_local < 0) { /* global block count given */
484b9ad928SBarry Smith     /* global blocks given: determine which ones are local */
494b9ad928SBarry Smith     if (jac->g_lens) {
504b9ad928SBarry Smith       /* check if the g_lens is has valid entries */
514b9ad928SBarry Smith       for (i = 0; i < jac->n; i++) {
527827d75bSBarry Smith         PetscCheck(jac->g_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Zero block not allowed");
5308401ef6SPierre 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");
544b9ad928SBarry Smith       }
554b9ad928SBarry Smith       if (size == 1) {
564b9ad928SBarry Smith         jac->n_local = jac->n;
579566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
589566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens, jac->n_local));
594b9ad928SBarry Smith         /* check that user set these correctly */
604b9ad928SBarry Smith         sum = 0;
614b9ad928SBarry Smith         for (i = 0; i < jac->n_local; i++) sum += jac->l_lens[i];
6208401ef6SPierre Jolivet         PetscCheck(sum == M, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Global lens set incorrectly");
634b9ad928SBarry Smith       } else {
649566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->pmat, &start, &end));
65aaa8cc7dSPierre Jolivet         /* loop over blocks determining first one owned by me */
664b9ad928SBarry Smith         sum = 0;
674b9ad928SBarry Smith         for (i = 0; i < jac->n + 1; i++) {
689371c9d4SSatish Balay           if (sum == start) {
699371c9d4SSatish Balay             i_start = i;
709371c9d4SSatish Balay             goto start_1;
719371c9d4SSatish Balay           }
724b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
734b9ad928SBarry Smith         }
74e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
754b9ad928SBarry Smith       start_1:
764b9ad928SBarry Smith         for (i = i_start; i < jac->n + 1; i++) {
779371c9d4SSatish Balay           if (sum == end) {
789371c9d4SSatish Balay             i_end = i;
799371c9d4SSatish Balay             goto end_1;
809371c9d4SSatish Balay           }
814b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
824b9ad928SBarry Smith         }
83e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
844b9ad928SBarry Smith       end_1:
854b9ad928SBarry Smith         jac->n_local = i_end - i_start;
869566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
879566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens, jac->g_lens + i_start, jac->n_local));
884b9ad928SBarry Smith       }
894b9ad928SBarry Smith     } else { /* no global blocks given, determine then using default layout */
904b9ad928SBarry Smith       jac->n_local = jac->n / size + ((jac->n % size) > rank);
919566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
924b9ad928SBarry Smith       for (i = 0; i < jac->n_local; i++) {
934b9ad928SBarry Smith         jac->l_lens[i] = ((M / bs) / jac->n_local + (((M / bs) % jac->n_local) > i)) * bs;
947827d75bSBarry Smith         PetscCheck(jac->l_lens[i], PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Too many blocks given");
954b9ad928SBarry Smith       }
964b9ad928SBarry Smith     }
974b9ad928SBarry Smith   } else if (jac->n < 0 && jac->n_local < 0) { /* no blocks given */
984b9ad928SBarry Smith     jac->n       = size;
994b9ad928SBarry Smith     jac->n_local = 1;
1009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->l_lens));
1014b9ad928SBarry Smith     jac->l_lens[0] = M;
1027271b979SBarry Smith   } else { /* jac->n > 0 && jac->n_local > 0 */
1037271b979SBarry Smith     if (!jac->l_lens) {
1049566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local, &jac->l_lens));
1052fa5cd67SKarl 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));
1067271b979SBarry Smith     }
1074b9ad928SBarry Smith   }
10808401ef6SPierre Jolivet   PetscCheck(jac->n_local >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of blocks is less than number of processors");
1094b9ad928SBarry Smith 
110f1580f4eSBarry Smith   /*    Determines mat and pmat */
1119566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(pc->mat, MATOP_GET_DIAGONAL_BLOCK, &hasop));
112976e8c5aSLisandro Dalcin   if (!hasop && size == 1) {
1134b9ad928SBarry Smith     mat  = pc->mat;
1144b9ad928SBarry Smith     pmat = pc->pmat;
1154b9ad928SBarry Smith   } else {
11649517cdeSBarry Smith     if (pc->useAmat) {
11749517cdeSBarry Smith       /* use block from Amat matrix, not Pmat for local MatMult() */
1189566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->mat, &mat));
1194b9ad928SBarry Smith     }
12049517cdeSBarry Smith     if (pc->pmat != pc->mat || !pc->useAmat) {
1219566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->pmat, &pmat));
1222fa5cd67SKarl Rupp     } else pmat = mat;
1234b9ad928SBarry Smith   }
1244b9ad928SBarry Smith 
125f1580f4eSBarry Smith   /*
1264b9ad928SBarry Smith      Setup code depends on the number of blocks
1274b9ad928SBarry Smith   */
128cc1d6079SHong Zhang   if (jac->n_local == 1) {
1299566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Singleblock(pc, mat, pmat));
1304b9ad928SBarry Smith   } else {
1319566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiblock(pc, mat, pmat));
1324b9ad928SBarry Smith   }
1333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1344b9ad928SBarry Smith }
1354b9ad928SBarry Smith 
1364b9ad928SBarry Smith /* Default destroy, if it has never been setup */
137d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi(PC pc)
138d71ae5a4SJacob Faibussowitsch {
1394b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
1404b9ad928SBarry Smith 
1414b9ad928SBarry Smith   PetscFunctionBegin;
1429566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
1439566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
1442e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetSubKSP_C", NULL));
1452e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetTotalBlocks_C", NULL));
1462e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetTotalBlocks_C", NULL));
1472e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiSetLocalBlocks_C", NULL));
1482e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBJacobiGetLocalBlocks_C", NULL));
1499566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1514b9ad928SBarry Smith }
1524b9ad928SBarry Smith 
153d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_BJacobi(PC pc, PetscOptionItems *PetscOptionsObject)
154d71ae5a4SJacob Faibussowitsch {
1554b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
156248bfaf0SJed Brown   PetscInt    blocks, i;
157ace3abfcSBarry Smith   PetscBool   flg;
1584b9ad928SBarry Smith 
1594b9ad928SBarry Smith   PetscFunctionBegin;
160d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Block Jacobi options");
1619566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_blocks", "Total number of blocks", "PCBJacobiSetTotalBlocks", jac->n, &blocks, &flg));
1629566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetTotalBlocks(pc, blocks, NULL));
1639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_local_blocks", "Local number of blocks", "PCBJacobiSetLocalBlocks", jac->n_local, &blocks, &flg));
1649566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetLocalBlocks(pc, blocks, NULL));
165248bfaf0SJed Brown   if (jac->ksp) {
166248bfaf0SJed Brown     /* The sub-KSP has already been set up (e.g., PCSetUp_BJacobi_Singleblock), but KSPSetFromOptions was not called
167248bfaf0SJed Brown      * unless we had already been called. */
16848a46eb9SPierre Jolivet     for (i = 0; i < jac->n_local; i++) PetscCall(KSPSetFromOptions(jac->ksp[i]));
169248bfaf0SJed Brown   }
170d0609cedSBarry Smith   PetscOptionsHeadEnd();
1713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1724b9ad928SBarry Smith }
1734b9ad928SBarry Smith 
1749804daf3SBarry Smith #include <petscdraw.h>
175d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_BJacobi(PC pc, PetscViewer viewer)
176d71ae5a4SJacob Faibussowitsch {
1774b9ad928SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
178cbe18068SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
17969a612a9SBarry Smith   PetscMPIInt           rank;
18069a612a9SBarry Smith   PetscInt              i;
181d9884438SBarry Smith   PetscBool             iascii, isstring, isdraw;
1824b9ad928SBarry Smith   PetscViewer           sviewer;
183020d6619SPierre Jolivet   PetscViewerFormat     format;
184020d6619SPierre Jolivet   const char           *prefix;
1854b9ad928SBarry Smith 
1864b9ad928SBarry Smith   PetscFunctionBegin;
1879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19032077d6dSBarry Smith   if (iascii) {
19148a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat local matrix, number of blocks = %" PetscInt_FMT "\n", jac->n));
19263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  number of blocks = %" PetscInt_FMT "\n", jac->n));
1939566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
1949566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
195020d6619SPierre Jolivet     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
1969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for first block is in the following KSP and PC objects on rank 0:\n"));
1979566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
1989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Use -%sksp_view ::ascii_info_detail to display information for all blocks\n", prefix ? prefix : ""));
199933995ecSHong Zhang       if (jac->ksp && !jac->psubcomm) {
2009566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
201dd400576SPatrick Sanan         if (rank == 0) {
2029566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2039566063dSJacob Faibussowitsch           PetscCall(KSPView(jac->ksp[0], sviewer));
2049566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
2054b9ad928SBarry Smith         }
2069566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2079566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2089566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
209e4de9e1dSBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
211e4fa1014SBarry Smith       } else if (mpjac && jac->ksp && mpjac->psubcomm) {
2129566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
213e4fa1014SBarry Smith         if (!mpjac->psubcomm->color) {
2149566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2159566063dSJacob Faibussowitsch           PetscCall(KSPView(*(jac->ksp), sviewer));
2169566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
217cbe18068SHong Zhang         }
2189566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2199566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer, mpjac->psubcomm->child, &sviewer));
2209566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
2219530cbd7SBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2229566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2234b9ad928SBarry Smith       } else {
2249566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
225e4de9e1dSBarry Smith       }
226e4de9e1dSBarry Smith     } else {
2274814766eSBarry Smith       PetscInt n_global;
2281c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&jac->n_local, &n_global, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)pc)));
2299566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for each block is in the following KSP and PC objects:\n"));
2319371c9d4SSatish 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));
2329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2339566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
234dd2fa690SBarry Smith       for (i = 0; i < jac->n_local; i++) {
23563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] local block number %" PetscInt_FMT "\n", rank, i));
2369566063dSJacob Faibussowitsch         PetscCall(KSPView(jac->ksp[i], sviewer));
2379566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "- - - - - - - - - - - - - - - - - -\n"));
2384b9ad928SBarry Smith       }
2399566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
2419566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
2429566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2434b9ad928SBarry Smith     }
2444b9ad928SBarry Smith   } else if (isstring) {
24563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer, " blks=%" PetscInt_FMT, jac->n));
2469566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2479566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], sviewer));
2489566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
249d9884438SBarry Smith   } else if (isdraw) {
250d9884438SBarry Smith     PetscDraw draw;
251d9884438SBarry Smith     char      str[25];
252d9884438SBarry Smith     PetscReal x, y, bottom, h;
253d9884438SBarry Smith 
2549566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2559566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
25663a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str, 25, "Number blocks %" PetscInt_FMT, jac->n));
2579566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
258d9884438SBarry Smith     bottom = y - h;
2599566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
260d9884438SBarry Smith     /* warning the communicator on viewer is different then on ksp in parallel */
2619566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0], viewer));
2629566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2634b9ad928SBarry Smith   }
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2654b9ad928SBarry Smith }
2664b9ad928SBarry Smith 
267d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetSubKSP_BJacobi(PC pc, PetscInt *n_local, PetscInt *first_local, KSP **ksp)
268d71ae5a4SJacob Faibussowitsch {
269feb237baSPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2704b9ad928SBarry Smith 
2714b9ad928SBarry Smith   PetscFunctionBegin;
27228b400f6SJacob Faibussowitsch   PetscCheck(pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() first");
2734b9ad928SBarry Smith 
2744b9ad928SBarry Smith   if (n_local) *n_local = jac->n_local;
2754b9ad928SBarry Smith   if (first_local) *first_local = jac->first_local;
276020d6619SPierre Jolivet   if (ksp) *ksp = jac->ksp;
2773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2784b9ad928SBarry Smith }
2794b9ad928SBarry Smith 
280*f9663b93SPierre Jolivet static PetscErrorCode PCBJacobiSetTotalBlocks_BJacobi(PC pc, PetscInt blocks, const PetscInt *lens)
281d71ae5a4SJacob Faibussowitsch {
2824b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2834b9ad928SBarry Smith 
2844b9ad928SBarry Smith   PetscFunctionBegin;
2852472a847SBarry 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");
2864b9ad928SBarry Smith   jac->n = blocks;
2870a545947SLisandro Dalcin   if (!lens) jac->g_lens = NULL;
2882fa5cd67SKarl Rupp   else {
2899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks, &jac->g_lens));
2909566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->g_lens, lens, blocks));
2914b9ad928SBarry Smith   }
2923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2934b9ad928SBarry Smith }
2944b9ad928SBarry Smith 
295d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetTotalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
296d71ae5a4SJacob Faibussowitsch {
2974b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
2984b9ad928SBarry Smith 
2994b9ad928SBarry Smith   PetscFunctionBegin;
3004b9ad928SBarry Smith   *blocks = jac->n;
3014b9ad928SBarry Smith   if (lens) *lens = jac->g_lens;
3023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3034b9ad928SBarry Smith }
3044b9ad928SBarry Smith 
305d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiSetLocalBlocks_BJacobi(PC pc, PetscInt blocks, const PetscInt lens[])
306d71ae5a4SJacob Faibussowitsch {
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(PetscArraycpy(jac->l_lens, lens, blocks));
3174b9ad928SBarry Smith   }
3183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3194b9ad928SBarry Smith }
3204b9ad928SBarry Smith 
321d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCBJacobiGetLocalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
322d71ae5a4SJacob Faibussowitsch {
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;
3283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3294b9ad928SBarry Smith }
3304b9ad928SBarry Smith 
3314b9ad928SBarry Smith /*@C
332f1580f4eSBarry Smith   PCBJacobiGetSubKSP - Gets the local `KSP` contexts for all blocks on
3334b9ad928SBarry Smith   this processor.
3344b9ad928SBarry Smith 
3356da92b7fSHong Zhang   Not Collective
3364b9ad928SBarry Smith 
3374b9ad928SBarry Smith   Input Parameter:
3384b9ad928SBarry Smith . pc - the preconditioner context
3394b9ad928SBarry Smith 
3404b9ad928SBarry Smith   Output Parameters:
3410298fd71SBarry Smith + n_local     - the number of blocks on this processor, or NULL
3420298fd71SBarry Smith . first_local - the global number of the first block on this processor, or NULL
3434b9ad928SBarry Smith - ksp         - the array of KSP contexts
3444b9ad928SBarry Smith 
3454b9ad928SBarry Smith   Notes:
346f1580f4eSBarry Smith   After `PCBJacobiGetSubKSP()` the array of `KSP` contexts is not to be freed.
3474b9ad928SBarry Smith 
3484b9ad928SBarry Smith   Currently for some matrix implementations only 1 block per processor
3494b9ad928SBarry Smith   is supported.
3504b9ad928SBarry Smith 
351f1580f4eSBarry Smith   You must call `KSPSetUp()` or `PCSetUp()` before calling `PCBJacobiGetSubKSP()`.
3524b9ad928SBarry Smith 
353feefa0e1SJacob Faibussowitsch   Fortran Notes:
354f1580f4eSBarry Smith   You must pass in a `KSP` array that is large enough to contain all the local `KSP`s.
355f1580f4eSBarry Smith 
356f1580f4eSBarry Smith   You can call `PCBJacobiGetSubKSP`(pc,nlocal,firstlocal,`PETSC_NULL_KSP`,ierr) to determine how large the
357f1580f4eSBarry Smith   `KSP` array must be.
358196cc216SBarry Smith 
3594b9ad928SBarry Smith   Level: advanced
3604b9ad928SBarry Smith 
361f1580f4eSBarry Smith .seealso: `PCBJACOBI`, `PCASM`, `PCASMGetSubKSP()`
3624b9ad928SBarry Smith @*/
363d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetSubKSP(PC pc, PetscInt *n_local, PetscInt *first_local, KSP *ksp[])
364d71ae5a4SJacob Faibussowitsch {
3654b9ad928SBarry Smith   PetscFunctionBegin;
3660700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
367cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetSubKSP_C", (PC, PetscInt *, PetscInt *, KSP **), (pc, n_local, first_local, ksp));
3683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3694b9ad928SBarry Smith }
3704b9ad928SBarry Smith 
3714b9ad928SBarry Smith /*@
3724b9ad928SBarry Smith   PCBJacobiSetTotalBlocks - Sets the global number of blocks for the block
3734b9ad928SBarry Smith   Jacobi preconditioner.
3744b9ad928SBarry Smith 
375c3339decSBarry Smith   Collective
3764b9ad928SBarry Smith 
3774b9ad928SBarry Smith   Input Parameters:
3784b9ad928SBarry Smith + pc     - the preconditioner context
3794b9ad928SBarry Smith . blocks - the number of blocks
3804b9ad928SBarry Smith - lens   - [optional] integer array containing the size of each block
3814b9ad928SBarry Smith 
3824b9ad928SBarry Smith   Options Database Key:
3834b9ad928SBarry Smith . -pc_bjacobi_blocks <blocks> - Sets the number of global blocks
3844b9ad928SBarry Smith 
385f1580f4eSBarry Smith   Note:
3864b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
387f1580f4eSBarry Smith   All processors sharing the `PC` must call this routine with the same data.
3884b9ad928SBarry Smith 
3894b9ad928SBarry Smith   Level: intermediate
3904b9ad928SBarry Smith 
391f1580f4eSBarry Smith .seealso: `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiSetLocalBlocks()`
3924b9ad928SBarry Smith @*/
393d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiSetTotalBlocks(PC pc, PetscInt blocks, const PetscInt lens[])
394d71ae5a4SJacob Faibussowitsch {
3954b9ad928SBarry Smith   PetscFunctionBegin;
3960700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
39708401ef6SPierre Jolivet   PetscCheck(blocks > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Must have positive blocks");
398cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetTotalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4004b9ad928SBarry Smith }
4014b9ad928SBarry Smith 
4024b9ad928SBarry Smith /*@C
4034b9ad928SBarry Smith   PCBJacobiGetTotalBlocks - Gets the global number of blocks for the block
404f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`, preconditioner.
4054b9ad928SBarry Smith 
406ad4df100SBarry Smith   Not Collective
4074b9ad928SBarry Smith 
4084b9ad928SBarry Smith   Input Parameter:
4094b9ad928SBarry Smith . pc - the preconditioner context
4104b9ad928SBarry Smith 
411feefa0e1SJacob Faibussowitsch   Output Parameters:
4124b9ad928SBarry Smith + blocks - the number of blocks
4134b9ad928SBarry Smith - lens   - integer array containing the size of each block
4144b9ad928SBarry Smith 
4154b9ad928SBarry Smith   Level: intermediate
4164b9ad928SBarry Smith 
417f1580f4eSBarry Smith .seealso: `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiGetLocalBlocks()`
4184b9ad928SBarry Smith @*/
419d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetTotalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
420d71ae5a4SJacob Faibussowitsch {
4214b9ad928SBarry Smith   PetscFunctionBegin;
4220700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4234f572ea9SToby Isaac   PetscAssertPointer(blocks, 2);
424cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetTotalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4264b9ad928SBarry Smith }
4274b9ad928SBarry Smith 
4284b9ad928SBarry Smith /*@
4294b9ad928SBarry Smith   PCBJacobiSetLocalBlocks - Sets the local number of blocks for the block
430f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`,  preconditioner.
4314b9ad928SBarry Smith 
4324b9ad928SBarry Smith   Not Collective
4334b9ad928SBarry Smith 
4344b9ad928SBarry Smith   Input Parameters:
4354b9ad928SBarry Smith + pc     - the preconditioner context
4364b9ad928SBarry Smith . blocks - the number of blocks
4374b9ad928SBarry Smith - lens   - [optional] integer array containing size of each block
4384b9ad928SBarry Smith 
439342c94f9SMatthew G. Knepley   Options Database Key:
440342c94f9SMatthew G. Knepley . -pc_bjacobi_local_blocks <blocks> - Sets the number of local blocks
441342c94f9SMatthew G. Knepley 
4424b9ad928SBarry Smith   Note:
4434b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
4444b9ad928SBarry Smith 
4454b9ad928SBarry Smith   Level: intermediate
4464b9ad928SBarry Smith 
447f1580f4eSBarry Smith .seealso: `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiSetTotalBlocks()`
4484b9ad928SBarry Smith @*/
449d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiSetLocalBlocks(PC pc, PetscInt blocks, const PetscInt lens[])
450d71ae5a4SJacob Faibussowitsch {
4514b9ad928SBarry Smith   PetscFunctionBegin;
4520700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
45308401ef6SPierre Jolivet   PetscCheck(blocks >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have nonegative blocks");
454cac4c232SBarry Smith   PetscTryMethod(pc, "PCBJacobiSetLocalBlocks_C", (PC, PetscInt, const PetscInt[]), (pc, blocks, lens));
4553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4564b9ad928SBarry Smith }
4574b9ad928SBarry Smith 
4584b9ad928SBarry Smith /*@C
4594b9ad928SBarry Smith   PCBJacobiGetLocalBlocks - Gets the local number of blocks for the block
460f1580f4eSBarry Smith   Jacobi, `PCBJACOBI`, preconditioner.
4614b9ad928SBarry Smith 
4624b9ad928SBarry Smith   Not Collective
4634b9ad928SBarry Smith 
4644b9ad928SBarry Smith   Input Parameters:
4654b9ad928SBarry Smith + pc     - the preconditioner context
4664b9ad928SBarry Smith . blocks - the number of blocks
4674b9ad928SBarry Smith - lens   - [optional] integer array containing size of each block
4684b9ad928SBarry Smith 
4694b9ad928SBarry Smith   Note:
4704b9ad928SBarry Smith   Currently only a limited number of blocking configurations are supported.
4714b9ad928SBarry Smith 
4724b9ad928SBarry Smith   Level: intermediate
4734b9ad928SBarry Smith 
474f1580f4eSBarry Smith .seealso: `PCBJACOBI`, `PCSetUseAmat()`, `PCBJacobiGetTotalBlocks()`
4754b9ad928SBarry Smith @*/
476d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBJacobiGetLocalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
477d71ae5a4SJacob Faibussowitsch {
4784b9ad928SBarry Smith   PetscFunctionBegin;
4790700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4804f572ea9SToby Isaac   PetscAssertPointer(blocks, 2);
481cac4c232SBarry Smith   PetscUseMethod(pc, "PCBJacobiGetLocalBlocks_C", (PC, PetscInt *, const PetscInt *[]), (pc, blocks, lens));
4823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4834b9ad928SBarry Smith }
4844b9ad928SBarry Smith 
4854b9ad928SBarry Smith /*MC
4864b9ad928SBarry Smith    PCBJACOBI - Use block Jacobi preconditioning, each block is (approximately) solved with
487f1580f4eSBarry Smith            its own `KSP` object.
4884b9ad928SBarry Smith 
4894b9ad928SBarry Smith    Options Database Keys:
490011ea8aeSBarry Smith +  -pc_use_amat - use Amat to apply block of operator in inner Krylov method
491011ea8aeSBarry Smith -  -pc_bjacobi_blocks <n> - use n total blocks
4924b9ad928SBarry Smith 
49395452b02SPatrick Sanan    Notes:
494f1580f4eSBarry Smith     See `PCJACOBI` for diagonal Jacobi, `PCVPBJACOBI` for variable point block, and `PCPBJACOBI` for fixed size point block
495468ae2e8SBarry Smith 
49695452b02SPatrick 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.
4974b9ad928SBarry Smith 
498f1580f4eSBarry Smith      To set options on the solvers for each block append -sub_ to all the `KSP` and `PC`
499d7ee0231SBarry Smith         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
5004b9ad928SBarry Smith 
501f1580f4eSBarry Smith      To set the options on the solvers separate for each block call `PCBJacobiGetSubKSP()`
502f1580f4eSBarry Smith          and set the options directly on the resulting `KSP` object (you can access its `PC`
5030462cc06SPierre Jolivet          `KSPGetPC()`)
5044b9ad928SBarry Smith 
505f1580f4eSBarry Smith      For GPU-based vectors (`VECCUDA`, `VECViennaCL`) it is recommended to use exactly one block per MPI process for best
5062210c163SDominic Meiser          performance.  Different block partitioning may lead to additional data transfers
5072210c163SDominic Meiser          between host and GPU that lead to degraded performance.
5082210c163SDominic Meiser 
509011ea8aeSBarry Smith      When multiple processes share a single block, each block encompasses exactly all the unknowns owned its set of processes.
510011ea8aeSBarry Smith 
5114b9ad928SBarry Smith    Level: beginner
5124b9ad928SBarry Smith 
513f1580f4eSBarry Smith .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCType`,
514db781477SPatrick Sanan           `PCASM`, `PCSetUseAmat()`, `PCGetUseAmat()`, `PCBJacobiGetSubKSP()`, `PCBJacobiSetTotalBlocks()`,
515db781477SPatrick Sanan           `PCBJacobiSetLocalBlocks()`, `PCSetModifySubMatrices()`, `PCJACOBI`, `PCVPBJACOBI`, `PCPBJACOBI`
5164b9ad928SBarry Smith M*/
5174b9ad928SBarry Smith 
518d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_BJacobi(PC pc)
519d71ae5a4SJacob Faibussowitsch {
52069a612a9SBarry Smith   PetscMPIInt rank;
5214b9ad928SBarry Smith   PC_BJacobi *jac;
5224b9ad928SBarry Smith 
5234b9ad928SBarry Smith   PetscFunctionBegin;
5244dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&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));
5503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5514b9ad928SBarry Smith }
5524b9ad928SBarry Smith 
5534b9ad928SBarry Smith /*
5544b9ad928SBarry Smith         These are for a single block per processor; works for AIJ, BAIJ; Seq and MPI
5554b9ad928SBarry Smith */
556d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Singleblock(PC pc)
557d71ae5a4SJacob Faibussowitsch {
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));
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566e91c6855SBarry Smith }
567e91c6855SBarry Smith 
568d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Singleblock(PC pc)
569d71ae5a4SJacob Faibussowitsch {
570e91c6855SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
571e91c6855SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
572e91c6855SBarry Smith 
573e91c6855SBarry Smith   PetscFunctionBegin;
5749566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Singleblock(pc));
5759566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
5769566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
5779566063dSJacob Faibussowitsch   PetscCall(PetscFree(bjac));
5782e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
5793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5804b9ad928SBarry Smith }
5814b9ad928SBarry Smith 
582d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Singleblock(PC pc)
583d71ae5a4SJacob Faibussowitsch {
5844b9ad928SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
5852295b7c8SHong Zhang   KSP                subksp = jac->ksp[0];
586539c167fSBarry Smith   KSPConvergedReason reason;
5874b9ad928SBarry Smith 
5884b9ad928SBarry Smith   PetscFunctionBegin;
5899566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
5909566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
591ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
5923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5934b9ad928SBarry Smith }
5944b9ad928SBarry Smith 
595d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Singleblock(PC pc, Vec x, Vec y)
596d71ae5a4SJacob Faibussowitsch {
5974b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
5984b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
5996e111a19SKarl Rupp 
6004b9ad928SBarry Smith   PetscFunctionBegin;
6019566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVectorRead(x, bjac->x));
6029566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVector(y, bjac->y));
603bba28a21SBarry Smith   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
604910cf402Sprj-      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
605910cf402Sprj-      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6069566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
6079566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], bjac->x, bjac->y));
6089566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
6099566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVectorRead(x, bjac->x));
6109566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVector(y, bjac->y));
6113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6124b9ad928SBarry Smith }
6134b9ad928SBarry Smith 
614d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_BJacobi_Singleblock(PC pc, Mat X, Mat Y)
615d71ae5a4SJacob Faibussowitsch {
6167b6e2003SPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi *)pc->data;
6177b6e2003SPierre Jolivet   Mat         sX, sY;
6187b6e2003SPierre Jolivet 
6197b6e2003SPierre Jolivet   PetscFunctionBegin;
6207b6e2003SPierre Jolivet   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
6217b6e2003SPierre Jolivet      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
6227b6e2003SPierre Jolivet      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6239566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0], pc->reusepreconditioner));
6249566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(X, &sX));
6259566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Y, &sY));
6269566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
6273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6287b6e2003SPierre Jolivet }
6297b6e2003SPierre Jolivet 
630d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplySymmetricLeft_BJacobi_Singleblock(PC pc, Vec x, Vec y)
631d71ae5a4SJacob Faibussowitsch {
6324b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6334b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
634d9ca1df4SBarry Smith   PetscScalar            *y_array;
635d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6364b9ad928SBarry Smith   PC                      subpc;
6374b9ad928SBarry Smith 
6384b9ad928SBarry Smith   PetscFunctionBegin;
6394b9ad928SBarry Smith   /*
6404b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6414b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6424b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6434b9ad928SBarry Smith     for the sequential solve.
6444b9ad928SBarry Smith   */
6459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6469566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6479566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6489566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6494b9ad928SBarry Smith   /* apply the symmetric left portion of the inner PC operator */
6504b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6519566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6529566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricLeft(subpc, bjac->x, bjac->y));
6539566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
6549566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
6559566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
6569566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
6573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6584b9ad928SBarry Smith }
6594b9ad928SBarry Smith 
660d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplySymmetricRight_BJacobi_Singleblock(PC pc, Vec x, Vec y)
661d71ae5a4SJacob Faibussowitsch {
6624b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6634b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
664d9ca1df4SBarry Smith   PetscScalar            *y_array;
665d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6664b9ad928SBarry Smith   PC                      subpc;
6674b9ad928SBarry Smith 
6684b9ad928SBarry Smith   PetscFunctionBegin;
6694b9ad928SBarry Smith   /*
6704b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6714b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6724b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6734b9ad928SBarry Smith     for the sequential solve.
6744b9ad928SBarry Smith   */
6759566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
6769566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
6779566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
6789566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
6794b9ad928SBarry Smith 
6804b9ad928SBarry Smith   /* apply the symmetric right portion of the inner PC operator */
6814b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6824b9ad928SBarry Smith 
6839566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0], &subpc));
6849566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricRight(subpc, bjac->x, bjac->y));
6854b9ad928SBarry Smith 
68611e4f71cSBarry Smith   PetscCall(VecResetArray(bjac->x));
68711e4f71cSBarry Smith   PetscCall(VecResetArray(bjac->y));
6889566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
6899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
6903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6914b9ad928SBarry Smith }
6924b9ad928SBarry Smith 
693d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_BJacobi_Singleblock(PC pc, Vec x, Vec y)
694d71ae5a4SJacob Faibussowitsch {
6954b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi *)pc->data;
6964b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock *)jac->data;
697d9ca1df4SBarry Smith   PetscScalar            *y_array;
698d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6994b9ad928SBarry Smith 
7004b9ad928SBarry Smith   PetscFunctionBegin;
7014b9ad928SBarry Smith   /*
7024b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
7034b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
7044b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
7054b9ad928SBarry Smith     for the sequential solve.
7064b9ad928SBarry Smith   */
7079566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &x_array));
7089566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &y_array));
7099566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x, x_array));
7109566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y, y_array));
7119566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(jac->ksp[0], bjac->x, bjac->y));
7129566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, bjac->y));
7139566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
7149566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
7159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &x_array));
7169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &y_array));
7173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7184b9ad928SBarry Smith }
7194b9ad928SBarry Smith 
720d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC pc, Mat mat, Mat pmat)
721d71ae5a4SJacob Faibussowitsch {
7224b9ad928SBarry Smith   PC_BJacobi             *jac = (PC_BJacobi *)pc->data;
72369a612a9SBarry Smith   PetscInt                m;
7244b9ad928SBarry Smith   KSP                     ksp;
7254b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac;
726de0953f6SBarry Smith   PetscBool               wasSetup = PETSC_TRUE;
7273f6dc190SJunchao Zhang   VecType                 vectype;
728ea41da7aSPierre Jolivet   const char             *prefix;
7294b9ad928SBarry Smith 
7304b9ad928SBarry Smith   PetscFunctionBegin;
7314b9ad928SBarry Smith   if (!pc->setupcalled) {
732c2efdce3SBarry Smith     if (!jac->ksp) {
7333821be0aSBarry Smith       PetscInt nestlevel;
7343821be0aSBarry Smith 
735302a9ddcSMatthew Knepley       wasSetup = PETSC_FALSE;
7362fa5cd67SKarl Rupp 
7379566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
7383821be0aSBarry Smith       PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
7393821be0aSBarry Smith       PetscCall(KSPSetNestLevel(ksp, nestlevel + 1));
7409566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
7419566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
7429566063dSJacob Faibussowitsch       PetscCall(KSPSetType(ksp, KSPPREONLY));
7439566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
7449566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp, prefix));
7459566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
7464b9ad928SBarry Smith 
747e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Singleblock;
7484b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Singleblock;
7494b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Singleblock;
7507b6e2003SPierre Jolivet       pc->ops->matapply            = PCMatApply_BJacobi_Singleblock;
7514b9ad928SBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Singleblock;
7524b9ad928SBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Singleblock;
7534b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Singleblock;
7544b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Singleblock;
7554b9ad928SBarry Smith 
7569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, &jac->ksp));
7574b9ad928SBarry Smith       jac->ksp[0] = ksp;
758c2efdce3SBarry Smith 
7594dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&bjac));
7604b9ad928SBarry Smith       jac->data = (void *)bjac;
7614b9ad928SBarry Smith     } else {
762c2efdce3SBarry Smith       ksp  = jac->ksp[0];
763c2efdce3SBarry Smith       bjac = (PC_BJacobi_Singleblock *)jac->data;
764c2efdce3SBarry Smith     }
765c2efdce3SBarry Smith 
766c2efdce3SBarry Smith     /*
767c2efdce3SBarry Smith       The reason we need to generate these vectors is to serve
768c2efdce3SBarry Smith       as the right-hand side and solution vector for the solve on the
769c2efdce3SBarry Smith       block. We do not need to allocate space for the vectors since
770c2efdce3SBarry Smith       that is provided via VecPlaceArray() just before the call to
771c2efdce3SBarry Smith       KSPSolve() on the block.
772c2efdce3SBarry Smith     */
7739566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pmat, &m, &m));
7749566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->x));
7759566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &bjac->y));
7769566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
7779566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->x, vectype));
7789566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->y, vectype));
779c2efdce3SBarry Smith   } else {
7804b9ad928SBarry Smith     ksp  = jac->ksp[0];
7814b9ad928SBarry Smith     bjac = (PC_BJacobi_Singleblock *)jac->data;
7824b9ad928SBarry Smith   }
7839566063dSJacob Faibussowitsch   PetscCall(KSPGetOptionsPrefix(ksp, &prefix));
78449517cdeSBarry Smith   if (pc->useAmat) {
7859566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, mat, pmat));
7869566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mat, prefix));
7874b9ad928SBarry Smith   } else {
7889566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, pmat, pmat));
7894b9ad928SBarry Smith   }
7909566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(pmat, prefix));
79190f1c854SHong Zhang   if (!wasSetup && pc->setfromoptionscalled) {
792248bfaf0SJed Brown     /* If PCSetFromOptions_BJacobi is called later, KSPSetFromOptions will be called at that time. */
7939566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ksp));
794302a9ddcSMatthew Knepley   }
7953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7964b9ad928SBarry Smith }
7974b9ad928SBarry Smith 
798d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Multiblock(PC pc)
799d71ae5a4SJacob Faibussowitsch {
8004b9ad928SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
8014b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
80269a612a9SBarry Smith   PetscInt               i;
8034b9ad928SBarry Smith 
8044b9ad928SBarry Smith   PetscFunctionBegin;
805e91c6855SBarry Smith   if (bjac && bjac->pmat) {
8069566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->n_local, &bjac->pmat));
80748a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(MatDestroyMatrices(jac->n_local, &bjac->mat));
808e91c6855SBarry Smith   }
8094b9ad928SBarry Smith 
8104b9ad928SBarry Smith   for (i = 0; i < jac->n_local; i++) {
8119566063dSJacob Faibussowitsch     PetscCall(KSPReset(jac->ksp[i]));
812e91c6855SBarry Smith     if (bjac && bjac->x) {
8139566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->x[i]));
8149566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->y[i]));
8159566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&bjac->is[i]));
8164b9ad928SBarry Smith     }
817e91c6855SBarry Smith   }
8189566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
8199566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
8203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
821e91c6855SBarry Smith }
822e91c6855SBarry Smith 
823d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Multiblock(PC pc)
824d71ae5a4SJacob Faibussowitsch {
825e91c6855SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi *)pc->data;
826c2efdce3SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
827e91c6855SBarry Smith   PetscInt               i;
828e91c6855SBarry Smith 
829e91c6855SBarry Smith   PetscFunctionBegin;
8309566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiblock(pc));
831c2efdce3SBarry Smith   if (bjac) {
8329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(bjac->x, bjac->y));
8339566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->starts));
8349566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->is));
835c2efdce3SBarry Smith   }
8369566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->data));
83748a46eb9SPierre Jolivet   for (i = 0; i < jac->n_local; i++) PetscCall(KSPDestroy(&jac->ksp[i]));
8389566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
8392e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
8403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8414b9ad928SBarry Smith }
8424b9ad928SBarry Smith 
843d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiblock(PC pc)
844d71ae5a4SJacob Faibussowitsch {
8454b9ad928SBarry Smith   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
84669a612a9SBarry Smith   PetscInt           i, n_local = jac->n_local;
847539c167fSBarry Smith   KSPConvergedReason reason;
8484b9ad928SBarry Smith 
8494b9ad928SBarry Smith   PetscFunctionBegin;
8504b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8519566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(jac->ksp[i]));
8529566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(jac->ksp[i], &reason));
853ad540459SPierre Jolivet     if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
8544b9ad928SBarry Smith   }
8553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8564b9ad928SBarry Smith }
8574b9ad928SBarry Smith 
858d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Multiblock(PC pc, Vec x, Vec y)
859d71ae5a4SJacob Faibussowitsch {
8604b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
86169a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
8624b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
863d9ca1df4SBarry Smith   PetscScalar           *yin;
864d9ca1df4SBarry Smith   const PetscScalar     *xin;
86558ebbce7SBarry Smith 
8664b9ad928SBarry Smith   PetscFunctionBegin;
8679566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
8689566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
8694b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
8704b9ad928SBarry Smith     /*
8714b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
8724b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
8734b9ad928SBarry Smith        the global vector.
8744b9ad928SBarry Smith     */
8759566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
8769566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
8774b9ad928SBarry Smith 
8789566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
8799566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->ksp[i], bjac->x[i], bjac->y[i]));
8809566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
8819566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
882d11f3a42SBarry Smith 
8839566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
8849566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
8854b9ad928SBarry Smith   }
8869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
8879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
8883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8894b9ad928SBarry Smith }
8904b9ad928SBarry Smith 
891f4d694ddSBarry Smith static PetscErrorCode PCApplySymmetricLeft_BJacobi_Multiblock(PC pc, Vec x, Vec y)
892f4d694ddSBarry Smith {
893f4d694ddSBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
894f4d694ddSBarry Smith   PetscInt               i, n_local = jac->n_local;
895f4d694ddSBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
896f4d694ddSBarry Smith   PetscScalar           *yin;
897f4d694ddSBarry Smith   const PetscScalar     *xin;
898f4d694ddSBarry Smith   PC                     subpc;
899f4d694ddSBarry Smith 
900f4d694ddSBarry Smith   PetscFunctionBegin;
901f4d694ddSBarry Smith   PetscCall(VecGetArrayRead(x, &xin));
902f4d694ddSBarry Smith   PetscCall(VecGetArray(y, &yin));
903f4d694ddSBarry Smith   for (i = 0; i < n_local; i++) {
9044b9ad928SBarry Smith     /*
905f4d694ddSBarry Smith        To avoid copying the subvector from x into a workspace we instead
906f4d694ddSBarry Smith        make the workspace vector array point to the subpart of the array of
907f4d694ddSBarry Smith        the global vector.
9084b9ad928SBarry Smith     */
909f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
910f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
911f4d694ddSBarry Smith 
912f4d694ddSBarry Smith     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
913f4d694ddSBarry Smith     /* apply the symmetric left portion of the inner PC operator */
914f4d694ddSBarry Smith     /* note this by-passes the inner KSP and its options completely */
915f4d694ddSBarry Smith     PetscCall(KSPGetPC(jac->ksp[i], &subpc));
916f4d694ddSBarry Smith     PetscCall(PCApplySymmetricLeft(subpc, bjac->x[i], bjac->y[i]));
917f4d694ddSBarry Smith     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
918f4d694ddSBarry Smith 
919f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->x[i]));
920f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->y[i]));
921f4d694ddSBarry Smith   }
922f4d694ddSBarry Smith   PetscCall(VecRestoreArrayRead(x, &xin));
923f4d694ddSBarry Smith   PetscCall(VecRestoreArray(y, &yin));
9243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
925f4d694ddSBarry Smith }
926f4d694ddSBarry Smith 
927f4d694ddSBarry Smith static PetscErrorCode PCApplySymmetricRight_BJacobi_Multiblock(PC pc, Vec x, Vec y)
928f4d694ddSBarry Smith {
929f4d694ddSBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
930f4d694ddSBarry Smith   PetscInt               i, n_local = jac->n_local;
931f4d694ddSBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
932f4d694ddSBarry Smith   PetscScalar           *yin;
933f4d694ddSBarry Smith   const PetscScalar     *xin;
934f4d694ddSBarry Smith   PC                     subpc;
935f4d694ddSBarry Smith 
936f4d694ddSBarry Smith   PetscFunctionBegin;
937f4d694ddSBarry Smith   PetscCall(VecGetArrayRead(x, &xin));
938f4d694ddSBarry Smith   PetscCall(VecGetArray(y, &yin));
939f4d694ddSBarry Smith   for (i = 0; i < n_local; i++) {
940f4d694ddSBarry Smith     /*
941f4d694ddSBarry Smith        To avoid copying the subvector from x into a workspace we instead
942f4d694ddSBarry Smith        make the workspace vector array point to the subpart of the array of
943f4d694ddSBarry Smith        the global vector.
944f4d694ddSBarry Smith     */
945f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
946f4d694ddSBarry Smith     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
947f4d694ddSBarry Smith 
948f4d694ddSBarry Smith     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
949f4d694ddSBarry Smith     /* apply the symmetric left portion of the inner PC operator */
950f4d694ddSBarry Smith     /* note this by-passes the inner KSP and its options completely */
951f4d694ddSBarry Smith     PetscCall(KSPGetPC(jac->ksp[i], &subpc));
952f4d694ddSBarry Smith     PetscCall(PCApplySymmetricRight(subpc, bjac->x[i], bjac->y[i]));
953f4d694ddSBarry Smith     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
954f4d694ddSBarry Smith 
955f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->x[i]));
956f4d694ddSBarry Smith     PetscCall(VecResetArray(bjac->y[i]));
957f4d694ddSBarry Smith   }
958f4d694ddSBarry Smith   PetscCall(VecRestoreArrayRead(x, &xin));
959f4d694ddSBarry Smith   PetscCall(VecRestoreArray(y, &yin));
9603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
961f4d694ddSBarry Smith }
962f4d694ddSBarry Smith 
963d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_BJacobi_Multiblock(PC pc, Vec x, Vec y)
964d71ae5a4SJacob Faibussowitsch {
9654b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
96669a612a9SBarry Smith   PetscInt               i, n_local = jac->n_local;
9674b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
968d9ca1df4SBarry Smith   PetscScalar           *yin;
969d9ca1df4SBarry Smith   const PetscScalar     *xin;
9704b9ad928SBarry Smith 
9714b9ad928SBarry Smith   PetscFunctionBegin;
9729566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xin));
9739566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yin));
9744b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
9754b9ad928SBarry Smith     /*
9764b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
9774b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
9784b9ad928SBarry Smith        the global vector.
9794b9ad928SBarry Smith     */
9809566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i], xin + bjac->starts[i]));
9819566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i], yin + bjac->starts[i]));
9824b9ad928SBarry Smith 
9839566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
9849566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(jac->ksp[i], bjac->x[i], bjac->y[i]));
9859566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i], pc, bjac->y[i]));
9869566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks, jac->ksp[i], bjac->x[i], bjac->y[i], 0));
987a7ff49e8SJed Brown 
9889566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9899566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9904b9ad928SBarry Smith   }
9919566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xin));
9929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yin));
9933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9944b9ad928SBarry Smith }
9954b9ad928SBarry Smith 
996d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC pc, Mat mat, Mat pmat)
997d71ae5a4SJacob Faibussowitsch {
9984b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi *)pc->data;
99969a612a9SBarry Smith   PetscInt               m, n_local, N, M, start, i;
1000ea41da7aSPierre Jolivet   const char            *prefix;
10014b9ad928SBarry Smith   KSP                    ksp;
10024b9ad928SBarry Smith   Vec                    x, y;
10034b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock *)jac->data;
10044b9ad928SBarry Smith   PC                     subpc;
10054b9ad928SBarry Smith   IS                     is;
1006434a97beSBrad Aagaard   MatReuse               scall;
10073f6dc190SJunchao Zhang   VecType                vectype;
10084b9ad928SBarry Smith 
10094b9ad928SBarry Smith   PetscFunctionBegin;
10109566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &M, &N));
10114b9ad928SBarry Smith 
10124b9ad928SBarry Smith   n_local = jac->n_local;
10134b9ad928SBarry Smith 
101449517cdeSBarry Smith   if (pc->useAmat) {
1015ace3abfcSBarry Smith     PetscBool same;
10169566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat, ((PetscObject)pmat)->type_name, &same));
101728b400f6SJacob Faibussowitsch     PetscCheck(same, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Matrices not of same type");
10184b9ad928SBarry Smith   }
10194b9ad928SBarry Smith 
10204b9ad928SBarry Smith   if (!pc->setupcalled) {
10213821be0aSBarry Smith     PetscInt nestlevel;
10223821be0aSBarry Smith 
10234b9ad928SBarry Smith     scall = MAT_INITIAL_MATRIX;
1024c2efdce3SBarry Smith 
1025c2efdce3SBarry Smith     if (!jac->ksp) {
1026e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Multiblock;
10274b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Multiblock;
10284b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Multiblock;
10297b6e2003SPierre Jolivet       pc->ops->matapply            = NULL;
1030f4d694ddSBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Multiblock;
1031f4d694ddSBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Multiblock;
10324b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Multiblock;
10334b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Multiblock;
10344b9ad928SBarry Smith 
10354dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&bjac));
10369566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &jac->ksp));
10379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n_local, &bjac->x, n_local, &bjac->y));
10389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->starts));
10394b9ad928SBarry Smith 
10404b9ad928SBarry Smith       jac->data = (void *)bjac;
10419566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local, &bjac->is));
10424b9ad928SBarry Smith 
10434b9ad928SBarry Smith       for (i = 0; i < n_local; i++) {
10449566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
10453821be0aSBarry Smith         PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
10463821be0aSBarry Smith         PetscCall(KSPSetNestLevel(ksp, nestlevel + 1));
10479566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
10489566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
10499566063dSJacob Faibussowitsch         PetscCall(KSPSetType(ksp, KSPPREONLY));
10509566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp, &subpc));
10519566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc, &prefix));
10529566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp, prefix));
10539566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
10542fa5cd67SKarl Rupp 
1055c2efdce3SBarry Smith         jac->ksp[i] = ksp;
1056c2efdce3SBarry Smith       }
1057c2efdce3SBarry Smith     } else {
1058c2efdce3SBarry Smith       bjac = (PC_BJacobi_Multiblock *)jac->data;
1059c2efdce3SBarry Smith     }
10604b9ad928SBarry Smith 
1061c2efdce3SBarry Smith     start = 0;
10629566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat, &vectype));
1063c2efdce3SBarry Smith     for (i = 0; i < n_local; i++) {
10644b9ad928SBarry Smith       m = jac->l_lens[i];
10654b9ad928SBarry Smith       /*
10664b9ad928SBarry Smith       The reason we need to generate these vectors is to serve
10674b9ad928SBarry Smith       as the right-hand side and solution vector for the solve on the
10684b9ad928SBarry Smith       block. We do not need to allocate space for the vectors since
10694b9ad928SBarry Smith       that is provided via VecPlaceArray() just before the call to
10704b9ad928SBarry Smith       KSPSolve() on the block.
10714b9ad928SBarry Smith 
10724b9ad928SBarry Smith       */
10739566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, m, &x));
10749566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, m, NULL, &y));
10759566063dSJacob Faibussowitsch       PetscCall(VecSetType(x, vectype));
10769566063dSJacob Faibussowitsch       PetscCall(VecSetType(y, vectype));
10772fa5cd67SKarl Rupp 
10784b9ad928SBarry Smith       bjac->x[i]      = x;
10794b9ad928SBarry Smith       bjac->y[i]      = y;
10804b9ad928SBarry Smith       bjac->starts[i] = start;
10814b9ad928SBarry Smith 
10829566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, m, start, 1, &is));
10834b9ad928SBarry Smith       bjac->is[i] = is;
10844b9ad928SBarry Smith 
10854b9ad928SBarry Smith       start += m;
10864b9ad928SBarry Smith     }
10874b9ad928SBarry Smith   } else {
10884b9ad928SBarry Smith     bjac = (PC_BJacobi_Multiblock *)jac->data;
10894b9ad928SBarry Smith     /*
10904b9ad928SBarry Smith        Destroy the blocks from the previous iteration
10914b9ad928SBarry Smith     */
10924b9ad928SBarry Smith     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
10939566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(n_local, &bjac->pmat));
109448a46eb9SPierre Jolivet       if (pc->useAmat) PetscCall(MatDestroyMatrices(n_local, &bjac->mat));
10954b9ad928SBarry Smith       scall = MAT_INITIAL_MATRIX;
10962fa5cd67SKarl Rupp     } else scall = MAT_REUSE_MATRIX;
10974b9ad928SBarry Smith   }
10984b9ad928SBarry Smith 
10999566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(pmat, n_local, bjac->is, bjac->is, scall, &bjac->pmat));
110048a46eb9SPierre Jolivet   if (pc->useAmat) PetscCall(MatCreateSubMatrices(mat, n_local, bjac->is, bjac->is, scall, &bjac->mat));
11014b9ad928SBarry Smith   /* Return control to the user so that the submatrices can be modified (e.g., to apply
11024b9ad928SBarry Smith      different boundary conditions for the submatrices than for the global problem) */
11039566063dSJacob Faibussowitsch   PetscCall(PCModifySubMatrices(pc, n_local, bjac->is, bjac->is, bjac->pmat, pc->modifysubmatricesP));
11044b9ad928SBarry Smith 
11054b9ad928SBarry Smith   for (i = 0; i < n_local; i++) {
11069566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[i], &prefix));
110749517cdeSBarry Smith     if (pc->useAmat) {
11089566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->mat[i], bjac->pmat[i]));
11099566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(bjac->mat[i], prefix));
11104b9ad928SBarry Smith     } else {
11119566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i], bjac->pmat[i], bjac->pmat[i]));
11124b9ad928SBarry Smith     }
11139566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(bjac->pmat[i], prefix));
111448a46eb9SPierre Jolivet     if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[i]));
111590f1c854SHong Zhang   }
11163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11174b9ad928SBarry Smith }
11185a7e1895SHong Zhang 
11195a7e1895SHong Zhang /*
1120fd0b8932SBarry Smith       These are for a single block with multiple processes
11215a7e1895SHong Zhang */
1122d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiproc(PC pc)
1123d71ae5a4SJacob Faibussowitsch {
1124fd0b8932SBarry Smith   PC_BJacobi        *jac    = (PC_BJacobi *)pc->data;
1125fd0b8932SBarry Smith   KSP                subksp = jac->ksp[0];
1126fd0b8932SBarry Smith   KSPConvergedReason reason;
1127fd0b8932SBarry Smith 
1128fd0b8932SBarry Smith   PetscFunctionBegin;
11299566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
11309566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp, &reason));
1131ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1133fd0b8932SBarry Smith }
1134fd0b8932SBarry Smith 
1135d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_BJacobi_Multiproc(PC pc)
1136d71ae5a4SJacob Faibussowitsch {
11375a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
11385a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
11395a7e1895SHong Zhang 
11405a7e1895SHong Zhang   PetscFunctionBegin;
11419566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->ysub));
11429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->xsub));
11439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mpjac->submats));
11449566063dSJacob Faibussowitsch   if (jac->ksp) PetscCall(KSPReset(jac->ksp[0]));
11453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1146e91c6855SBarry Smith }
1147e91c6855SBarry Smith 
1148d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_BJacobi_Multiproc(PC pc)
1149d71ae5a4SJacob Faibussowitsch {
1150e91c6855SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
1151e91c6855SBarry Smith   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1152e91c6855SBarry Smith 
1153e91c6855SBarry Smith   PetscFunctionBegin;
11549566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiproc(pc));
11559566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
11569566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
11579566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&mpjac->psubcomm));
11585a7e1895SHong Zhang 
11599566063dSJacob Faibussowitsch   PetscCall(PetscFree(mpjac));
11602e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
11613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11625a7e1895SHong Zhang }
11635a7e1895SHong Zhang 
1164d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_BJacobi_Multiproc(PC pc, Vec x, Vec y)
1165d71ae5a4SJacob Faibussowitsch {
11665a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
11675a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
1168d9ca1df4SBarry Smith   PetscScalar          *yarray;
1169d9ca1df4SBarry Smith   const PetscScalar    *xarray;
1170539c167fSBarry Smith   KSPConvergedReason    reason;
11715a7e1895SHong Zhang 
11725a7e1895SHong Zhang   PetscFunctionBegin;
11735a7e1895SHong Zhang   /* place x's and y's local arrays into xsub and ysub */
11749566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xarray));
11759566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yarray));
11769566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->xsub, xarray));
11779566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->ysub, yarray));
11785a7e1895SHong Zhang 
11795a7e1895SHong Zhang   /* apply preconditioner on each matrix block */
11809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
11819566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0], mpjac->xsub, mpjac->ysub));
11829566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, mpjac->ysub));
11839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], mpjac->xsub, mpjac->ysub, 0));
11849566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
1185ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
1186250cf88bSHong Zhang 
11879566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->xsub));
11889566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->ysub));
11899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xarray));
11909566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yarray));
11913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11925a7e1895SHong Zhang }
11935a7e1895SHong Zhang 
1194d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_BJacobi_Multiproc(PC pc, Mat X, Mat Y)
1195d71ae5a4SJacob Faibussowitsch {
11967b6e2003SPierre Jolivet   PC_BJacobi        *jac = (PC_BJacobi *)pc->data;
11977b6e2003SPierre Jolivet   KSPConvergedReason reason;
11987b6e2003SPierre Jolivet   Mat                sX, sY;
11997b6e2003SPierre Jolivet   const PetscScalar *x;
12007b6e2003SPierre Jolivet   PetscScalar       *y;
12017b6e2003SPierre Jolivet   PetscInt           m, N, lda, ldb;
12027b6e2003SPierre Jolivet 
12037b6e2003SPierre Jolivet   PetscFunctionBegin;
12047b6e2003SPierre Jolivet   /* apply preconditioner on each matrix block */
12059566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m, NULL));
12069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, NULL, &N));
12079566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
12089566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(Y, &ldb));
12099566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(X, &x));
12109566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(Y, &y));
12119566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, (PetscScalar *)x, &sX));
12129566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]), m, PETSC_DECIDE, PETSC_DECIDE, N, y, &sY));
12139566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sX, lda));
12149566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sY, ldb));
12159566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
12169566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0], sX, sY));
12179566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0], pc, NULL));
12189566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks, jac->ksp[0], X, Y, 0));
12199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sY));
12209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sX));
12219566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(Y, &y));
12229566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(X, &x));
12239566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0], &reason));
1224ad540459SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
12253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12267b6e2003SPierre Jolivet }
12277b6e2003SPierre Jolivet 
1228d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC pc)
1229d71ae5a4SJacob Faibussowitsch {
12305a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi *)pc->data;
12315a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc *)jac->data;
12325a7e1895SHong Zhang   PetscInt              m, n;
1233ce94432eSBarry Smith   MPI_Comm              comm, subcomm = 0;
12345a7e1895SHong Zhang   const char           *prefix;
1235de0953f6SBarry Smith   PetscBool             wasSetup = PETSC_TRUE;
12363f6dc190SJunchao Zhang   VecType               vectype;
12371f62890fSKarl Rupp 
12385a7e1895SHong Zhang   PetscFunctionBegin;
12399566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
124008401ef6SPierre Jolivet   PetscCheck(jac->n_local <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Only a single block in a subcommunicator is supported");
12415a7e1895SHong Zhang   jac->n_local = 1; /* currently only a single block is supported for a subcommunicator */
12425a7e1895SHong Zhang   if (!pc->setupcalled) {
12433821be0aSBarry Smith     PetscInt nestlevel;
12443821be0aSBarry Smith 
1245de0953f6SBarry Smith     wasSetup = PETSC_FALSE;
12464dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mpjac));
12475a7e1895SHong Zhang     jac->data = (void *)mpjac;
12485a7e1895SHong Zhang 
12495a7e1895SHong Zhang     /* initialize datastructure mpjac */
12505a7e1895SHong Zhang     if (!jac->psubcomm) {
12515a7e1895SHong Zhang       /* Create default contiguous subcommunicatiors if user does not provide them */
12529566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm, &jac->psubcomm));
12539566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(jac->psubcomm, jac->n));
12549566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetType(jac->psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
12555a7e1895SHong Zhang     }
12565a7e1895SHong Zhang     mpjac->psubcomm = jac->psubcomm;
1257306c2d5bSBarry Smith     subcomm         = PetscSubcommChild(mpjac->psubcomm);
12585a7e1895SHong Zhang 
12595a7e1895SHong Zhang     /* Get matrix blocks of pmat */
12609566063dSJacob Faibussowitsch     PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
12615a7e1895SHong Zhang 
12625a7e1895SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
12639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &jac->ksp));
12649566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm, &jac->ksp[0]));
12653821be0aSBarry Smith     PetscCall(PCGetKSPNestLevel(pc, &nestlevel));
12663821be0aSBarry Smith     PetscCall(KSPSetNestLevel(jac->ksp[0], nestlevel + 1));
12679566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(jac->ksp[0], pc->erroriffailure));
12689566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp[0], (PetscObject)pc, 1));
12699566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
12709566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(jac->ksp[0], &mpjac->pc));
12715a7e1895SHong Zhang 
12729566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
12739566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(jac->ksp[0], prefix));
12749566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(jac->ksp[0], "sub_"));
12759566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[0], &prefix));
12769566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mpjac->submats, prefix));
12775a7e1895SHong Zhang 
12785a7e1895SHong Zhang     /* create dummy vectors xsub and ysub */
12799566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mpjac->submats, &m, &n));
12809566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, n, PETSC_DECIDE, NULL, &mpjac->xsub));
12819566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm, 1, m, PETSC_DECIDE, NULL, &mpjac->ysub));
12829566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(mpjac->submats, &vectype));
12839566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->xsub, vectype));
12849566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->ysub, vectype));
12855a7e1895SHong Zhang 
1286fd0b8932SBarry Smith     pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiproc;
1287e91c6855SBarry Smith     pc->ops->reset         = PCReset_BJacobi_Multiproc;
12885a7e1895SHong Zhang     pc->ops->destroy       = PCDestroy_BJacobi_Multiproc;
12895a7e1895SHong Zhang     pc->ops->apply         = PCApply_BJacobi_Multiproc;
12907b6e2003SPierre Jolivet     pc->ops->matapply      = PCMatApply_BJacobi_Multiproc;
1291fc08c53fSHong Zhang   } else { /* pc->setupcalled */
1292306c2d5bSBarry Smith     subcomm = PetscSubcommChild(mpjac->psubcomm);
12939e0ae222SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
12945a7e1895SHong Zhang       /* destroy old matrix blocks, then get new matrix blocks */
12959566063dSJacob Faibussowitsch       if (mpjac->submats) PetscCall(MatDestroy(&mpjac->submats));
12969566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_INITIAL_MATRIX, &mpjac->submats));
1297fc08c53fSHong Zhang     } else {
12989566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat, subcomm, MAT_REUSE_MATRIX, &mpjac->submats));
12995a7e1895SHong Zhang     }
13009566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0], mpjac->submats, mpjac->submats));
13015a7e1895SHong Zhang   }
13025a7e1895SHong Zhang 
130348a46eb9SPierre Jolivet   if (!wasSetup && pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(jac->ksp[0]));
13043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13055a7e1895SHong Zhang }
1306