xref: /petsc/src/ksp/pc/impls/bjacobi/bjacobi.c (revision 2e956fe4fc852fabc23b437482e1fb7b77fddb0d)
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 
126849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi(PC pc)
134b9ad928SBarry Smith {
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));
295a7e1895SHong Zhang     PetscFunctionReturn(0);
305a7e1895SHong Zhang   }
315a7e1895SHong Zhang 
325a7e1895SHong Zhang   /* --------------------------------------------------------------------------
334b9ad928SBarry Smith       Determines the number of blocks assigned to each processor
345a7e1895SHong Zhang   -----------------------------------------------------------------------------*/
354b9ad928SBarry Smith 
364b9ad928SBarry Smith   /*   local block count  given */
374b9ad928SBarry Smith   if (jac->n_local > 0 && jac->n < 0) {
381c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&jac->n_local,&jac->n,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)pc)));
394b9ad928SBarry Smith     if (jac->l_lens) { /* check that user set these correctly */
404b9ad928SBarry Smith       sum = 0;
414b9ad928SBarry Smith       for (i=0; i<jac->n_local; i++) {
4208401ef6SPierre 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");
434b9ad928SBarry Smith         sum += jac->l_lens[i];
444b9ad928SBarry Smith       }
4508401ef6SPierre Jolivet       PetscCheck(sum == M,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local lens set incorrectly");
464b9ad928SBarry Smith     } else {
479566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local,&jac->l_lens));
482fa5cd67SKarl 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));
494b9ad928SBarry Smith     }
504b9ad928SBarry Smith   } else if (jac->n > 0 && jac->n_local < 0) { /* global block count given */
514b9ad928SBarry Smith     /* global blocks given: determine which ones are local */
524b9ad928SBarry Smith     if (jac->g_lens) {
534b9ad928SBarry Smith       /* check if the g_lens is has valid entries */
544b9ad928SBarry Smith       for (i=0; i<jac->n; i++) {
557827d75bSBarry Smith         PetscCheck(jac->g_lens[i],PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Zero block not allowed");
5608401ef6SPierre 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");
574b9ad928SBarry Smith       }
584b9ad928SBarry Smith       if (size == 1) {
594b9ad928SBarry Smith         jac->n_local = jac->n;
609566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local,&jac->l_lens));
619566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens,jac->g_lens,jac->n_local));
624b9ad928SBarry Smith         /* check that user set these correctly */
634b9ad928SBarry Smith         sum = 0;
644b9ad928SBarry Smith         for (i=0; i<jac->n_local; i++) sum += jac->l_lens[i];
6508401ef6SPierre Jolivet         PetscCheck(sum == M,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Global lens set incorrectly");
664b9ad928SBarry Smith       } else {
679566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->pmat,&start,&end));
684b9ad928SBarry Smith         /* loop over blocks determing first one owned by me */
694b9ad928SBarry Smith         sum = 0;
704b9ad928SBarry Smith         for (i=0; i<jac->n+1; i++) {
714b9ad928SBarry Smith           if (sum == start) { i_start = i; goto start_1;}
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++) {
774b9ad928SBarry Smith           if (sum == end) { i_end = i; goto end_1; }
784b9ad928SBarry Smith           if (i < jac->n) sum += jac->g_lens[i];
794b9ad928SBarry Smith         }
80e7e72b3dSBarry Smith         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Block sizes used in PCBJacobiSetTotalBlocks()\nare not compatible with parallel matrix layout");
814b9ad928SBarry Smith end_1:
824b9ad928SBarry Smith         jac->n_local = i_end - i_start;
839566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(jac->n_local,&jac->l_lens));
849566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(jac->l_lens,jac->g_lens+i_start,jac->n_local));
854b9ad928SBarry Smith       }
864b9ad928SBarry Smith     } else { /* no global blocks given, determine then using default layout */
874b9ad928SBarry Smith       jac->n_local = jac->n/size + ((jac->n % size) > rank);
889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local,&jac->l_lens));
894b9ad928SBarry Smith       for (i=0; i<jac->n_local; i++) {
904b9ad928SBarry Smith         jac->l_lens[i] = ((M/bs)/jac->n_local + (((M/bs) % jac->n_local) > i))*bs;
917827d75bSBarry Smith         PetscCheck(jac->l_lens[i],PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Too many blocks given");
924b9ad928SBarry Smith       }
934b9ad928SBarry Smith     }
944b9ad928SBarry Smith   } else if (jac->n < 0 && jac->n_local < 0) { /* no blocks given */
954b9ad928SBarry Smith     jac->n         = size;
964b9ad928SBarry Smith     jac->n_local   = 1;
979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1,&jac->l_lens));
984b9ad928SBarry Smith     jac->l_lens[0] = M;
997271b979SBarry Smith   } else { /* jac->n > 0 && jac->n_local > 0 */
1007271b979SBarry Smith     if (!jac->l_lens) {
1019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(jac->n_local,&jac->l_lens));
1022fa5cd67SKarl 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));
1037271b979SBarry Smith     }
1044b9ad928SBarry Smith   }
10508401ef6SPierre Jolivet   PetscCheck(jac->n_local >= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of blocks is less than number of processors");
1064b9ad928SBarry Smith 
1075a7e1895SHong Zhang   /* -------------------------
1085a7e1895SHong Zhang       Determines mat and pmat
1095a7e1895SHong Zhang   ---------------------------*/
1109566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(pc->mat,MATOP_GET_DIAGONAL_BLOCK,&hasop));
111976e8c5aSLisandro Dalcin   if (!hasop && size == 1) {
1124b9ad928SBarry Smith     mat  = pc->mat;
1134b9ad928SBarry Smith     pmat = pc->pmat;
1144b9ad928SBarry Smith   } else {
11549517cdeSBarry Smith     if (pc->useAmat) {
11649517cdeSBarry Smith       /* use block from Amat matrix, not Pmat for local MatMult() */
1179566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->mat,&mat));
1184b9ad928SBarry Smith     }
11949517cdeSBarry Smith     if (pc->pmat != pc->mat || !pc->useAmat) {
1209566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonalBlock(pc->pmat,&pmat));
1212fa5cd67SKarl Rupp     } else pmat = mat;
1224b9ad928SBarry Smith   }
1234b9ad928SBarry Smith 
1244b9ad928SBarry Smith   /* ------
1254b9ad928SBarry Smith      Setup code depends on the number of blocks
1264b9ad928SBarry Smith   */
127cc1d6079SHong Zhang   if (jac->n_local == 1) {
1289566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Singleblock(pc,mat,pmat));
1294b9ad928SBarry Smith   } else {
1309566063dSJacob Faibussowitsch     PetscCall(PCSetUp_BJacobi_Multiblock(pc,mat,pmat));
1314b9ad928SBarry Smith   }
1324b9ad928SBarry Smith   PetscFunctionReturn(0);
1334b9ad928SBarry Smith }
1344b9ad928SBarry Smith 
1354b9ad928SBarry Smith /* Default destroy, if it has never been setup */
1366849ba73SBarry Smith static PetscErrorCode PCDestroy_BJacobi(PC pc)
1374b9ad928SBarry Smith {
1384b9ad928SBarry Smith   PC_BJacobi     *jac = (PC_BJacobi*)pc->data;
1394b9ad928SBarry Smith 
1404b9ad928SBarry Smith   PetscFunctionBegin;
1419566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
1429566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
143*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetSubKSP_C",NULL));
144*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetTotalBlocks_C",NULL));
145*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetTotalBlocks_C",NULL));
146*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetLocalBlocks_C",NULL));
147*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetLocalBlocks_C",NULL));
1489566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1494b9ad928SBarry Smith   PetscFunctionReturn(0);
1504b9ad928SBarry Smith }
1514b9ad928SBarry Smith 
1524416b707SBarry Smith static PetscErrorCode PCSetFromOptions_BJacobi(PetscOptionItems *PetscOptionsObject,PC pc)
1534b9ad928SBarry Smith {
1544b9ad928SBarry Smith   PC_BJacobi     *jac = (PC_BJacobi*)pc->data;
155248bfaf0SJed Brown   PetscInt       blocks,i;
156ace3abfcSBarry Smith   PetscBool      flg;
1574b9ad928SBarry Smith 
1584b9ad928SBarry Smith   PetscFunctionBegin;
159d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"Block Jacobi options");
1609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_blocks","Total number of blocks","PCBJacobiSetTotalBlocks",jac->n,&blocks,&flg));
1619566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetTotalBlocks(pc,blocks,NULL));
1629566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_local_blocks","Local number of blocks","PCBJacobiSetLocalBlocks",jac->n_local,&blocks,&flg));
1639566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetLocalBlocks(pc,blocks,NULL));
164248bfaf0SJed Brown   if (jac->ksp) {
165248bfaf0SJed Brown     /* The sub-KSP has already been set up (e.g., PCSetUp_BJacobi_Singleblock), but KSPSetFromOptions was not called
166248bfaf0SJed Brown      * unless we had already been called. */
167248bfaf0SJed Brown     for (i=0; i<jac->n_local; i++) {
1689566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->ksp[i]));
169248bfaf0SJed Brown     }
170248bfaf0SJed Brown   }
171d0609cedSBarry Smith   PetscOptionsHeadEnd();
1724b9ad928SBarry Smith   PetscFunctionReturn(0);
1734b9ad928SBarry Smith }
1744b9ad928SBarry Smith 
1759804daf3SBarry Smith #include <petscdraw.h>
1766849ba73SBarry Smith static PetscErrorCode PCView_BJacobi(PC pc,PetscViewer viewer)
1774b9ad928SBarry Smith {
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) {
19249517cdeSBarry Smith     if (pc->useAmat) {
19363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  using Amat local matrix, number of blocks = %" PetscInt_FMT "\n",jac->n));
1944b9ad928SBarry Smith     }
19563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  number of blocks = %" PetscInt_FMT "\n",jac->n));
1969566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank));
1979566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer,&format));
198020d6619SPierre Jolivet     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
1999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Local solver information for first block is in the following KSP and PC objects on rank 0:\n"));
2009566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc,&prefix));
2019566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Use -%sksp_view ::ascii_info_detail to display information for all blocks\n",prefix?prefix:""));
202933995ecSHong Zhang       if (jac->ksp && !jac->psubcomm) {
2039566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
204dd400576SPatrick Sanan         if (rank == 0) {
2059566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2069566063dSJacob Faibussowitsch           PetscCall(KSPView(jac->ksp[0],sviewer));
2079566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
2084b9ad928SBarry Smith         }
2099566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2109566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2119566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
212e4de9e1dSBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2139566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
214e4fa1014SBarry Smith       } else if (mpjac && jac->ksp && mpjac->psubcomm) {
2159566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer,mpjac->psubcomm->child,&sviewer));
216e4fa1014SBarry Smith         if (!mpjac->psubcomm->color) {
2179566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2189566063dSJacob Faibussowitsch           PetscCall(KSPView(*(jac->ksp),sviewer));
2199566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
220cbe18068SHong Zhang         }
2219566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2229566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer,mpjac->psubcomm->child,&sviewer));
2239566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
2249530cbd7SBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2259566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2264b9ad928SBarry Smith       } else {
2279566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
228e4de9e1dSBarry Smith       }
229e4de9e1dSBarry Smith     } else {
2304814766eSBarry Smith       PetscInt n_global;
2311c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&jac->n_local,&n_global,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)pc)));
2329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Local solver information for each block is in the following KSP and PC objects:\n"));
23463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"[%d] number of local blocks = %" PetscInt_FMT ", first local block number = %" PetscInt_FMT "\n",
23563a3b9bcSJacob Faibussowitsch                                                    rank,jac->n_local,jac->first_local));
2369566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2379566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
238dd2fa690SBarry Smith       for (i=0; i<jac->n_local; i++) {
23963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"[%d] local block number %" PetscInt_FMT "\n",rank,i));
2409566063dSJacob Faibussowitsch         PetscCall(KSPView(jac->ksp[i],sviewer));
2419566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n"));
2424b9ad928SBarry Smith       }
2439566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2449566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
2459566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
2469566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2474b9ad928SBarry Smith     }
2484b9ad928SBarry Smith   } else if (isstring) {
24963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer," blks=%" PetscInt_FMT,jac->n));
2509566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2519566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0],sviewer));
2529566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
253d9884438SBarry Smith   } else if (isdraw) {
254d9884438SBarry Smith     PetscDraw draw;
255d9884438SBarry Smith     char      str[25];
256d9884438SBarry Smith     PetscReal x,y,bottom,h;
257d9884438SBarry Smith 
2589566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
2599566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw,&x,&y));
26063a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str,25,"Number blocks %" PetscInt_FMT,jac->n));
2619566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h));
262d9884438SBarry Smith     bottom = y - h;
2639566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw,x,bottom));
264d9884438SBarry Smith     /* warning the communicator on viewer is different then on ksp in parallel */
2659566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0],viewer));
2669566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2674b9ad928SBarry Smith   }
2684b9ad928SBarry Smith   PetscFunctionReturn(0);
2694b9ad928SBarry Smith }
2704b9ad928SBarry Smith 
2714b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
2724b9ad928SBarry Smith 
2731e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetSubKSP_BJacobi(PC pc,PetscInt *n_local,PetscInt *first_local,KSP **ksp)
2744b9ad928SBarry Smith {
275feb237baSPierre Jolivet   PC_BJacobi *jac = (PC_BJacobi*)pc->data;
2764b9ad928SBarry Smith 
2774b9ad928SBarry Smith   PetscFunctionBegin;
27828b400f6SJacob Faibussowitsch   PetscCheck(pc->setupcalled,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call KSPSetUp() or PCSetUp() first");
2794b9ad928SBarry Smith 
2804b9ad928SBarry Smith   if (n_local) *n_local = jac->n_local;
2814b9ad928SBarry Smith   if (first_local) *first_local = jac->first_local;
282020d6619SPierre Jolivet   if (ksp) *ksp                 = jac->ksp;
2834b9ad928SBarry Smith   PetscFunctionReturn(0);
2844b9ad928SBarry Smith }
2854b9ad928SBarry Smith 
2861e6b0712SBarry Smith static PetscErrorCode  PCBJacobiSetTotalBlocks_BJacobi(PC pc,PetscInt blocks,PetscInt *lens)
2874b9ad928SBarry Smith {
2884b9ad928SBarry Smith   PC_BJacobi     *jac = (PC_BJacobi*)pc->data;
2894b9ad928SBarry Smith 
2904b9ad928SBarry Smith   PetscFunctionBegin;
2912472a847SBarry 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");
2924b9ad928SBarry Smith   jac->n = blocks;
2930a545947SLisandro Dalcin   if (!lens) jac->g_lens = NULL;
2942fa5cd67SKarl Rupp   else {
2959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks,&jac->g_lens));
2969566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject)pc,blocks*sizeof(PetscInt)));
2979566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->g_lens,lens,blocks));
2984b9ad928SBarry Smith   }
2994b9ad928SBarry Smith   PetscFunctionReturn(0);
3004b9ad928SBarry Smith }
3014b9ad928SBarry Smith 
3021e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetTotalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
3034b9ad928SBarry Smith {
3044b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi*) pc->data;
3054b9ad928SBarry Smith 
3064b9ad928SBarry Smith   PetscFunctionBegin;
3074b9ad928SBarry Smith   *blocks = jac->n;
3084b9ad928SBarry Smith   if (lens) *lens = jac->g_lens;
3094b9ad928SBarry Smith   PetscFunctionReturn(0);
3104b9ad928SBarry Smith }
3114b9ad928SBarry Smith 
3121e6b0712SBarry Smith static PetscErrorCode  PCBJacobiSetLocalBlocks_BJacobi(PC pc,PetscInt blocks,const PetscInt lens[])
3134b9ad928SBarry Smith {
3144b9ad928SBarry Smith   PC_BJacobi     *jac;
3154b9ad928SBarry Smith 
3164b9ad928SBarry Smith   PetscFunctionBegin;
3174b9ad928SBarry Smith   jac = (PC_BJacobi*)pc->data;
3184b9ad928SBarry Smith 
3194b9ad928SBarry Smith   jac->n_local = blocks;
3200a545947SLisandro Dalcin   if (!lens) jac->l_lens = NULL;
3212fa5cd67SKarl Rupp   else {
3229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks,&jac->l_lens));
3239566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject)pc,blocks*sizeof(PetscInt)));
3249566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->l_lens,lens,blocks));
3254b9ad928SBarry Smith   }
3264b9ad928SBarry Smith   PetscFunctionReturn(0);
3274b9ad928SBarry Smith }
3284b9ad928SBarry Smith 
3291e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetLocalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
3304b9ad928SBarry Smith {
3314b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi*) pc->data;
3324b9ad928SBarry Smith 
3334b9ad928SBarry Smith   PetscFunctionBegin;
3344b9ad928SBarry Smith   *blocks = jac->n_local;
3354b9ad928SBarry Smith   if (lens) *lens = jac->l_lens;
3364b9ad928SBarry Smith   PetscFunctionReturn(0);
3374b9ad928SBarry Smith }
3384b9ad928SBarry Smith 
3394b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
3404b9ad928SBarry Smith 
3414b9ad928SBarry Smith /*@C
3424b9ad928SBarry Smith    PCBJacobiGetSubKSP - Gets the local KSP contexts for all blocks on
3434b9ad928SBarry Smith    this processor.
3444b9ad928SBarry Smith 
3456da92b7fSHong Zhang    Not Collective
3464b9ad928SBarry Smith 
3474b9ad928SBarry Smith    Input Parameter:
3484b9ad928SBarry Smith .  pc - the preconditioner context
3494b9ad928SBarry Smith 
3504b9ad928SBarry Smith    Output Parameters:
3510298fd71SBarry Smith +  n_local - the number of blocks on this processor, or NULL
3520298fd71SBarry Smith .  first_local - the global number of the first block on this processor, or NULL
3534b9ad928SBarry Smith -  ksp - the array of KSP contexts
3544b9ad928SBarry Smith 
3554b9ad928SBarry Smith    Notes:
3564b9ad928SBarry Smith    After PCBJacobiGetSubKSP() the array of KSP contexts is not to be freed.
3574b9ad928SBarry Smith 
3584b9ad928SBarry Smith    Currently for some matrix implementations only 1 block per processor
3594b9ad928SBarry Smith    is supported.
3604b9ad928SBarry Smith 
3614b9ad928SBarry Smith    You must call KSPSetUp() or PCSetUp() before calling PCBJacobiGetSubKSP().
3624b9ad928SBarry Smith 
363196cc216SBarry Smith    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
3642bf68e3eSBarry Smith       You can call PCBJacobiGetSubKSP(pc,nlocal,firstlocal,PETSC_NULL_KSP,ierr) to determine how large the
365196cc216SBarry Smith       KSP array must be.
366196cc216SBarry Smith 
3674b9ad928SBarry Smith    Level: advanced
3684b9ad928SBarry Smith 
369db781477SPatrick Sanan .seealso: `PCASMGetSubKSP()`
3704b9ad928SBarry Smith @*/
3717087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[])
3724b9ad928SBarry Smith {
3734b9ad928SBarry Smith   PetscFunctionBegin;
3740700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
375cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));
3764b9ad928SBarry Smith   PetscFunctionReturn(0);
3774b9ad928SBarry Smith }
3784b9ad928SBarry Smith 
3794b9ad928SBarry Smith /*@
3804b9ad928SBarry Smith    PCBJacobiSetTotalBlocks - Sets the global number of blocks for the block
3814b9ad928SBarry Smith    Jacobi preconditioner.
3824b9ad928SBarry Smith 
3834b9ad928SBarry Smith    Collective on PC
3844b9ad928SBarry Smith 
3854b9ad928SBarry Smith    Input Parameters:
3864b9ad928SBarry Smith +  pc - the preconditioner context
3874b9ad928SBarry Smith .  blocks - the number of blocks
3884b9ad928SBarry Smith -  lens - [optional] integer array containing the size of each block
3894b9ad928SBarry Smith 
3904b9ad928SBarry Smith    Options Database Key:
3914b9ad928SBarry Smith .  -pc_bjacobi_blocks <blocks> - Sets the number of global blocks
3924b9ad928SBarry Smith 
3934b9ad928SBarry Smith    Notes:
3944b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
3954b9ad928SBarry Smith    All processors sharing the PC must call this routine with the same data.
3964b9ad928SBarry Smith 
3974b9ad928SBarry Smith    Level: intermediate
3984b9ad928SBarry Smith 
399db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiSetLocalBlocks()`
4004b9ad928SBarry Smith @*/
4017087cfbeSBarry Smith PetscErrorCode  PCBJacobiSetTotalBlocks(PC pc,PetscInt blocks,const PetscInt lens[])
4024b9ad928SBarry Smith {
4034b9ad928SBarry Smith   PetscFunctionBegin;
4040700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
40508401ef6SPierre Jolivet   PetscCheck(blocks > 0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Must have positive blocks");
406cac4c232SBarry Smith   PetscTryMethod(pc,"PCBJacobiSetTotalBlocks_C",(PC,PetscInt,const PetscInt[]),(pc,blocks,lens));
4074b9ad928SBarry Smith   PetscFunctionReturn(0);
4084b9ad928SBarry Smith }
4094b9ad928SBarry Smith 
4104b9ad928SBarry Smith /*@C
4114b9ad928SBarry Smith    PCBJacobiGetTotalBlocks - Gets the global number of blocks for the block
4124b9ad928SBarry Smith    Jacobi preconditioner.
4134b9ad928SBarry Smith 
414ad4df100SBarry Smith    Not Collective
4154b9ad928SBarry Smith 
4164b9ad928SBarry Smith    Input Parameter:
4174b9ad928SBarry Smith .  pc - the preconditioner context
4184b9ad928SBarry Smith 
4194b9ad928SBarry Smith    Output parameters:
4204b9ad928SBarry Smith +  blocks - the number of blocks
4214b9ad928SBarry Smith -  lens - integer array containing the size of each block
4224b9ad928SBarry Smith 
4234b9ad928SBarry Smith    Level: intermediate
4244b9ad928SBarry Smith 
425db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiGetLocalBlocks()`
4264b9ad928SBarry Smith @*/
4277087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetTotalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
4284b9ad928SBarry Smith {
4294b9ad928SBarry Smith   PetscFunctionBegin;
4300700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID,1);
4314482741eSBarry Smith   PetscValidIntPointer(blocks,2);
432cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetTotalBlocks_C",(PC,PetscInt*, const PetscInt *[]),(pc,blocks,lens));
4334b9ad928SBarry Smith   PetscFunctionReturn(0);
4344b9ad928SBarry Smith }
4354b9ad928SBarry Smith 
4364b9ad928SBarry Smith /*@
4374b9ad928SBarry Smith    PCBJacobiSetLocalBlocks - Sets the local number of blocks for the block
4384b9ad928SBarry Smith    Jacobi preconditioner.
4394b9ad928SBarry Smith 
4404b9ad928SBarry Smith    Not Collective
4414b9ad928SBarry Smith 
4424b9ad928SBarry Smith    Input Parameters:
4434b9ad928SBarry Smith +  pc - the preconditioner context
4444b9ad928SBarry Smith .  blocks - the number of blocks
4454b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4464b9ad928SBarry Smith 
447342c94f9SMatthew G. Knepley    Options Database Key:
448342c94f9SMatthew G. Knepley .  -pc_bjacobi_local_blocks <blocks> - Sets the number of local blocks
449342c94f9SMatthew G. Knepley 
4504b9ad928SBarry Smith    Note:
4514b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4524b9ad928SBarry Smith 
4534b9ad928SBarry Smith    Level: intermediate
4544b9ad928SBarry Smith 
455db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiSetTotalBlocks()`
4564b9ad928SBarry Smith @*/
4577087cfbeSBarry Smith PetscErrorCode  PCBJacobiSetLocalBlocks(PC pc,PetscInt blocks,const PetscInt lens[])
4584b9ad928SBarry Smith {
4594b9ad928SBarry Smith   PetscFunctionBegin;
4600700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
46108401ef6SPierre Jolivet   PetscCheck(blocks >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have nonegative blocks");
462cac4c232SBarry Smith   PetscTryMethod(pc,"PCBJacobiSetLocalBlocks_C",(PC,PetscInt,const PetscInt []),(pc,blocks,lens));
4634b9ad928SBarry Smith   PetscFunctionReturn(0);
4644b9ad928SBarry Smith }
4654b9ad928SBarry Smith 
4664b9ad928SBarry Smith /*@C
4674b9ad928SBarry Smith    PCBJacobiGetLocalBlocks - Gets the local number of blocks for the block
4684b9ad928SBarry Smith    Jacobi preconditioner.
4694b9ad928SBarry Smith 
4704b9ad928SBarry Smith    Not Collective
4714b9ad928SBarry Smith 
4724b9ad928SBarry Smith    Input Parameters:
4734b9ad928SBarry Smith +  pc - the preconditioner context
4744b9ad928SBarry Smith .  blocks - the number of blocks
4754b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4764b9ad928SBarry Smith 
4774b9ad928SBarry Smith    Note:
4784b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4794b9ad928SBarry Smith 
4804b9ad928SBarry Smith    Level: intermediate
4814b9ad928SBarry Smith 
482db781477SPatrick Sanan .seealso: `PCSetUseAmat()`, `PCBJacobiGetTotalBlocks()`
4834b9ad928SBarry Smith @*/
4847087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetLocalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
4854b9ad928SBarry Smith {
4864b9ad928SBarry Smith   PetscFunctionBegin;
4870700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID,1);
4884482741eSBarry Smith   PetscValidIntPointer(blocks,2);
489cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetLocalBlocks_C",(PC,PetscInt*, const PetscInt *[]),(pc,blocks,lens));
4904b9ad928SBarry Smith   PetscFunctionReturn(0);
4914b9ad928SBarry Smith }
4924b9ad928SBarry Smith 
4934b9ad928SBarry Smith /* -----------------------------------------------------------------------------------*/
4944b9ad928SBarry Smith 
4954b9ad928SBarry Smith /*MC
4964b9ad928SBarry Smith    PCBJACOBI - Use block Jacobi preconditioning, each block is (approximately) solved with
4974b9ad928SBarry Smith            its own KSP object.
4984b9ad928SBarry Smith 
4994b9ad928SBarry Smith    Options Database Keys:
500011ea8aeSBarry Smith +  -pc_use_amat - use Amat to apply block of operator in inner Krylov method
501011ea8aeSBarry Smith -  -pc_bjacobi_blocks <n> - use n total blocks
5024b9ad928SBarry Smith 
50395452b02SPatrick Sanan    Notes:
504468ae2e8SBarry Smith     See PCJACOBI for diagonal Jacobi, PCVPBJACOBI for variable point block, and PCPBJACOBI for fixed size point block
505468ae2e8SBarry Smith 
50695452b02SPatrick 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.
5074b9ad928SBarry Smith 
5084b9ad928SBarry Smith      To set options on the solvers for each block append -sub_ to all the KSP, KSP, and PC
509d7ee0231SBarry Smith         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
5104b9ad928SBarry Smith 
511a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCBJacobiGetSubKSP()
5124b9ad928SBarry Smith          and set the options directly on the resulting KSP object (you can access its PC
5134b9ad928SBarry Smith          KSPGetPC())
5144b9ad928SBarry Smith 
515e9e886b6SKarl Rupp      For GPU-based vectors (CUDA, ViennaCL) it is recommended to use exactly one block per MPI process for best
5162210c163SDominic Meiser          performance.  Different block partitioning may lead to additional data transfers
5172210c163SDominic Meiser          between host and GPU that lead to degraded performance.
5182210c163SDominic Meiser 
519011ea8aeSBarry Smith      The options prefix for each block is sub_, for example -sub_pc_type lu.
520011ea8aeSBarry Smith 
521011ea8aeSBarry Smith      When multiple processes share a single block, each block encompasses exactly all the unknowns owned its set of processes.
522011ea8aeSBarry Smith 
52390dfcc32SBarry Smith      See PCJACOBI for point Jacobi preconditioning, PCVPBJACOBI for variable size point block Jacobi and PCPBJACOBI for large blocks
52490dfcc32SBarry Smith 
5254b9ad928SBarry Smith    Level: beginner
5264b9ad928SBarry Smith 
527db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
528db781477SPatrick Sanan           `PCASM`, `PCSetUseAmat()`, `PCGetUseAmat()`, `PCBJacobiGetSubKSP()`, `PCBJacobiSetTotalBlocks()`,
529db781477SPatrick Sanan           `PCBJacobiSetLocalBlocks()`, `PCSetModifySubMatrices()`, `PCJACOBI`, `PCVPBJACOBI`, `PCPBJACOBI`
5304b9ad928SBarry Smith M*/
5314b9ad928SBarry Smith 
5328cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_BJacobi(PC pc)
5334b9ad928SBarry Smith {
53469a612a9SBarry Smith   PetscMPIInt    rank;
5354b9ad928SBarry Smith   PC_BJacobi     *jac;
5364b9ad928SBarry Smith 
5374b9ad928SBarry Smith   PetscFunctionBegin;
5389566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc,&jac));
5399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank));
5402fa5cd67SKarl Rupp 
5410a545947SLisandro Dalcin   pc->ops->apply           = NULL;
5427b6e2003SPierre Jolivet   pc->ops->matapply        = NULL;
5430a545947SLisandro Dalcin   pc->ops->applytranspose  = NULL;
5444b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_BJacobi;
5454b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_BJacobi;
5464b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_BJacobi;
5474b9ad928SBarry Smith   pc->ops->view            = PCView_BJacobi;
5480a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5494b9ad928SBarry Smith 
5504b9ad928SBarry Smith   pc->data               = (void*)jac;
5514b9ad928SBarry Smith   jac->n                 = -1;
5524b9ad928SBarry Smith   jac->n_local           = -1;
5534b9ad928SBarry Smith   jac->first_local       = rank;
5540a545947SLisandro Dalcin   jac->ksp               = NULL;
5550a545947SLisandro Dalcin   jac->g_lens            = NULL;
5560a545947SLisandro Dalcin   jac->l_lens            = NULL;
5570a545947SLisandro Dalcin   jac->psubcomm          = NULL;
5584b9ad928SBarry Smith 
5599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetSubKSP_C",PCBJacobiGetSubKSP_BJacobi));
5609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetTotalBlocks_C",PCBJacobiSetTotalBlocks_BJacobi));
5619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetTotalBlocks_C",PCBJacobiGetTotalBlocks_BJacobi));
5629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetLocalBlocks_C",PCBJacobiSetLocalBlocks_BJacobi));
5639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetLocalBlocks_C",PCBJacobiGetLocalBlocks_BJacobi));
5644b9ad928SBarry Smith   PetscFunctionReturn(0);
5654b9ad928SBarry Smith }
5664b9ad928SBarry Smith 
5674b9ad928SBarry Smith /* --------------------------------------------------------------------------------------------*/
5684b9ad928SBarry Smith /*
5694b9ad928SBarry Smith         These are for a single block per processor; works for AIJ, BAIJ; Seq and MPI
5704b9ad928SBarry Smith */
57181f0254dSBarry Smith static PetscErrorCode PCReset_BJacobi_Singleblock(PC pc)
5724b9ad928SBarry Smith {
5734b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
5744b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
5754b9ad928SBarry Smith 
5764b9ad928SBarry Smith   PetscFunctionBegin;
5779566063dSJacob Faibussowitsch   PetscCall(KSPReset(jac->ksp[0]));
5789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->x));
5799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->y));
580e91c6855SBarry Smith   PetscFunctionReturn(0);
581e91c6855SBarry Smith }
582e91c6855SBarry Smith 
58381f0254dSBarry Smith static PetscErrorCode PCDestroy_BJacobi_Singleblock(PC pc)
584e91c6855SBarry Smith {
585e91c6855SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
586e91c6855SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
587e91c6855SBarry Smith 
588e91c6855SBarry Smith   PetscFunctionBegin;
5899566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Singleblock(pc));
5909566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
5919566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
5929566063dSJacob Faibussowitsch   PetscCall(PetscFree(bjac));
593*2e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
5944b9ad928SBarry Smith   PetscFunctionReturn(0);
5954b9ad928SBarry Smith }
5964b9ad928SBarry Smith 
59781f0254dSBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Singleblock(PC pc)
5984b9ad928SBarry Smith {
5994b9ad928SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
6002295b7c8SHong Zhang   KSP                subksp = jac->ksp[0];
601539c167fSBarry Smith   KSPConvergedReason reason;
6024b9ad928SBarry Smith 
6034b9ad928SBarry Smith   PetscFunctionBegin;
6049566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
6059566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp,&reason));
606c0decd05SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
607261222b2SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
6082295b7c8SHong Zhang   }
6094b9ad928SBarry Smith   PetscFunctionReturn(0);
6104b9ad928SBarry Smith }
6114b9ad928SBarry Smith 
61281f0254dSBarry Smith static PetscErrorCode PCApply_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6134b9ad928SBarry Smith {
6144b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6154b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
6166e111a19SKarl Rupp 
6174b9ad928SBarry Smith   PetscFunctionBegin;
6189566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVectorRead(x, bjac->x));
6199566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVector(y, bjac->y));
620bba28a21SBarry Smith   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
621910cf402Sprj-      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
622910cf402Sprj-      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(KSPSolve(jac->ksp[0],bjac->x,bjac->y));
6259566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,bjac->y));
6269566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVectorRead(x, bjac->x));
6279566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVector(y, bjac->y));
6284b9ad928SBarry Smith   PetscFunctionReturn(0);
6294b9ad928SBarry Smith }
6304b9ad928SBarry Smith 
6317b6e2003SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Singleblock(PC pc,Mat X,Mat Y)
6327b6e2003SPierre Jolivet {
6337b6e2003SPierre Jolivet   PC_BJacobi     *jac  = (PC_BJacobi*)pc->data;
6347b6e2003SPierre Jolivet   Mat            sX,sY;
6357b6e2003SPierre Jolivet 
6367b6e2003SPierre Jolivet   PetscFunctionBegin;
6377b6e2003SPierre Jolivet   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
6387b6e2003SPierre Jolivet      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
6397b6e2003SPierre Jolivet      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6409566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0],pc->reusepreconditioner));
6419566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(X,&sX));
6429566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Y,&sY));
6439566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0],sX,sY));
6447b6e2003SPierre Jolivet   PetscFunctionReturn(0);
6457b6e2003SPierre Jolivet }
6467b6e2003SPierre Jolivet 
64781f0254dSBarry Smith static PetscErrorCode PCApplySymmetricLeft_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6484b9ad928SBarry Smith {
6494b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6504b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
651d9ca1df4SBarry Smith   PetscScalar            *y_array;
652d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6534b9ad928SBarry Smith   PC                     subpc;
6544b9ad928SBarry Smith 
6554b9ad928SBarry Smith   PetscFunctionBegin;
6564b9ad928SBarry Smith   /*
6574b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6584b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6594b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6604b9ad928SBarry Smith     for the sequential solve.
6614b9ad928SBarry Smith   */
6629566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
6639566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
6649566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
6659566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
6664b9ad928SBarry Smith   /* apply the symmetric left portion of the inner PC operator */
6674b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6689566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0],&subpc));
6699566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricLeft(subpc,bjac->x,bjac->y));
6709566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
6719566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
6729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
6739566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
6744b9ad928SBarry Smith   PetscFunctionReturn(0);
6754b9ad928SBarry Smith }
6764b9ad928SBarry Smith 
67781f0254dSBarry Smith static PetscErrorCode PCApplySymmetricRight_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6784b9ad928SBarry Smith {
6794b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6804b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
681d9ca1df4SBarry Smith   PetscScalar            *y_array;
682d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6834b9ad928SBarry Smith   PC                     subpc;
6844b9ad928SBarry Smith 
6854b9ad928SBarry Smith   PetscFunctionBegin;
6864b9ad928SBarry Smith   /*
6874b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6884b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6894b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6904b9ad928SBarry Smith     for the sequential solve.
6914b9ad928SBarry Smith   */
6929566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
6939566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
6949566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
6959566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
6964b9ad928SBarry Smith 
6974b9ad928SBarry Smith   /* apply the symmetric right portion of the inner PC operator */
6984b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6994b9ad928SBarry Smith 
7009566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0],&subpc));
7019566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricRight(subpc,bjac->x,bjac->y));
7024b9ad928SBarry Smith 
7039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
7049566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
7054b9ad928SBarry Smith   PetscFunctionReturn(0);
7064b9ad928SBarry Smith }
7074b9ad928SBarry Smith 
70881f0254dSBarry Smith static PetscErrorCode PCApplyTranspose_BJacobi_Singleblock(PC pc,Vec x,Vec y)
7094b9ad928SBarry Smith {
7104b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
7114b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
712d9ca1df4SBarry Smith   PetscScalar            *y_array;
713d9ca1df4SBarry Smith   const PetscScalar      *x_array;
7144b9ad928SBarry Smith 
7154b9ad928SBarry Smith   PetscFunctionBegin;
7164b9ad928SBarry Smith   /*
7174b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
7184b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
7194b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
7204b9ad928SBarry Smith     for the sequential solve.
7214b9ad928SBarry Smith   */
7229566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
7239566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
7249566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
7259566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
7269566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(jac->ksp[0],bjac->x,bjac->y));
7279566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,bjac->y));
7289566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
7299566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
7309566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
7319566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
7324b9ad928SBarry Smith   PetscFunctionReturn(0);
7334b9ad928SBarry Smith }
7344b9ad928SBarry Smith 
7356849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC pc,Mat mat,Mat pmat)
7364b9ad928SBarry Smith {
7374b9ad928SBarry Smith   PC_BJacobi             *jac = (PC_BJacobi*)pc->data;
73869a612a9SBarry Smith   PetscInt               m;
7394b9ad928SBarry Smith   KSP                    ksp;
7404b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac;
741de0953f6SBarry Smith   PetscBool              wasSetup = PETSC_TRUE;
7423f6dc190SJunchao Zhang   VecType                vectype;
743ea41da7aSPierre Jolivet   const char             *prefix;
7444b9ad928SBarry Smith 
7454b9ad928SBarry Smith   PetscFunctionBegin;
7464b9ad928SBarry Smith   if (!pc->setupcalled) {
747c2efdce3SBarry Smith     if (!jac->ksp) {
748302a9ddcSMatthew Knepley       wasSetup = PETSC_FALSE;
7492fa5cd67SKarl Rupp 
7509566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF,&ksp));
7519566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ksp,pc->erroriffailure));
7529566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1));
7539566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ksp));
7549566063dSJacob Faibussowitsch       PetscCall(KSPSetType(ksp,KSPPREONLY));
7559566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc,&prefix));
7569566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp,prefix));
7579566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ksp,"sub_"));
7584b9ad928SBarry Smith 
759e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Singleblock;
7604b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Singleblock;
7614b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Singleblock;
7627b6e2003SPierre Jolivet       pc->ops->matapply            = PCMatApply_BJacobi_Singleblock;
7634b9ad928SBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Singleblock;
7644b9ad928SBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Singleblock;
7654b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Singleblock;
7664b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Singleblock;
7674b9ad928SBarry Smith 
7689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1,&jac->ksp));
7694b9ad928SBarry Smith       jac->ksp[0] = ksp;
770c2efdce3SBarry Smith 
7719566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc,&bjac));
7724b9ad928SBarry Smith       jac->data = (void*)bjac;
7734b9ad928SBarry Smith     } else {
774c2efdce3SBarry Smith       ksp  = jac->ksp[0];
775c2efdce3SBarry Smith       bjac = (PC_BJacobi_Singleblock*)jac->data;
776c2efdce3SBarry Smith     }
777c2efdce3SBarry Smith 
778c2efdce3SBarry Smith     /*
779c2efdce3SBarry Smith       The reason we need to generate these vectors is to serve
780c2efdce3SBarry Smith       as the right-hand side and solution vector for the solve on the
781c2efdce3SBarry Smith       block. We do not need to allocate space for the vectors since
782c2efdce3SBarry Smith       that is provided via VecPlaceArray() just before the call to
783c2efdce3SBarry Smith       KSPSolve() on the block.
784c2efdce3SBarry Smith     */
7859566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pmat,&m,&m));
7869566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&bjac->x));
7879566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&bjac->y));
7889566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat,&vectype));
7899566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->x,vectype));
7909566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->y,vectype));
7919566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->x));
7929566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->y));
793c2efdce3SBarry Smith   } else {
7944b9ad928SBarry Smith     ksp  = jac->ksp[0];
7954b9ad928SBarry Smith     bjac = (PC_BJacobi_Singleblock*)jac->data;
7964b9ad928SBarry Smith   }
7979566063dSJacob Faibussowitsch   PetscCall(KSPGetOptionsPrefix(ksp,&prefix));
79849517cdeSBarry Smith   if (pc->useAmat) {
7999566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp,mat,pmat));
8009566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mat,prefix));
8014b9ad928SBarry Smith   } else {
8029566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp,pmat,pmat));
8034b9ad928SBarry Smith   }
8049566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(pmat,prefix));
80590f1c854SHong Zhang   if (!wasSetup && pc->setfromoptionscalled) {
806248bfaf0SJed Brown     /* If PCSetFromOptions_BJacobi is called later, KSPSetFromOptions will be called at that time. */
8079566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ksp));
808302a9ddcSMatthew Knepley   }
8094b9ad928SBarry Smith   PetscFunctionReturn(0);
8104b9ad928SBarry Smith }
8114b9ad928SBarry Smith 
8124b9ad928SBarry Smith /* ---------------------------------------------------------------------------------------------*/
81381f0254dSBarry Smith static PetscErrorCode PCReset_BJacobi_Multiblock(PC pc)
8144b9ad928SBarry Smith {
8154b9ad928SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi*)pc->data;
8164b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
81769a612a9SBarry Smith   PetscInt              i;
8184b9ad928SBarry Smith 
8194b9ad928SBarry Smith   PetscFunctionBegin;
820e91c6855SBarry Smith   if (bjac && bjac->pmat) {
8219566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->n_local,&bjac->pmat));
82249517cdeSBarry Smith     if (pc->useAmat) {
8239566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(jac->n_local,&bjac->mat));
8244b9ad928SBarry Smith     }
825e91c6855SBarry Smith   }
8264b9ad928SBarry Smith 
8274b9ad928SBarry Smith   for (i=0; i<jac->n_local; i++) {
8289566063dSJacob Faibussowitsch     PetscCall(KSPReset(jac->ksp[i]));
829e91c6855SBarry Smith     if (bjac && bjac->x) {
8309566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->x[i]));
8319566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->y[i]));
8329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&bjac->is[i]));
8334b9ad928SBarry Smith     }
834e91c6855SBarry Smith   }
8359566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
8369566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
837e91c6855SBarry Smith   PetscFunctionReturn(0);
838e91c6855SBarry Smith }
839e91c6855SBarry Smith 
84081f0254dSBarry Smith static PetscErrorCode PCDestroy_BJacobi_Multiblock(PC pc)
841e91c6855SBarry Smith {
842e91c6855SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi*)pc->data;
843c2efdce3SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
844e91c6855SBarry Smith   PetscInt              i;
845e91c6855SBarry Smith 
846e91c6855SBarry Smith   PetscFunctionBegin;
8479566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiblock(pc));
848c2efdce3SBarry Smith   if (bjac) {
8499566063dSJacob Faibussowitsch     PetscCall(PetscFree2(bjac->x,bjac->y));
8509566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->starts));
8519566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->is));
852c2efdce3SBarry Smith   }
8539566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->data));
854e91c6855SBarry Smith   for (i=0; i<jac->n_local; i++) {
8559566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&jac->ksp[i]));
856e91c6855SBarry Smith   }
8579566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
858*2e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
8594b9ad928SBarry Smith   PetscFunctionReturn(0);
8604b9ad928SBarry Smith }
8614b9ad928SBarry Smith 
86281f0254dSBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiblock(PC pc)
8634b9ad928SBarry Smith {
8644b9ad928SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
86569a612a9SBarry Smith   PetscInt           i,n_local = jac->n_local;
866539c167fSBarry Smith   KSPConvergedReason reason;
8674b9ad928SBarry Smith 
8684b9ad928SBarry Smith   PetscFunctionBegin;
8694b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
8709566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(jac->ksp[i]));
8719566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(jac->ksp[i],&reason));
872c0decd05SBarry Smith     if (reason == KSP_DIVERGED_PC_FAILED) {
873261222b2SHong Zhang       pc->failedreason = PC_SUBPC_ERROR;
8742295b7c8SHong Zhang     }
8754b9ad928SBarry Smith   }
8764b9ad928SBarry Smith   PetscFunctionReturn(0);
8774b9ad928SBarry Smith }
8784b9ad928SBarry Smith 
8794b9ad928SBarry Smith /*
8804b9ad928SBarry Smith       Preconditioner for block Jacobi
8814b9ad928SBarry Smith */
88281f0254dSBarry Smith static PetscErrorCode PCApply_BJacobi_Multiblock(PC pc,Vec x,Vec y)
8834b9ad928SBarry Smith {
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;
88958ebbce7SBarry 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_ApplyOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
9039566063dSJacob Faibussowitsch     PetscCall(KSPSolve(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_ApplyOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
906d11f3a42SBarry Smith 
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 
9154b9ad928SBarry Smith /*
9164b9ad928SBarry Smith       Preconditioner for block Jacobi
9174b9ad928SBarry Smith */
91881f0254dSBarry Smith static PetscErrorCode PCApplyTranspose_BJacobi_Multiblock(PC pc,Vec x,Vec y)
9194b9ad928SBarry Smith {
9204b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi*)pc->data;
92169a612a9SBarry Smith   PetscInt              i,n_local = jac->n_local;
9224b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
923d9ca1df4SBarry Smith   PetscScalar           *yin;
924d9ca1df4SBarry Smith   const PetscScalar     *xin;
9254b9ad928SBarry Smith 
9264b9ad928SBarry Smith   PetscFunctionBegin;
9279566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&xin));
9289566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&yin));
9294b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
9304b9ad928SBarry Smith     /*
9314b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
9324b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
9334b9ad928SBarry Smith        the global vector.
9344b9ad928SBarry Smith     */
9359566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i],xin+bjac->starts[i]));
9369566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i],yin+bjac->starts[i]));
9374b9ad928SBarry Smith 
9389566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
9399566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(jac->ksp[i],bjac->x[i],bjac->y[i]));
9409566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i],pc,bjac->y[i]));
9419566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
942a7ff49e8SJed Brown 
9439566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9449566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9454b9ad928SBarry Smith   }
9469566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&xin));
9479566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&yin));
9484b9ad928SBarry Smith   PetscFunctionReturn(0);
9494b9ad928SBarry Smith }
9504b9ad928SBarry Smith 
9516849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC pc,Mat mat,Mat pmat)
9524b9ad928SBarry Smith {
9534b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi*)pc->data;
95469a612a9SBarry Smith   PetscInt              m,n_local,N,M,start,i;
955ea41da7aSPierre Jolivet   const char            *prefix;
9564b9ad928SBarry Smith   KSP                   ksp;
9574b9ad928SBarry Smith   Vec                   x,y;
9584b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
9594b9ad928SBarry Smith   PC                    subpc;
9604b9ad928SBarry Smith   IS                    is;
961434a97beSBrad Aagaard   MatReuse              scall;
9623f6dc190SJunchao Zhang   VecType               vectype;
9634b9ad928SBarry Smith 
9644b9ad928SBarry Smith   PetscFunctionBegin;
9659566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat,&M,&N));
9664b9ad928SBarry Smith 
9674b9ad928SBarry Smith   n_local = jac->n_local;
9684b9ad928SBarry Smith 
96949517cdeSBarry Smith   if (pc->useAmat) {
970ace3abfcSBarry Smith     PetscBool same;
9719566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat,((PetscObject)pmat)->type_name,&same));
97228b400f6SJacob Faibussowitsch     PetscCheck(same,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Matrices not of same type");
9734b9ad928SBarry Smith   }
9744b9ad928SBarry Smith 
9754b9ad928SBarry Smith   if (!pc->setupcalled) {
9764b9ad928SBarry Smith     scall = MAT_INITIAL_MATRIX;
977c2efdce3SBarry Smith 
978c2efdce3SBarry Smith     if (!jac->ksp) {
979e91c6855SBarry Smith       pc->ops->reset         = PCReset_BJacobi_Multiblock;
9804b9ad928SBarry Smith       pc->ops->destroy       = PCDestroy_BJacobi_Multiblock;
9814b9ad928SBarry Smith       pc->ops->apply         = PCApply_BJacobi_Multiblock;
9827b6e2003SPierre Jolivet       pc->ops->matapply      = NULL;
9834b9ad928SBarry Smith       pc->ops->applytranspose= PCApplyTranspose_BJacobi_Multiblock;
9844b9ad928SBarry Smith       pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiblock;
9854b9ad928SBarry Smith 
9869566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc,&bjac));
9879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&jac->ksp));
9889566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(KSP))));
9899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n_local,&bjac->x,n_local,&bjac->y));
9909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&bjac->starts));
9919566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(PetscScalar))));
9924b9ad928SBarry Smith 
9934b9ad928SBarry Smith       jac->data = (void*)bjac;
9949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&bjac->is));
9959566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(IS))));
9964b9ad928SBarry Smith 
9974b9ad928SBarry Smith       for (i=0; i<n_local; i++) {
9989566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF,&ksp));
9999566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp,pc->erroriffailure));
10009566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1));
10019566063dSJacob Faibussowitsch         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ksp));
10029566063dSJacob Faibussowitsch         PetscCall(KSPSetType(ksp,KSPPREONLY));
10039566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp,&subpc));
10049566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc,&prefix));
10059566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp,prefix));
10069566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp,"sub_"));
10072fa5cd67SKarl Rupp 
1008c2efdce3SBarry Smith         jac->ksp[i] = ksp;
1009c2efdce3SBarry Smith       }
1010c2efdce3SBarry Smith     } else {
1011c2efdce3SBarry Smith       bjac = (PC_BJacobi_Multiblock*)jac->data;
1012c2efdce3SBarry Smith     }
10134b9ad928SBarry Smith 
1014c2efdce3SBarry Smith     start = 0;
10159566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat,&vectype));
1016c2efdce3SBarry Smith     for (i=0; i<n_local; i++) {
10174b9ad928SBarry Smith       m = jac->l_lens[i];
10184b9ad928SBarry Smith       /*
10194b9ad928SBarry Smith       The reason we need to generate these vectors is to serve
10204b9ad928SBarry Smith       as the right-hand side and solution vector for the solve on the
10214b9ad928SBarry Smith       block. We do not need to allocate space for the vectors since
10224b9ad928SBarry Smith       that is provided via VecPlaceArray() just before the call to
10234b9ad928SBarry Smith       KSPSolve() on the block.
10244b9ad928SBarry Smith 
10254b9ad928SBarry Smith       */
10269566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF,m,&x));
10279566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&y));
10289566063dSJacob Faibussowitsch       PetscCall(VecSetType(x,vectype));
10299566063dSJacob Faibussowitsch       PetscCall(VecSetType(y,vectype));
10309566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)x));
10319566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)y));
10322fa5cd67SKarl Rupp 
10334b9ad928SBarry Smith       bjac->x[i]      = x;
10344b9ad928SBarry Smith       bjac->y[i]      = y;
10354b9ad928SBarry Smith       bjac->starts[i] = start;
10364b9ad928SBarry Smith 
10379566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF,m,start,1,&is));
10384b9ad928SBarry Smith       bjac->is[i] = is;
10399566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)is));
10404b9ad928SBarry Smith 
10414b9ad928SBarry Smith       start += m;
10424b9ad928SBarry Smith     }
10434b9ad928SBarry Smith   } else {
10444b9ad928SBarry Smith     bjac = (PC_BJacobi_Multiblock*)jac->data;
10454b9ad928SBarry Smith     /*
10464b9ad928SBarry Smith        Destroy the blocks from the previous iteration
10474b9ad928SBarry Smith     */
10484b9ad928SBarry Smith     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
10499566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(n_local,&bjac->pmat));
105049517cdeSBarry Smith       if (pc->useAmat) {
10519566063dSJacob Faibussowitsch         PetscCall(MatDestroyMatrices(n_local,&bjac->mat));
10524b9ad928SBarry Smith       }
10534b9ad928SBarry Smith       scall = MAT_INITIAL_MATRIX;
10542fa5cd67SKarl Rupp     } else scall = MAT_REUSE_MATRIX;
10554b9ad928SBarry Smith   }
10564b9ad928SBarry Smith 
10579566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(pmat,n_local,bjac->is,bjac->is,scall,&bjac->pmat));
105849517cdeSBarry Smith   if (pc->useAmat) {
10599566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(mat,n_local,bjac->is,bjac->is,scall,&bjac->mat));
10604b9ad928SBarry Smith   }
10614b9ad928SBarry Smith   /* Return control to the user so that the submatrices can be modified (e.g., to apply
10624b9ad928SBarry Smith      different boundary conditions for the submatrices than for the global problem) */
10639566063dSJacob Faibussowitsch   PetscCall(PCModifySubMatrices(pc,n_local,bjac->is,bjac->is,bjac->pmat,pc->modifysubmatricesP));
10644b9ad928SBarry Smith 
10654b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
10669566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->pmat[i]));
10679566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[i],&prefix));
106849517cdeSBarry Smith     if (pc->useAmat) {
10699566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->mat[i]));
10709566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i],bjac->mat[i],bjac->pmat[i]));
10719566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(bjac->mat[i],prefix));
10724b9ad928SBarry Smith     } else {
10739566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i],bjac->pmat[i],bjac->pmat[i]));
10744b9ad928SBarry Smith     }
10759566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(bjac->pmat[i],prefix));
107690f1c854SHong Zhang     if (pc->setfromoptionscalled) {
10779566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->ksp[i]));
10784b9ad928SBarry Smith     }
107990f1c854SHong Zhang   }
10804b9ad928SBarry Smith   PetscFunctionReturn(0);
10814b9ad928SBarry Smith }
10825a7e1895SHong Zhang 
10835a7e1895SHong Zhang /* ---------------------------------------------------------------------------------------------*/
10845a7e1895SHong Zhang /*
1085fd0b8932SBarry Smith       These are for a single block with multiple processes
10865a7e1895SHong Zhang */
1087fd0b8932SBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiproc(PC pc)
1088fd0b8932SBarry Smith {
1089fd0b8932SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
1090fd0b8932SBarry Smith   KSP                subksp = jac->ksp[0];
1091fd0b8932SBarry Smith   KSPConvergedReason reason;
1092fd0b8932SBarry Smith 
1093fd0b8932SBarry Smith   PetscFunctionBegin;
10949566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
10959566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp,&reason));
1096fd0b8932SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
1097fd0b8932SBarry Smith     pc->failedreason = PC_SUBPC_ERROR;
1098fd0b8932SBarry Smith   }
1099fd0b8932SBarry Smith   PetscFunctionReturn(0);
1100fd0b8932SBarry Smith }
1101fd0b8932SBarry Smith 
1102e91c6855SBarry Smith static PetscErrorCode PCReset_BJacobi_Multiproc(PC pc)
11035a7e1895SHong Zhang {
11045a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11055a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
11065a7e1895SHong Zhang 
11075a7e1895SHong Zhang   PetscFunctionBegin;
11089566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->ysub));
11099566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->xsub));
11109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mpjac->submats));
11119566063dSJacob Faibussowitsch   if (jac->ksp) PetscCall(KSPReset(jac->ksp[0]));
1112e91c6855SBarry Smith   PetscFunctionReturn(0);
1113e91c6855SBarry Smith }
1114e91c6855SBarry Smith 
1115e91c6855SBarry Smith static PetscErrorCode PCDestroy_BJacobi_Multiproc(PC pc)
1116e91c6855SBarry Smith {
1117e91c6855SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
1118e91c6855SBarry Smith   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
1119e91c6855SBarry Smith 
1120e91c6855SBarry Smith   PetscFunctionBegin;
11219566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiproc(pc));
11229566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
11239566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
11249566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&mpjac->psubcomm));
11255a7e1895SHong Zhang 
11269566063dSJacob Faibussowitsch   PetscCall(PetscFree(mpjac));
1127*2e956fe4SStefano Zampini   PetscCall(PCDestroy_BJacobi(pc));
11285a7e1895SHong Zhang   PetscFunctionReturn(0);
11295a7e1895SHong Zhang }
11305a7e1895SHong Zhang 
11315a7e1895SHong Zhang static PetscErrorCode PCApply_BJacobi_Multiproc(PC pc,Vec x,Vec y)
11325a7e1895SHong Zhang {
11335a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11345a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
1135d9ca1df4SBarry Smith   PetscScalar          *yarray;
1136d9ca1df4SBarry Smith   const PetscScalar    *xarray;
1137539c167fSBarry Smith   KSPConvergedReason   reason;
11385a7e1895SHong Zhang 
11395a7e1895SHong Zhang   PetscFunctionBegin;
11405a7e1895SHong Zhang   /* place x's and y's local arrays into xsub and ysub */
11419566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&xarray));
11429566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&yarray));
11439566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->xsub,xarray));
11449566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->ysub,yarray));
11455a7e1895SHong Zhang 
11465a7e1895SHong Zhang   /* apply preconditioner on each matrix block */
11479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks,jac->ksp[0],mpjac->xsub,mpjac->ysub,0));
11489566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0],mpjac->xsub,mpjac->ysub));
11499566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,mpjac->ysub));
11509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks,jac->ksp[0],mpjac->xsub,mpjac->ysub,0));
11519566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0],&reason));
1152c0decd05SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
1153261222b2SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
1154250cf88bSHong Zhang   }
1155250cf88bSHong Zhang 
11569566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->xsub));
11579566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->ysub));
11589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&xarray));
11599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&yarray));
11605a7e1895SHong Zhang   PetscFunctionReturn(0);
11615a7e1895SHong Zhang }
11625a7e1895SHong Zhang 
11637b6e2003SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Multiproc(PC pc,Mat X,Mat Y)
11647b6e2003SPierre Jolivet {
11657b6e2003SPierre Jolivet   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11667b6e2003SPierre Jolivet   KSPConvergedReason   reason;
11677b6e2003SPierre Jolivet   Mat                  sX,sY;
11687b6e2003SPierre Jolivet   const PetscScalar    *x;
11697b6e2003SPierre Jolivet   PetscScalar          *y;
11707b6e2003SPierre Jolivet   PetscInt             m,N,lda,ldb;
11717b6e2003SPierre Jolivet 
11727b6e2003SPierre Jolivet   PetscFunctionBegin;
11737b6e2003SPierre Jolivet   /* apply preconditioner on each matrix block */
11749566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X,&m,NULL));
11759566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X,NULL,&N));
11769566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X,&lda));
11779566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(Y,&ldb));
11789566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(X,&x));
11799566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(Y,&y));
11809566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]),m,PETSC_DECIDE,PETSC_DECIDE,N,(PetscScalar*)x,&sX));
11819566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]),m,PETSC_DECIDE,PETSC_DECIDE,N,y,&sY));
11829566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sX,lda));
11839566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sY,ldb));
11849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks,jac->ksp[0],X,Y,0));
11859566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0],sX,sY));
11869566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,NULL));
11879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks,jac->ksp[0],X,Y,0));
11889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sY));
11899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sX));
11909566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(Y,&y));
11919566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(X,&x));
11929566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0],&reason));
11937b6e2003SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) {
11947b6e2003SPierre Jolivet     pc->failedreason = PC_SUBPC_ERROR;
11957b6e2003SPierre Jolivet   }
11967b6e2003SPierre Jolivet   PetscFunctionReturn(0);
11977b6e2003SPierre Jolivet }
11987b6e2003SPierre Jolivet 
11995a7e1895SHong Zhang static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC pc)
12005a7e1895SHong Zhang {
12015a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
12025a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
12035a7e1895SHong Zhang   PetscInt             m,n;
1204ce94432eSBarry Smith   MPI_Comm             comm,subcomm=0;
12055a7e1895SHong Zhang   const char           *prefix;
1206de0953f6SBarry Smith   PetscBool            wasSetup = PETSC_TRUE;
12073f6dc190SJunchao Zhang   VecType              vectype;
12081f62890fSKarl Rupp 
12095a7e1895SHong Zhang   PetscFunctionBegin;
12109566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
121108401ef6SPierre Jolivet   PetscCheck(jac->n_local <= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Only a single block in a subcommunicator is supported");
12125a7e1895SHong Zhang   jac->n_local = 1; /* currently only a single block is supported for a subcommunicator */
12135a7e1895SHong Zhang   if (!pc->setupcalled) {
1214de0953f6SBarry Smith     wasSetup  = PETSC_FALSE;
12159566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(pc,&mpjac));
12165a7e1895SHong Zhang     jac->data = (void*)mpjac;
12175a7e1895SHong Zhang 
12185a7e1895SHong Zhang     /* initialize datastructure mpjac */
12195a7e1895SHong Zhang     if (!jac->psubcomm) {
12205a7e1895SHong Zhang       /* Create default contiguous subcommunicatiors if user does not provide them */
12219566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm,&jac->psubcomm));
12229566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(jac->psubcomm,jac->n));
12239566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetType(jac->psubcomm,PETSC_SUBCOMM_CONTIGUOUS));
12249566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(PetscSubcomm)));
12255a7e1895SHong Zhang     }
12265a7e1895SHong Zhang     mpjac->psubcomm = jac->psubcomm;
1227306c2d5bSBarry Smith     subcomm         = PetscSubcommChild(mpjac->psubcomm);
12285a7e1895SHong Zhang 
12295a7e1895SHong Zhang     /* Get matrix blocks of pmat */
12309566063dSJacob Faibussowitsch     PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_INITIAL_MATRIX,&mpjac->submats));
12315a7e1895SHong Zhang 
12325a7e1895SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
12339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1,&jac->ksp));
12349566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm,&jac->ksp[0]));
12359566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(jac->ksp[0],pc->erroriffailure));
12369566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp[0],(PetscObject)pc,1));
12379566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->ksp[0]));
12389566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0],mpjac->submats,mpjac->submats));
12399566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(jac->ksp[0],&mpjac->pc));
12405a7e1895SHong Zhang 
12419566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc,&prefix));
12429566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(jac->ksp[0],prefix));
12439566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(jac->ksp[0],"sub_"));
12449566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[0],&prefix));
12459566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mpjac->submats,prefix));
12465a7e1895SHong Zhang 
12475a7e1895SHong Zhang     /* create dummy vectors xsub and ysub */
12489566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mpjac->submats,&m,&n));
12499566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm,1,n,PETSC_DECIDE,NULL,&mpjac->xsub));
12509566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm,1,m,PETSC_DECIDE,NULL,&mpjac->ysub));
12519566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(mpjac->submats,&vectype));
12529566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->xsub,vectype));
12539566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->ysub,vectype));
12549566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)mpjac->xsub));
12559566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)mpjac->ysub));
12565a7e1895SHong Zhang 
1257fd0b8932SBarry Smith     pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiproc;
1258e91c6855SBarry Smith     pc->ops->reset         = PCReset_BJacobi_Multiproc;
12595a7e1895SHong Zhang     pc->ops->destroy       = PCDestroy_BJacobi_Multiproc;
12605a7e1895SHong Zhang     pc->ops->apply         = PCApply_BJacobi_Multiproc;
12617b6e2003SPierre Jolivet     pc->ops->matapply      = PCMatApply_BJacobi_Multiproc;
1262fc08c53fSHong Zhang   } else { /* pc->setupcalled */
1263306c2d5bSBarry Smith     subcomm = PetscSubcommChild(mpjac->psubcomm);
12649e0ae222SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
12655a7e1895SHong Zhang       /* destroy old matrix blocks, then get new matrix blocks */
12669566063dSJacob Faibussowitsch       if (mpjac->submats) PetscCall(MatDestroy(&mpjac->submats));
12679566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_INITIAL_MATRIX,&mpjac->submats));
1268fc08c53fSHong Zhang     } else {
12699566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_REUSE_MATRIX,&mpjac->submats));
12705a7e1895SHong Zhang     }
12719566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0],mpjac->submats,mpjac->submats));
12725a7e1895SHong Zhang   }
12735a7e1895SHong Zhang 
1274de0953f6SBarry Smith   if (!wasSetup && pc->setfromoptionscalled) {
12759566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(jac->ksp[0]));
12765a7e1895SHong Zhang   }
12775a7e1895SHong Zhang   PetscFunctionReturn(0);
12785a7e1895SHong Zhang }
1279