xref: /petsc/src/ksp/pc/impls/bjacobi/bjacobi.c (revision d0609ced746bc51b019815ca91d747429db24893)
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));
1439566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1444b9ad928SBarry Smith   PetscFunctionReturn(0);
1454b9ad928SBarry Smith }
1464b9ad928SBarry Smith 
1474416b707SBarry Smith static PetscErrorCode PCSetFromOptions_BJacobi(PetscOptionItems *PetscOptionsObject,PC pc)
1484b9ad928SBarry Smith {
1494b9ad928SBarry Smith   PC_BJacobi     *jac = (PC_BJacobi*)pc->data;
150248bfaf0SJed Brown   PetscInt       blocks,i;
151ace3abfcSBarry Smith   PetscBool      flg;
1524b9ad928SBarry Smith 
1534b9ad928SBarry Smith   PetscFunctionBegin;
154*d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"Block Jacobi options");
1559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_blocks","Total number of blocks","PCBJacobiSetTotalBlocks",jac->n,&blocks,&flg));
1569566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetTotalBlocks(pc,blocks,NULL));
1579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_bjacobi_local_blocks","Local number of blocks","PCBJacobiSetLocalBlocks",jac->n_local,&blocks,&flg));
1589566063dSJacob Faibussowitsch   if (flg) PetscCall(PCBJacobiSetLocalBlocks(pc,blocks,NULL));
159248bfaf0SJed Brown   if (jac->ksp) {
160248bfaf0SJed Brown     /* The sub-KSP has already been set up (e.g., PCSetUp_BJacobi_Singleblock), but KSPSetFromOptions was not called
161248bfaf0SJed Brown      * unless we had already been called. */
162248bfaf0SJed Brown     for (i=0; i<jac->n_local; i++) {
1639566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->ksp[i]));
164248bfaf0SJed Brown     }
165248bfaf0SJed Brown   }
166*d0609cedSBarry Smith   PetscOptionsHeadEnd();
1674b9ad928SBarry Smith   PetscFunctionReturn(0);
1684b9ad928SBarry Smith }
1694b9ad928SBarry Smith 
1709804daf3SBarry Smith #include <petscdraw.h>
1716849ba73SBarry Smith static PetscErrorCode PCView_BJacobi(PC pc,PetscViewer viewer)
1724b9ad928SBarry Smith {
1734b9ad928SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
174cbe18068SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
17569a612a9SBarry Smith   PetscMPIInt          rank;
17669a612a9SBarry Smith   PetscInt             i;
177d9884438SBarry Smith   PetscBool            iascii,isstring,isdraw;
1784b9ad928SBarry Smith   PetscViewer          sviewer;
179020d6619SPierre Jolivet   PetscViewerFormat    format;
180020d6619SPierre Jolivet   const char           *prefix;
1814b9ad928SBarry Smith 
1824b9ad928SBarry Smith   PetscFunctionBegin;
1839566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring));
1859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
18632077d6dSBarry Smith   if (iascii) {
18749517cdeSBarry Smith     if (pc->useAmat) {
1889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  using Amat local matrix, number of blocks = %D\n",jac->n));
1894b9ad928SBarry Smith     }
1909566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  number of blocks = %D\n",jac->n));
1919566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank));
1929566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer,&format));
193020d6619SPierre Jolivet     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
1949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Local solver information for first block is in the following KSP and PC objects on rank 0:\n"));
1959566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc,&prefix));
1969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Use -%sksp_view ::ascii_info_detail to display information for all blocks\n",prefix?prefix:""));
197933995ecSHong Zhang       if (jac->ksp && !jac->psubcomm) {
1989566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
199dd400576SPatrick Sanan         if (rank == 0) {
2009566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2019566063dSJacob Faibussowitsch           PetscCall(KSPView(jac->ksp[0],sviewer));
2029566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
2034b9ad928SBarry Smith         }
2049566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2059566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2069566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
207e4de9e1dSBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2089566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
209e4fa1014SBarry Smith       } else if (mpjac && jac->ksp && mpjac->psubcomm) {
2109566063dSJacob Faibussowitsch         PetscCall(PetscViewerGetSubViewer(viewer,mpjac->psubcomm->child,&sviewer));
211e4fa1014SBarry Smith         if (!mpjac->psubcomm->color) {
2129566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));
2139566063dSJacob Faibussowitsch           PetscCall(KSPView(*(jac->ksp),sviewer));
2149566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));
215cbe18068SHong Zhang         }
2169566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(sviewer));
2179566063dSJacob Faibussowitsch         PetscCall(PetscViewerRestoreSubViewer(viewer,mpjac->psubcomm->child,&sviewer));
2189566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
2199530cbd7SBarry Smith         /*  extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
2209566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2214b9ad928SBarry Smith       } else {
2229566063dSJacob Faibussowitsch         PetscCall(PetscViewerFlush(viewer));
223e4de9e1dSBarry Smith       }
224e4de9e1dSBarry Smith     } else {
2254814766eSBarry Smith       PetscInt n_global;
2261c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&jac->n_local,&n_global,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)pc)));
2279566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2289566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"  Local solver information for each block is in the following KSP and PC objects:\n"));
229*d0609cedSBarry Smith       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"[%d] number of local blocks = %D, first local block number = %D\n",rank,jac->n_local,jac->first_local));
2309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2319566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
232dd2fa690SBarry Smith       for (i=0; i<jac->n_local; i++) {
2339566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"[%d] local block number %D\n",rank,i));
2349566063dSJacob Faibussowitsch         PetscCall(KSPView(jac->ksp[i],sviewer));
2359566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n"));
2364b9ad928SBarry Smith       }
2379566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2389566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
2399566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
2409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2414b9ad928SBarry Smith     }
2424b9ad928SBarry Smith   } else if (isstring) {
2439566063dSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer," blks=%D",jac->n));
2449566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
2459566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0],sviewer));
2469566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
247d9884438SBarry Smith   } else if (isdraw) {
248d9884438SBarry Smith     PetscDraw draw;
249d9884438SBarry Smith     char      str[25];
250d9884438SBarry Smith     PetscReal x,y,bottom,h;
251d9884438SBarry Smith 
2529566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
2539566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw,&x,&y));
2549566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str,25,"Number blocks %D",jac->n));
2559566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h));
256d9884438SBarry Smith     bottom = y - h;
2579566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw,x,bottom));
258d9884438SBarry Smith     /* warning the communicator on viewer is different then on ksp in parallel */
2599566063dSJacob Faibussowitsch     if (jac->ksp) PetscCall(KSPView(jac->ksp[0],viewer));
2609566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2614b9ad928SBarry Smith   }
2624b9ad928SBarry Smith   PetscFunctionReturn(0);
2634b9ad928SBarry Smith }
2644b9ad928SBarry Smith 
2654b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
2664b9ad928SBarry Smith 
2671e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetSubKSP_BJacobi(PC pc,PetscInt *n_local,PetscInt *first_local,KSP **ksp)
2684b9ad928SBarry Smith {
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;
2774b9ad928SBarry Smith   PetscFunctionReturn(0);
2784b9ad928SBarry Smith }
2794b9ad928SBarry Smith 
2801e6b0712SBarry Smith static PetscErrorCode  PCBJacobiSetTotalBlocks_BJacobi(PC pc,PetscInt blocks,PetscInt *lens)
2814b9ad928SBarry Smith {
2824b9ad928SBarry Smith   PC_BJacobi     *jac = (PC_BJacobi*)pc->data;
2834b9ad928SBarry Smith 
2844b9ad928SBarry Smith   PetscFunctionBegin;
2852c71b3e2SJacob Faibussowitsch   PetscCheckFalse(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(PetscLogObjectMemory((PetscObject)pc,blocks*sizeof(PetscInt)));
2919566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->g_lens,lens,blocks));
2924b9ad928SBarry Smith   }
2934b9ad928SBarry Smith   PetscFunctionReturn(0);
2944b9ad928SBarry Smith }
2954b9ad928SBarry Smith 
2961e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetTotalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
2974b9ad928SBarry Smith {
2984b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi*) pc->data;
2994b9ad928SBarry Smith 
3004b9ad928SBarry Smith   PetscFunctionBegin;
3014b9ad928SBarry Smith   *blocks = jac->n;
3024b9ad928SBarry Smith   if (lens) *lens = jac->g_lens;
3034b9ad928SBarry Smith   PetscFunctionReturn(0);
3044b9ad928SBarry Smith }
3054b9ad928SBarry Smith 
3061e6b0712SBarry Smith static PetscErrorCode  PCBJacobiSetLocalBlocks_BJacobi(PC pc,PetscInt blocks,const PetscInt lens[])
3074b9ad928SBarry Smith {
3084b9ad928SBarry Smith   PC_BJacobi     *jac;
3094b9ad928SBarry Smith 
3104b9ad928SBarry Smith   PetscFunctionBegin;
3114b9ad928SBarry Smith   jac = (PC_BJacobi*)pc->data;
3124b9ad928SBarry Smith 
3134b9ad928SBarry Smith   jac->n_local = blocks;
3140a545947SLisandro Dalcin   if (!lens) jac->l_lens = NULL;
3152fa5cd67SKarl Rupp   else {
3169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(blocks,&jac->l_lens));
3179566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectMemory((PetscObject)pc,blocks*sizeof(PetscInt)));
3189566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(jac->l_lens,lens,blocks));
3194b9ad928SBarry Smith   }
3204b9ad928SBarry Smith   PetscFunctionReturn(0);
3214b9ad928SBarry Smith }
3224b9ad928SBarry Smith 
3231e6b0712SBarry Smith static PetscErrorCode  PCBJacobiGetLocalBlocks_BJacobi(PC pc, PetscInt *blocks, const PetscInt *lens[])
3244b9ad928SBarry Smith {
3254b9ad928SBarry Smith   PC_BJacobi *jac = (PC_BJacobi*) pc->data;
3264b9ad928SBarry Smith 
3274b9ad928SBarry Smith   PetscFunctionBegin;
3284b9ad928SBarry Smith   *blocks = jac->n_local;
3294b9ad928SBarry Smith   if (lens) *lens = jac->l_lens;
3304b9ad928SBarry Smith   PetscFunctionReturn(0);
3314b9ad928SBarry Smith }
3324b9ad928SBarry Smith 
3334b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
3344b9ad928SBarry Smith 
3354b9ad928SBarry Smith /*@C
3364b9ad928SBarry Smith    PCBJacobiGetSubKSP - Gets the local KSP contexts for all blocks on
3374b9ad928SBarry Smith    this processor.
3384b9ad928SBarry Smith 
3396da92b7fSHong Zhang    Not Collective
3404b9ad928SBarry Smith 
3414b9ad928SBarry Smith    Input Parameter:
3424b9ad928SBarry Smith .  pc - the preconditioner context
3434b9ad928SBarry Smith 
3444b9ad928SBarry Smith    Output Parameters:
3450298fd71SBarry Smith +  n_local - the number of blocks on this processor, or NULL
3460298fd71SBarry Smith .  first_local - the global number of the first block on this processor, or NULL
3474b9ad928SBarry Smith -  ksp - the array of KSP contexts
3484b9ad928SBarry Smith 
3494b9ad928SBarry Smith    Notes:
3504b9ad928SBarry Smith    After PCBJacobiGetSubKSP() the array of KSP contexts is not to be freed.
3514b9ad928SBarry Smith 
3524b9ad928SBarry Smith    Currently for some matrix implementations only 1 block per processor
3534b9ad928SBarry Smith    is supported.
3544b9ad928SBarry Smith 
3554b9ad928SBarry Smith    You must call KSPSetUp() or PCSetUp() before calling PCBJacobiGetSubKSP().
3564b9ad928SBarry Smith 
357196cc216SBarry Smith    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
3582bf68e3eSBarry Smith       You can call PCBJacobiGetSubKSP(pc,nlocal,firstlocal,PETSC_NULL_KSP,ierr) to determine how large the
359196cc216SBarry Smith       KSP array must be.
360196cc216SBarry Smith 
3614b9ad928SBarry Smith    Level: advanced
3624b9ad928SBarry Smith 
363536f90c4SPierre Jolivet .seealso: PCASMGetSubKSP()
3644b9ad928SBarry Smith @*/
3657087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[])
3664b9ad928SBarry Smith {
3674b9ad928SBarry Smith   PetscFunctionBegin;
3680700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
369cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));
3704b9ad928SBarry Smith   PetscFunctionReturn(0);
3714b9ad928SBarry Smith }
3724b9ad928SBarry Smith 
3734b9ad928SBarry Smith /*@
3744b9ad928SBarry Smith    PCBJacobiSetTotalBlocks - Sets the global number of blocks for the block
3754b9ad928SBarry Smith    Jacobi preconditioner.
3764b9ad928SBarry Smith 
3774b9ad928SBarry Smith    Collective on PC
3784b9ad928SBarry Smith 
3794b9ad928SBarry Smith    Input Parameters:
3804b9ad928SBarry Smith +  pc - the preconditioner context
3814b9ad928SBarry Smith .  blocks - the number of blocks
3824b9ad928SBarry Smith -  lens - [optional] integer array containing the size of each block
3834b9ad928SBarry Smith 
3844b9ad928SBarry Smith    Options Database Key:
3854b9ad928SBarry Smith .  -pc_bjacobi_blocks <blocks> - Sets the number of global blocks
3864b9ad928SBarry Smith 
3874b9ad928SBarry Smith    Notes:
3884b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
3894b9ad928SBarry Smith    All processors sharing the PC must call this routine with the same data.
3904b9ad928SBarry Smith 
3914b9ad928SBarry Smith    Level: intermediate
3924b9ad928SBarry Smith 
39349517cdeSBarry Smith .seealso: PCSetUseAmat(), PCBJacobiSetLocalBlocks()
3944b9ad928SBarry Smith @*/
3957087cfbeSBarry Smith PetscErrorCode  PCBJacobiSetTotalBlocks(PC pc,PetscInt blocks,const PetscInt lens[])
3964b9ad928SBarry Smith {
3974b9ad928SBarry Smith   PetscFunctionBegin;
3980700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
39908401ef6SPierre Jolivet   PetscCheck(blocks > 0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Must have positive blocks");
400cac4c232SBarry Smith   PetscTryMethod(pc,"PCBJacobiSetTotalBlocks_C",(PC,PetscInt,const PetscInt[]),(pc,blocks,lens));
4014b9ad928SBarry Smith   PetscFunctionReturn(0);
4024b9ad928SBarry Smith }
4034b9ad928SBarry Smith 
4044b9ad928SBarry Smith /*@C
4054b9ad928SBarry Smith    PCBJacobiGetTotalBlocks - Gets the global number of blocks for the block
4064b9ad928SBarry Smith    Jacobi preconditioner.
4074b9ad928SBarry Smith 
408ad4df100SBarry Smith    Not Collective
4094b9ad928SBarry Smith 
4104b9ad928SBarry Smith    Input Parameter:
4114b9ad928SBarry Smith .  pc - the preconditioner context
4124b9ad928SBarry Smith 
4134b9ad928SBarry Smith    Output parameters:
4144b9ad928SBarry Smith +  blocks - the number of blocks
4154b9ad928SBarry Smith -  lens - integer array containing the size of each block
4164b9ad928SBarry Smith 
4174b9ad928SBarry Smith    Level: intermediate
4184b9ad928SBarry Smith 
41949517cdeSBarry Smith .seealso: PCSetUseAmat(), PCBJacobiGetLocalBlocks()
4204b9ad928SBarry Smith @*/
4217087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetTotalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
4224b9ad928SBarry Smith {
4234b9ad928SBarry Smith   PetscFunctionBegin;
4240700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID,1);
4254482741eSBarry Smith   PetscValidIntPointer(blocks,2);
426cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetTotalBlocks_C",(PC,PetscInt*, const PetscInt *[]),(pc,blocks,lens));
4274b9ad928SBarry Smith   PetscFunctionReturn(0);
4284b9ad928SBarry Smith }
4294b9ad928SBarry Smith 
4304b9ad928SBarry Smith /*@
4314b9ad928SBarry Smith    PCBJacobiSetLocalBlocks - Sets the local number of blocks for the block
4324b9ad928SBarry Smith    Jacobi preconditioner.
4334b9ad928SBarry Smith 
4344b9ad928SBarry Smith    Not Collective
4354b9ad928SBarry Smith 
4364b9ad928SBarry Smith    Input Parameters:
4374b9ad928SBarry Smith +  pc - the preconditioner context
4384b9ad928SBarry Smith .  blocks - the number of blocks
4394b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4404b9ad928SBarry Smith 
441342c94f9SMatthew G. Knepley    Options Database Key:
442342c94f9SMatthew G. Knepley .  -pc_bjacobi_local_blocks <blocks> - Sets the number of local blocks
443342c94f9SMatthew G. Knepley 
4444b9ad928SBarry Smith    Note:
4454b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4464b9ad928SBarry Smith 
4474b9ad928SBarry Smith    Level: intermediate
4484b9ad928SBarry Smith 
44949517cdeSBarry Smith .seealso: PCSetUseAmat(), PCBJacobiSetTotalBlocks()
4504b9ad928SBarry Smith @*/
4517087cfbeSBarry Smith PetscErrorCode  PCBJacobiSetLocalBlocks(PC pc,PetscInt blocks,const PetscInt lens[])
4524b9ad928SBarry Smith {
4534b9ad928SBarry Smith   PetscFunctionBegin;
4540700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
45508401ef6SPierre Jolivet   PetscCheck(blocks >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have nonegative blocks");
456cac4c232SBarry Smith   PetscTryMethod(pc,"PCBJacobiSetLocalBlocks_C",(PC,PetscInt,const PetscInt []),(pc,blocks,lens));
4574b9ad928SBarry Smith   PetscFunctionReturn(0);
4584b9ad928SBarry Smith }
4594b9ad928SBarry Smith 
4604b9ad928SBarry Smith /*@C
4614b9ad928SBarry Smith    PCBJacobiGetLocalBlocks - Gets the local number of blocks for the block
4624b9ad928SBarry Smith    Jacobi preconditioner.
4634b9ad928SBarry Smith 
4644b9ad928SBarry Smith    Not Collective
4654b9ad928SBarry Smith 
4664b9ad928SBarry Smith    Input Parameters:
4674b9ad928SBarry Smith +  pc - the preconditioner context
4684b9ad928SBarry Smith .  blocks - the number of blocks
4694b9ad928SBarry Smith -  lens - [optional] integer array containing size of each block
4704b9ad928SBarry Smith 
4714b9ad928SBarry Smith    Note:
4724b9ad928SBarry Smith    Currently only a limited number of blocking configurations are supported.
4734b9ad928SBarry Smith 
4744b9ad928SBarry Smith    Level: intermediate
4754b9ad928SBarry Smith 
47649517cdeSBarry Smith .seealso: PCSetUseAmat(), PCBJacobiGetTotalBlocks()
4774b9ad928SBarry Smith @*/
4787087cfbeSBarry Smith PetscErrorCode  PCBJacobiGetLocalBlocks(PC pc, PetscInt *blocks, const PetscInt *lens[])
4794b9ad928SBarry Smith {
4804b9ad928SBarry Smith   PetscFunctionBegin;
4810700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID,1);
4824482741eSBarry Smith   PetscValidIntPointer(blocks,2);
483cac4c232SBarry Smith   PetscUseMethod(pc,"PCBJacobiGetLocalBlocks_C",(PC,PetscInt*, const PetscInt *[]),(pc,blocks,lens));
4844b9ad928SBarry Smith   PetscFunctionReturn(0);
4854b9ad928SBarry Smith }
4864b9ad928SBarry Smith 
4874b9ad928SBarry Smith /* -----------------------------------------------------------------------------------*/
4884b9ad928SBarry Smith 
4894b9ad928SBarry Smith /*MC
4904b9ad928SBarry Smith    PCBJACOBI - Use block Jacobi preconditioning, each block is (approximately) solved with
4914b9ad928SBarry Smith            its own KSP object.
4924b9ad928SBarry Smith 
4934b9ad928SBarry Smith    Options Database Keys:
494011ea8aeSBarry Smith +  -pc_use_amat - use Amat to apply block of operator in inner Krylov method
495011ea8aeSBarry Smith -  -pc_bjacobi_blocks <n> - use n total blocks
4964b9ad928SBarry Smith 
49795452b02SPatrick Sanan    Notes:
49895452b02SPatrick 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.
4994b9ad928SBarry Smith 
5004b9ad928SBarry Smith      To set options on the solvers for each block append -sub_ to all the KSP, KSP, and PC
501d7ee0231SBarry Smith         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly
5024b9ad928SBarry Smith 
503a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCBJacobiGetSubKSP()
5044b9ad928SBarry Smith          and set the options directly on the resulting KSP object (you can access its PC
5054b9ad928SBarry Smith          KSPGetPC())
5064b9ad928SBarry Smith 
507e9e886b6SKarl Rupp      For GPU-based vectors (CUDA, ViennaCL) it is recommended to use exactly one block per MPI process for best
5082210c163SDominic Meiser          performance.  Different block partitioning may lead to additional data transfers
5092210c163SDominic Meiser          between host and GPU that lead to degraded performance.
5102210c163SDominic Meiser 
511011ea8aeSBarry Smith      The options prefix for each block is sub_, for example -sub_pc_type lu.
512011ea8aeSBarry Smith 
513011ea8aeSBarry Smith      When multiple processes share a single block, each block encompasses exactly all the unknowns owned its set of processes.
514011ea8aeSBarry Smith 
51590dfcc32SBarry Smith      See PCJACOBI for point Jacobi preconditioning, PCVPBJACOBI for variable size point block Jacobi and PCPBJACOBI for large blocks
51690dfcc32SBarry Smith 
5174b9ad928SBarry Smith    Level: beginner
5184b9ad928SBarry Smith 
5194b9ad928SBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
52049517cdeSBarry Smith            PCASM, PCSetUseAmat(), PCGetUseAmat(), PCBJacobiGetSubKSP(), PCBJacobiSetTotalBlocks(),
52190dfcc32SBarry Smith            PCBJacobiSetLocalBlocks(), PCSetModifySubMatrices(), PCJACOBI, PCVPBJACOBI, PCPBJACOBI
5224b9ad928SBarry Smith M*/
5234b9ad928SBarry Smith 
5248cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_BJacobi(PC pc)
5254b9ad928SBarry Smith {
52669a612a9SBarry Smith   PetscMPIInt    rank;
5274b9ad928SBarry Smith   PC_BJacobi     *jac;
5284b9ad928SBarry Smith 
5294b9ad928SBarry Smith   PetscFunctionBegin;
5309566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc,&jac));
5319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank));
5322fa5cd67SKarl Rupp 
5330a545947SLisandro Dalcin   pc->ops->apply           = NULL;
5347b6e2003SPierre Jolivet   pc->ops->matapply        = NULL;
5350a545947SLisandro Dalcin   pc->ops->applytranspose  = NULL;
5364b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_BJacobi;
5374b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_BJacobi;
5384b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_BJacobi;
5394b9ad928SBarry Smith   pc->ops->view            = PCView_BJacobi;
5400a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5414b9ad928SBarry Smith 
5424b9ad928SBarry Smith   pc->data               = (void*)jac;
5434b9ad928SBarry Smith   jac->n                 = -1;
5444b9ad928SBarry Smith   jac->n_local           = -1;
5454b9ad928SBarry Smith   jac->first_local       = rank;
5460a545947SLisandro Dalcin   jac->ksp               = NULL;
5470a545947SLisandro Dalcin   jac->g_lens            = NULL;
5480a545947SLisandro Dalcin   jac->l_lens            = NULL;
5490a545947SLisandro Dalcin   jac->psubcomm          = NULL;
5504b9ad928SBarry Smith 
5519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetSubKSP_C",PCBJacobiGetSubKSP_BJacobi));
5529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetTotalBlocks_C",PCBJacobiSetTotalBlocks_BJacobi));
5539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetTotalBlocks_C",PCBJacobiGetTotalBlocks_BJacobi));
5549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiSetLocalBlocks_C",PCBJacobiSetLocalBlocks_BJacobi));
5559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBJacobiGetLocalBlocks_C",PCBJacobiGetLocalBlocks_BJacobi));
5564b9ad928SBarry Smith   PetscFunctionReturn(0);
5574b9ad928SBarry Smith }
5584b9ad928SBarry Smith 
5594b9ad928SBarry Smith /* --------------------------------------------------------------------------------------------*/
5604b9ad928SBarry Smith /*
5614b9ad928SBarry Smith         These are for a single block per processor; works for AIJ, BAIJ; Seq and MPI
5624b9ad928SBarry Smith */
56381f0254dSBarry Smith static PetscErrorCode PCReset_BJacobi_Singleblock(PC pc)
5644b9ad928SBarry Smith {
5654b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
5664b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
5674b9ad928SBarry Smith 
5684b9ad928SBarry Smith   PetscFunctionBegin;
5699566063dSJacob Faibussowitsch   PetscCall(KSPReset(jac->ksp[0]));
5709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->x));
5719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bjac->y));
572e91c6855SBarry Smith   PetscFunctionReturn(0);
573e91c6855SBarry Smith }
574e91c6855SBarry Smith 
57581f0254dSBarry Smith static PetscErrorCode PCDestroy_BJacobi_Singleblock(PC pc)
576e91c6855SBarry Smith {
577e91c6855SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
578e91c6855SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
579e91c6855SBarry Smith 
580e91c6855SBarry Smith   PetscFunctionBegin;
5819566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Singleblock(pc));
5829566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
5839566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
5849566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
5859566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
5869566063dSJacob Faibussowitsch   PetscCall(PetscFree(bjac));
5879566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5884b9ad928SBarry Smith   PetscFunctionReturn(0);
5894b9ad928SBarry Smith }
5904b9ad928SBarry Smith 
59181f0254dSBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Singleblock(PC pc)
5924b9ad928SBarry Smith {
5934b9ad928SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
5942295b7c8SHong Zhang   KSP                subksp = jac->ksp[0];
595539c167fSBarry Smith   KSPConvergedReason reason;
5964b9ad928SBarry Smith 
5974b9ad928SBarry Smith   PetscFunctionBegin;
5989566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
5999566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp,&reason));
600c0decd05SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
601261222b2SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
6022295b7c8SHong Zhang   }
6034b9ad928SBarry Smith   PetscFunctionReturn(0);
6044b9ad928SBarry Smith }
6054b9ad928SBarry Smith 
60681f0254dSBarry Smith static PetscErrorCode PCApply_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6074b9ad928SBarry Smith {
6084b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6094b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
6106e111a19SKarl Rupp 
6114b9ad928SBarry Smith   PetscFunctionBegin;
6129566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVectorRead(x, bjac->x));
6139566063dSJacob Faibussowitsch   PetscCall(VecGetLocalVector(y, bjac->y));
614bba28a21SBarry Smith   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
615910cf402Sprj-      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
616910cf402Sprj-      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6179566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0],pc->reusepreconditioner));
6189566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0],bjac->x,bjac->y));
6199566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,bjac->y));
6209566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVectorRead(x, bjac->x));
6219566063dSJacob Faibussowitsch   PetscCall(VecRestoreLocalVector(y, bjac->y));
6224b9ad928SBarry Smith   PetscFunctionReturn(0);
6234b9ad928SBarry Smith }
6244b9ad928SBarry Smith 
6257b6e2003SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Singleblock(PC pc,Mat X,Mat Y)
6267b6e2003SPierre Jolivet {
6277b6e2003SPierre Jolivet   PC_BJacobi     *jac  = (PC_BJacobi*)pc->data;
6287b6e2003SPierre Jolivet   Mat            sX,sY;
6297b6e2003SPierre Jolivet 
6307b6e2003SPierre Jolivet   PetscFunctionBegin;
6317b6e2003SPierre Jolivet   /* Since the inner KSP matrix may point directly to the diagonal block of an MPI matrix the inner
6327b6e2003SPierre Jolivet      matrix may change even if the outer KSP/PC has not updated the preconditioner, this will trigger a rebuild
6337b6e2003SPierre Jolivet      of the inner preconditioner automatically unless we pass down the outer preconditioners reuse flag.*/
6349566063dSJacob Faibussowitsch   PetscCall(KSPSetReusePreconditioner(jac->ksp[0],pc->reusepreconditioner));
6359566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(X,&sX));
6369566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLocalMatrix(Y,&sY));
6379566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0],sX,sY));
6387b6e2003SPierre Jolivet   PetscFunctionReturn(0);
6397b6e2003SPierre Jolivet }
6407b6e2003SPierre Jolivet 
64181f0254dSBarry Smith static PetscErrorCode PCApplySymmetricLeft_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6424b9ad928SBarry Smith {
6434b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6444b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
645d9ca1df4SBarry Smith   PetscScalar            *y_array;
646d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6474b9ad928SBarry Smith   PC                     subpc;
6484b9ad928SBarry Smith 
6494b9ad928SBarry Smith   PetscFunctionBegin;
6504b9ad928SBarry Smith   /*
6514b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6524b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6534b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6544b9ad928SBarry Smith     for the sequential solve.
6554b9ad928SBarry Smith   */
6569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
6579566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
6589566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
6599566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
6604b9ad928SBarry Smith   /* apply the symmetric left portion of the inner PC operator */
6614b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6629566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0],&subpc));
6639566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricLeft(subpc,bjac->x,bjac->y));
6649566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
6659566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
6669566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
6679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
6684b9ad928SBarry Smith   PetscFunctionReturn(0);
6694b9ad928SBarry Smith }
6704b9ad928SBarry Smith 
67181f0254dSBarry Smith static PetscErrorCode PCApplySymmetricRight_BJacobi_Singleblock(PC pc,Vec x,Vec y)
6724b9ad928SBarry Smith {
6734b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
6744b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
675d9ca1df4SBarry Smith   PetscScalar            *y_array;
676d9ca1df4SBarry Smith   const PetscScalar      *x_array;
6774b9ad928SBarry Smith   PC                     subpc;
6784b9ad928SBarry Smith 
6794b9ad928SBarry Smith   PetscFunctionBegin;
6804b9ad928SBarry Smith   /*
6814b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
6824b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
6834b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
6844b9ad928SBarry Smith     for the sequential solve.
6854b9ad928SBarry Smith   */
6869566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
6879566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
6889566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
6899566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
6904b9ad928SBarry Smith 
6914b9ad928SBarry Smith   /* apply the symmetric right portion of the inner PC operator */
6924b9ad928SBarry Smith   /* note this by-passes the inner KSP and its options completely */
6934b9ad928SBarry Smith 
6949566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(jac->ksp[0],&subpc));
6959566063dSJacob Faibussowitsch   PetscCall(PCApplySymmetricRight(subpc,bjac->x,bjac->y));
6964b9ad928SBarry Smith 
6979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
6989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
6994b9ad928SBarry Smith   PetscFunctionReturn(0);
7004b9ad928SBarry Smith }
7014b9ad928SBarry Smith 
70281f0254dSBarry Smith static PetscErrorCode PCApplyTranspose_BJacobi_Singleblock(PC pc,Vec x,Vec y)
7034b9ad928SBarry Smith {
7044b9ad928SBarry Smith   PC_BJacobi             *jac  = (PC_BJacobi*)pc->data;
7054b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac = (PC_BJacobi_Singleblock*)jac->data;
706d9ca1df4SBarry Smith   PetscScalar            *y_array;
707d9ca1df4SBarry Smith   const PetscScalar      *x_array;
7084b9ad928SBarry Smith 
7094b9ad928SBarry Smith   PetscFunctionBegin;
7104b9ad928SBarry Smith   /*
7114b9ad928SBarry Smith       The VecPlaceArray() is to avoid having to copy the
7124b9ad928SBarry Smith     y vector into the bjac->x vector. The reason for
7134b9ad928SBarry Smith     the bjac->x vector is that we need a sequential vector
7144b9ad928SBarry Smith     for the sequential solve.
7154b9ad928SBarry Smith   */
7169566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&x_array));
7179566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&y_array));
7189566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->x,x_array));
7199566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(bjac->y,y_array));
7209566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(jac->ksp[0],bjac->x,bjac->y));
7219566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,bjac->y));
7229566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->x));
7239566063dSJacob Faibussowitsch   PetscCall(VecResetArray(bjac->y));
7249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&x_array));
7259566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&y_array));
7264b9ad928SBarry Smith   PetscFunctionReturn(0);
7274b9ad928SBarry Smith }
7284b9ad928SBarry Smith 
7296849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Singleblock(PC pc,Mat mat,Mat pmat)
7304b9ad928SBarry Smith {
7314b9ad928SBarry Smith   PC_BJacobi             *jac = (PC_BJacobi*)pc->data;
73269a612a9SBarry Smith   PetscInt               m;
7334b9ad928SBarry Smith   KSP                    ksp;
7344b9ad928SBarry Smith   PC_BJacobi_Singleblock *bjac;
735de0953f6SBarry Smith   PetscBool              wasSetup = PETSC_TRUE;
7363f6dc190SJunchao Zhang   VecType                vectype;
737ea41da7aSPierre Jolivet   const char             *prefix;
7384b9ad928SBarry Smith 
7394b9ad928SBarry Smith   PetscFunctionBegin;
7404b9ad928SBarry Smith   if (!pc->setupcalled) {
741c2efdce3SBarry Smith     if (!jac->ksp) {
742302a9ddcSMatthew Knepley       wasSetup = PETSC_FALSE;
7432fa5cd67SKarl Rupp 
7449566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF,&ksp));
7459566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ksp,pc->erroriffailure));
7469566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1));
7479566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ksp));
7489566063dSJacob Faibussowitsch       PetscCall(KSPSetType(ksp,KSPPREONLY));
7499566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc,&prefix));
7509566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp,prefix));
7519566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ksp,"sub_"));
7524b9ad928SBarry Smith 
753e91c6855SBarry Smith       pc->ops->reset               = PCReset_BJacobi_Singleblock;
7544b9ad928SBarry Smith       pc->ops->destroy             = PCDestroy_BJacobi_Singleblock;
7554b9ad928SBarry Smith       pc->ops->apply               = PCApply_BJacobi_Singleblock;
7567b6e2003SPierre Jolivet       pc->ops->matapply            = PCMatApply_BJacobi_Singleblock;
7574b9ad928SBarry Smith       pc->ops->applysymmetricleft  = PCApplySymmetricLeft_BJacobi_Singleblock;
7584b9ad928SBarry Smith       pc->ops->applysymmetricright = PCApplySymmetricRight_BJacobi_Singleblock;
7594b9ad928SBarry Smith       pc->ops->applytranspose      = PCApplyTranspose_BJacobi_Singleblock;
7604b9ad928SBarry Smith       pc->ops->setuponblocks       = PCSetUpOnBlocks_BJacobi_Singleblock;
7614b9ad928SBarry Smith 
7629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1,&jac->ksp));
7634b9ad928SBarry Smith       jac->ksp[0] = ksp;
764c2efdce3SBarry Smith 
7659566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc,&bjac));
7664b9ad928SBarry Smith       jac->data = (void*)bjac;
7674b9ad928SBarry Smith     } else {
768c2efdce3SBarry Smith       ksp  = jac->ksp[0];
769c2efdce3SBarry Smith       bjac = (PC_BJacobi_Singleblock*)jac->data;
770c2efdce3SBarry Smith     }
771c2efdce3SBarry Smith 
772c2efdce3SBarry Smith     /*
773c2efdce3SBarry Smith       The reason we need to generate these vectors is to serve
774c2efdce3SBarry Smith       as the right-hand side and solution vector for the solve on the
775c2efdce3SBarry Smith       block. We do not need to allocate space for the vectors since
776c2efdce3SBarry Smith       that is provided via VecPlaceArray() just before the call to
777c2efdce3SBarry Smith       KSPSolve() on the block.
778c2efdce3SBarry Smith     */
7799566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pmat,&m,&m));
7809566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&bjac->x));
7819566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&bjac->y));
7829566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat,&vectype));
7839566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->x,vectype));
7849566063dSJacob Faibussowitsch     PetscCall(VecSetType(bjac->y,vectype));
7859566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->x));
7869566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->y));
787c2efdce3SBarry Smith   } else {
7884b9ad928SBarry Smith     ksp  = jac->ksp[0];
7894b9ad928SBarry Smith     bjac = (PC_BJacobi_Singleblock*)jac->data;
7904b9ad928SBarry Smith   }
7919566063dSJacob Faibussowitsch   PetscCall(KSPGetOptionsPrefix(ksp,&prefix));
79249517cdeSBarry Smith   if (pc->useAmat) {
7939566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp,mat,pmat));
7949566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mat,prefix));
7954b9ad928SBarry Smith   } else {
7969566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp,pmat,pmat));
7974b9ad928SBarry Smith   }
7989566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(pmat,prefix));
79990f1c854SHong Zhang   if (!wasSetup && pc->setfromoptionscalled) {
800248bfaf0SJed Brown     /* If PCSetFromOptions_BJacobi is called later, KSPSetFromOptions will be called at that time. */
8019566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ksp));
802302a9ddcSMatthew Knepley   }
8034b9ad928SBarry Smith   PetscFunctionReturn(0);
8044b9ad928SBarry Smith }
8054b9ad928SBarry Smith 
8064b9ad928SBarry Smith /* ---------------------------------------------------------------------------------------------*/
80781f0254dSBarry Smith static PetscErrorCode PCReset_BJacobi_Multiblock(PC pc)
8084b9ad928SBarry Smith {
8094b9ad928SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi*)pc->data;
8104b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
81169a612a9SBarry Smith   PetscInt              i;
8124b9ad928SBarry Smith 
8134b9ad928SBarry Smith   PetscFunctionBegin;
814e91c6855SBarry Smith   if (bjac && bjac->pmat) {
8159566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->n_local,&bjac->pmat));
81649517cdeSBarry Smith     if (pc->useAmat) {
8179566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(jac->n_local,&bjac->mat));
8184b9ad928SBarry Smith     }
819e91c6855SBarry Smith   }
8204b9ad928SBarry Smith 
8214b9ad928SBarry Smith   for (i=0; i<jac->n_local; i++) {
8229566063dSJacob Faibussowitsch     PetscCall(KSPReset(jac->ksp[i]));
823e91c6855SBarry Smith     if (bjac && bjac->x) {
8249566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->x[i]));
8259566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bjac->y[i]));
8269566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&bjac->is[i]));
8274b9ad928SBarry Smith     }
828e91c6855SBarry Smith   }
8299566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->l_lens));
8309566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->g_lens));
831e91c6855SBarry Smith   PetscFunctionReturn(0);
832e91c6855SBarry Smith }
833e91c6855SBarry Smith 
83481f0254dSBarry Smith static PetscErrorCode PCDestroy_BJacobi_Multiblock(PC pc)
835e91c6855SBarry Smith {
836e91c6855SBarry Smith   PC_BJacobi            *jac  = (PC_BJacobi*)pc->data;
837c2efdce3SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
838e91c6855SBarry Smith   PetscInt              i;
839e91c6855SBarry Smith 
840e91c6855SBarry Smith   PetscFunctionBegin;
8419566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiblock(pc));
842c2efdce3SBarry Smith   if (bjac) {
8439566063dSJacob Faibussowitsch     PetscCall(PetscFree2(bjac->x,bjac->y));
8449566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->starts));
8459566063dSJacob Faibussowitsch     PetscCall(PetscFree(bjac->is));
846c2efdce3SBarry Smith   }
8479566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->data));
848e91c6855SBarry Smith   for (i=0; i<jac->n_local; i++) {
8499566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&jac->ksp[i]));
850e91c6855SBarry Smith   }
8519566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
8529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
8534b9ad928SBarry Smith   PetscFunctionReturn(0);
8544b9ad928SBarry Smith }
8554b9ad928SBarry Smith 
85681f0254dSBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiblock(PC pc)
8574b9ad928SBarry Smith {
8584b9ad928SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
85969a612a9SBarry Smith   PetscInt           i,n_local = jac->n_local;
860539c167fSBarry Smith   KSPConvergedReason reason;
8614b9ad928SBarry Smith 
8624b9ad928SBarry Smith   PetscFunctionBegin;
8634b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
8649566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(jac->ksp[i]));
8659566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(jac->ksp[i],&reason));
866c0decd05SBarry Smith     if (reason == KSP_DIVERGED_PC_FAILED) {
867261222b2SHong Zhang       pc->failedreason = PC_SUBPC_ERROR;
8682295b7c8SHong Zhang     }
8694b9ad928SBarry Smith   }
8704b9ad928SBarry Smith   PetscFunctionReturn(0);
8714b9ad928SBarry Smith }
8724b9ad928SBarry Smith 
8734b9ad928SBarry Smith /*
8744b9ad928SBarry Smith       Preconditioner for block Jacobi
8754b9ad928SBarry Smith */
87681f0254dSBarry Smith static PetscErrorCode PCApply_BJacobi_Multiblock(PC pc,Vec x,Vec y)
8774b9ad928SBarry Smith {
8784b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi*)pc->data;
87969a612a9SBarry Smith   PetscInt              i,n_local = jac->n_local;
8804b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
881d9ca1df4SBarry Smith   PetscScalar           *yin;
882d9ca1df4SBarry Smith   const PetscScalar     *xin;
88358ebbce7SBarry Smith 
8844b9ad928SBarry Smith   PetscFunctionBegin;
8859566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&xin));
8869566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&yin));
8874b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
8884b9ad928SBarry Smith     /*
8894b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
8904b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
8914b9ad928SBarry Smith        the global vector.
8924b9ad928SBarry Smith     */
8939566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i],xin+bjac->starts[i]));
8949566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i],yin+bjac->starts[i]));
8954b9ad928SBarry Smith 
8969566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
8979566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->ksp[i],bjac->x[i],bjac->y[i]));
8989566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i],pc,bjac->y[i]));
8999566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
900d11f3a42SBarry Smith 
9019566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9029566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9034b9ad928SBarry Smith   }
9049566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&xin));
9059566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&yin));
9064b9ad928SBarry Smith   PetscFunctionReturn(0);
9074b9ad928SBarry Smith }
9084b9ad928SBarry Smith 
9094b9ad928SBarry Smith /*
9104b9ad928SBarry Smith       Preconditioner for block Jacobi
9114b9ad928SBarry Smith */
91281f0254dSBarry Smith static PetscErrorCode PCApplyTranspose_BJacobi_Multiblock(PC pc,Vec x,Vec y)
9134b9ad928SBarry Smith {
9144b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi*)pc->data;
91569a612a9SBarry Smith   PetscInt              i,n_local = jac->n_local;
9164b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
917d9ca1df4SBarry Smith   PetscScalar           *yin;
918d9ca1df4SBarry Smith   const PetscScalar     *xin;
9194b9ad928SBarry Smith 
9204b9ad928SBarry Smith   PetscFunctionBegin;
9219566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&xin));
9229566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&yin));
9234b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
9244b9ad928SBarry Smith     /*
9254b9ad928SBarry Smith        To avoid copying the subvector from x into a workspace we instead
9264b9ad928SBarry Smith        make the workspace vector array point to the subpart of the array of
9274b9ad928SBarry Smith        the global vector.
9284b9ad928SBarry Smith     */
9299566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->x[i],xin+bjac->starts[i]));
9309566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bjac->y[i],yin+bjac->starts[i]));
9314b9ad928SBarry Smith 
9329566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_ApplyTransposeOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
9339566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(jac->ksp[i],bjac->x[i],bjac->y[i]));
9349566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->ksp[i],pc,bjac->y[i]));
9359566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_ApplyTransposeOnBlocks,jac->ksp[i],bjac->x[i],bjac->y[i],0));
936a7ff49e8SJed Brown 
9379566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->x[i]));
9389566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bjac->y[i]));
9394b9ad928SBarry Smith   }
9409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&xin));
9419566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&yin));
9424b9ad928SBarry Smith   PetscFunctionReturn(0);
9434b9ad928SBarry Smith }
9444b9ad928SBarry Smith 
9456849ba73SBarry Smith static PetscErrorCode PCSetUp_BJacobi_Multiblock(PC pc,Mat mat,Mat pmat)
9464b9ad928SBarry Smith {
9474b9ad928SBarry Smith   PC_BJacobi            *jac = (PC_BJacobi*)pc->data;
94869a612a9SBarry Smith   PetscInt              m,n_local,N,M,start,i;
949ea41da7aSPierre Jolivet   const char            *prefix;
9504b9ad928SBarry Smith   KSP                   ksp;
9514b9ad928SBarry Smith   Vec                   x,y;
9524b9ad928SBarry Smith   PC_BJacobi_Multiblock *bjac = (PC_BJacobi_Multiblock*)jac->data;
9534b9ad928SBarry Smith   PC                    subpc;
9544b9ad928SBarry Smith   IS                    is;
955434a97beSBrad Aagaard   MatReuse              scall;
9563f6dc190SJunchao Zhang   VecType               vectype;
9574b9ad928SBarry Smith 
9584b9ad928SBarry Smith   PetscFunctionBegin;
9599566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat,&M,&N));
9604b9ad928SBarry Smith 
9614b9ad928SBarry Smith   n_local = jac->n_local;
9624b9ad928SBarry Smith 
96349517cdeSBarry Smith   if (pc->useAmat) {
964ace3abfcSBarry Smith     PetscBool same;
9659566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat,((PetscObject)pmat)->type_name,&same));
96628b400f6SJacob Faibussowitsch     PetscCheck(same,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Matrices not of same type");
9674b9ad928SBarry Smith   }
9684b9ad928SBarry Smith 
9694b9ad928SBarry Smith   if (!pc->setupcalled) {
9704b9ad928SBarry Smith     scall = MAT_INITIAL_MATRIX;
971c2efdce3SBarry Smith 
972c2efdce3SBarry Smith     if (!jac->ksp) {
973e91c6855SBarry Smith       pc->ops->reset         = PCReset_BJacobi_Multiblock;
9744b9ad928SBarry Smith       pc->ops->destroy       = PCDestroy_BJacobi_Multiblock;
9754b9ad928SBarry Smith       pc->ops->apply         = PCApply_BJacobi_Multiblock;
9767b6e2003SPierre Jolivet       pc->ops->matapply      = NULL;
9774b9ad928SBarry Smith       pc->ops->applytranspose= PCApplyTranspose_BJacobi_Multiblock;
9784b9ad928SBarry Smith       pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiblock;
9794b9ad928SBarry Smith 
9809566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(pc,&bjac));
9819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&jac->ksp));
9829566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(KSP))));
9839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(n_local,&bjac->x,n_local,&bjac->y));
9849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&bjac->starts));
9859566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(PetscScalar))));
9864b9ad928SBarry Smith 
9874b9ad928SBarry Smith       jac->data = (void*)bjac;
9889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n_local,&bjac->is));
9899566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(n_local*sizeof(IS))));
9904b9ad928SBarry Smith 
9914b9ad928SBarry Smith       for (i=0; i<n_local; i++) {
9929566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF,&ksp));
9939566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp,pc->erroriffailure));
9949566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1));
9959566063dSJacob Faibussowitsch         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ksp));
9969566063dSJacob Faibussowitsch         PetscCall(KSPSetType(ksp,KSPPREONLY));
9979566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp,&subpc));
9989566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc,&prefix));
9999566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp,prefix));
10009566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp,"sub_"));
10012fa5cd67SKarl Rupp 
1002c2efdce3SBarry Smith         jac->ksp[i] = ksp;
1003c2efdce3SBarry Smith       }
1004c2efdce3SBarry Smith     } else {
1005c2efdce3SBarry Smith       bjac = (PC_BJacobi_Multiblock*)jac->data;
1006c2efdce3SBarry Smith     }
10074b9ad928SBarry Smith 
1008c2efdce3SBarry Smith     start = 0;
10099566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(pmat,&vectype));
1010c2efdce3SBarry Smith     for (i=0; i<n_local; i++) {
10114b9ad928SBarry Smith       m = jac->l_lens[i];
10124b9ad928SBarry Smith       /*
10134b9ad928SBarry Smith       The reason we need to generate these vectors is to serve
10144b9ad928SBarry Smith       as the right-hand side and solution vector for the solve on the
10154b9ad928SBarry Smith       block. We do not need to allocate space for the vectors since
10164b9ad928SBarry Smith       that is provided via VecPlaceArray() just before the call to
10174b9ad928SBarry Smith       KSPSolve() on the block.
10184b9ad928SBarry Smith 
10194b9ad928SBarry Smith       */
10209566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF,m,&x));
10219566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,m,NULL,&y));
10229566063dSJacob Faibussowitsch       PetscCall(VecSetType(x,vectype));
10239566063dSJacob Faibussowitsch       PetscCall(VecSetType(y,vectype));
10249566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)x));
10259566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)y));
10262fa5cd67SKarl Rupp 
10274b9ad928SBarry Smith       bjac->x[i]      = x;
10284b9ad928SBarry Smith       bjac->y[i]      = y;
10294b9ad928SBarry Smith       bjac->starts[i] = start;
10304b9ad928SBarry Smith 
10319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF,m,start,1,&is));
10324b9ad928SBarry Smith       bjac->is[i] = is;
10339566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)is));
10344b9ad928SBarry Smith 
10354b9ad928SBarry Smith       start += m;
10364b9ad928SBarry Smith     }
10374b9ad928SBarry Smith   } else {
10384b9ad928SBarry Smith     bjac = (PC_BJacobi_Multiblock*)jac->data;
10394b9ad928SBarry Smith     /*
10404b9ad928SBarry Smith        Destroy the blocks from the previous iteration
10414b9ad928SBarry Smith     */
10424b9ad928SBarry Smith     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
10439566063dSJacob Faibussowitsch       PetscCall(MatDestroyMatrices(n_local,&bjac->pmat));
104449517cdeSBarry Smith       if (pc->useAmat) {
10459566063dSJacob Faibussowitsch         PetscCall(MatDestroyMatrices(n_local,&bjac->mat));
10464b9ad928SBarry Smith       }
10474b9ad928SBarry Smith       scall = MAT_INITIAL_MATRIX;
10482fa5cd67SKarl Rupp     } else scall = MAT_REUSE_MATRIX;
10494b9ad928SBarry Smith   }
10504b9ad928SBarry Smith 
10519566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(pmat,n_local,bjac->is,bjac->is,scall,&bjac->pmat));
105249517cdeSBarry Smith   if (pc->useAmat) {
10539566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(mat,n_local,bjac->is,bjac->is,scall,&bjac->mat));
10544b9ad928SBarry Smith   }
10554b9ad928SBarry Smith   /* Return control to the user so that the submatrices can be modified (e.g., to apply
10564b9ad928SBarry Smith      different boundary conditions for the submatrices than for the global problem) */
10579566063dSJacob Faibussowitsch   PetscCall(PCModifySubMatrices(pc,n_local,bjac->is,bjac->is,bjac->pmat,pc->modifysubmatricesP));
10584b9ad928SBarry Smith 
10594b9ad928SBarry Smith   for (i=0; i<n_local; i++) {
10609566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->pmat[i]));
10619566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[i],&prefix));
106249517cdeSBarry Smith     if (pc->useAmat) {
10639566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)bjac->mat[i]));
10649566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i],bjac->mat[i],bjac->pmat[i]));
10659566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(bjac->mat[i],prefix));
10664b9ad928SBarry Smith     } else {
10679566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->ksp[i],bjac->pmat[i],bjac->pmat[i]));
10684b9ad928SBarry Smith     }
10699566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(bjac->pmat[i],prefix));
107090f1c854SHong Zhang     if (pc->setfromoptionscalled) {
10719566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->ksp[i]));
10724b9ad928SBarry Smith     }
107390f1c854SHong Zhang   }
10744b9ad928SBarry Smith   PetscFunctionReturn(0);
10754b9ad928SBarry Smith }
10765a7e1895SHong Zhang 
10775a7e1895SHong Zhang /* ---------------------------------------------------------------------------------------------*/
10785a7e1895SHong Zhang /*
1079fd0b8932SBarry Smith       These are for a single block with multiple processes
10805a7e1895SHong Zhang */
1081fd0b8932SBarry Smith static PetscErrorCode PCSetUpOnBlocks_BJacobi_Multiproc(PC pc)
1082fd0b8932SBarry Smith {
1083fd0b8932SBarry Smith   PC_BJacobi         *jac = (PC_BJacobi*)pc->data;
1084fd0b8932SBarry Smith   KSP                subksp = jac->ksp[0];
1085fd0b8932SBarry Smith   KSPConvergedReason reason;
1086fd0b8932SBarry Smith 
1087fd0b8932SBarry Smith   PetscFunctionBegin;
10889566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(subksp));
10899566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(subksp,&reason));
1090fd0b8932SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
1091fd0b8932SBarry Smith     pc->failedreason = PC_SUBPC_ERROR;
1092fd0b8932SBarry Smith   }
1093fd0b8932SBarry Smith   PetscFunctionReturn(0);
1094fd0b8932SBarry Smith }
1095fd0b8932SBarry Smith 
1096e91c6855SBarry Smith static PetscErrorCode PCReset_BJacobi_Multiproc(PC pc)
10975a7e1895SHong Zhang {
10985a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
10995a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
11005a7e1895SHong Zhang 
11015a7e1895SHong Zhang   PetscFunctionBegin;
11029566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->ysub));
11039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&mpjac->xsub));
11049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mpjac->submats));
11059566063dSJacob Faibussowitsch   if (jac->ksp) PetscCall(KSPReset(jac->ksp[0]));
1106e91c6855SBarry Smith   PetscFunctionReturn(0);
1107e91c6855SBarry Smith }
1108e91c6855SBarry Smith 
1109e91c6855SBarry Smith static PetscErrorCode PCDestroy_BJacobi_Multiproc(PC pc)
1110e91c6855SBarry Smith {
1111e91c6855SBarry Smith   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
1112e91c6855SBarry Smith   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
1113e91c6855SBarry Smith 
1114e91c6855SBarry Smith   PetscFunctionBegin;
11159566063dSJacob Faibussowitsch   PetscCall(PCReset_BJacobi_Multiproc(pc));
11169566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->ksp[0]));
11179566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->ksp));
11189566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&mpjac->psubcomm));
11195a7e1895SHong Zhang 
11209566063dSJacob Faibussowitsch   PetscCall(PetscFree(mpjac));
11219566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
11225a7e1895SHong Zhang   PetscFunctionReturn(0);
11235a7e1895SHong Zhang }
11245a7e1895SHong Zhang 
11255a7e1895SHong Zhang static PetscErrorCode PCApply_BJacobi_Multiproc(PC pc,Vec x,Vec y)
11265a7e1895SHong Zhang {
11275a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11285a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
1129d9ca1df4SBarry Smith   PetscScalar          *yarray;
1130d9ca1df4SBarry Smith   const PetscScalar    *xarray;
1131539c167fSBarry Smith   KSPConvergedReason   reason;
11325a7e1895SHong Zhang 
11335a7e1895SHong Zhang   PetscFunctionBegin;
11345a7e1895SHong Zhang   /* place x's and y's local arrays into xsub and ysub */
11359566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x,&xarray));
11369566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y,&yarray));
11379566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->xsub,xarray));
11389566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(mpjac->ysub,yarray));
11395a7e1895SHong Zhang 
11405a7e1895SHong Zhang   /* apply preconditioner on each matrix block */
11419566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks,jac->ksp[0],mpjac->xsub,mpjac->ysub,0));
11429566063dSJacob Faibussowitsch   PetscCall(KSPSolve(jac->ksp[0],mpjac->xsub,mpjac->ysub));
11439566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,mpjac->ysub));
11449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks,jac->ksp[0],mpjac->xsub,mpjac->ysub,0));
11459566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0],&reason));
1146c0decd05SBarry Smith   if (reason == KSP_DIVERGED_PC_FAILED) {
1147261222b2SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
1148250cf88bSHong Zhang   }
1149250cf88bSHong Zhang 
11509566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->xsub));
11519566063dSJacob Faibussowitsch   PetscCall(VecResetArray(mpjac->ysub));
11529566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x,&xarray));
11539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y,&yarray));
11545a7e1895SHong Zhang   PetscFunctionReturn(0);
11555a7e1895SHong Zhang }
11565a7e1895SHong Zhang 
11577b6e2003SPierre Jolivet static PetscErrorCode PCMatApply_BJacobi_Multiproc(PC pc,Mat X,Mat Y)
11587b6e2003SPierre Jolivet {
11597b6e2003SPierre Jolivet   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11607b6e2003SPierre Jolivet   KSPConvergedReason   reason;
11617b6e2003SPierre Jolivet   Mat                  sX,sY;
11627b6e2003SPierre Jolivet   const PetscScalar    *x;
11637b6e2003SPierre Jolivet   PetscScalar          *y;
11647b6e2003SPierre Jolivet   PetscInt             m,N,lda,ldb;
11657b6e2003SPierre Jolivet 
11667b6e2003SPierre Jolivet   PetscFunctionBegin;
11677b6e2003SPierre Jolivet   /* apply preconditioner on each matrix block */
11689566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X,&m,NULL));
11699566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X,NULL,&N));
11709566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X,&lda));
11719566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(Y,&ldb));
11729566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(X,&x));
11739566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(Y,&y));
11749566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]),m,PETSC_DECIDE,PETSC_DECIDE,N,(PetscScalar*)x,&sX));
11759566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->ksp[0]),m,PETSC_DECIDE,PETSC_DECIDE,N,y,&sY));
11769566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sX,lda));
11779566063dSJacob Faibussowitsch   PetscCall(MatDenseSetLDA(sY,ldb));
11789566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_ApplyOnBlocks,jac->ksp[0],X,Y,0));
11799566063dSJacob Faibussowitsch   PetscCall(KSPMatSolve(jac->ksp[0],sX,sY));
11809566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(jac->ksp[0],pc,NULL));
11819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_ApplyOnBlocks,jac->ksp[0],X,Y,0));
11829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sY));
11839566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sX));
11849566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(Y,&y));
11859566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(X,&x));
11869566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(jac->ksp[0],&reason));
11877b6e2003SPierre Jolivet   if (reason == KSP_DIVERGED_PC_FAILED) {
11887b6e2003SPierre Jolivet     pc->failedreason = PC_SUBPC_ERROR;
11897b6e2003SPierre Jolivet   }
11907b6e2003SPierre Jolivet   PetscFunctionReturn(0);
11917b6e2003SPierre Jolivet }
11927b6e2003SPierre Jolivet 
11935a7e1895SHong Zhang static PetscErrorCode PCSetUp_BJacobi_Multiproc(PC pc)
11945a7e1895SHong Zhang {
11955a7e1895SHong Zhang   PC_BJacobi           *jac   = (PC_BJacobi*)pc->data;
11965a7e1895SHong Zhang   PC_BJacobi_Multiproc *mpjac = (PC_BJacobi_Multiproc*)jac->data;
11975a7e1895SHong Zhang   PetscInt             m,n;
1198ce94432eSBarry Smith   MPI_Comm             comm,subcomm=0;
11995a7e1895SHong Zhang   const char           *prefix;
1200de0953f6SBarry Smith   PetscBool            wasSetup = PETSC_TRUE;
12013f6dc190SJunchao Zhang   VecType              vectype;
12021f62890fSKarl Rupp 
12035a7e1895SHong Zhang   PetscFunctionBegin;
12049566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
120508401ef6SPierre Jolivet   PetscCheck(jac->n_local <= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Only a single block in a subcommunicator is supported");
12065a7e1895SHong Zhang   jac->n_local = 1; /* currently only a single block is supported for a subcommunicator */
12075a7e1895SHong Zhang   if (!pc->setupcalled) {
1208de0953f6SBarry Smith     wasSetup  = PETSC_FALSE;
12099566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(pc,&mpjac));
12105a7e1895SHong Zhang     jac->data = (void*)mpjac;
12115a7e1895SHong Zhang 
12125a7e1895SHong Zhang     /* initialize datastructure mpjac */
12135a7e1895SHong Zhang     if (!jac->psubcomm) {
12145a7e1895SHong Zhang       /* Create default contiguous subcommunicatiors if user does not provide them */
12159566063dSJacob Faibussowitsch       PetscCall(PetscSubcommCreate(comm,&jac->psubcomm));
12169566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetNumber(jac->psubcomm,jac->n));
12179566063dSJacob Faibussowitsch       PetscCall(PetscSubcommSetType(jac->psubcomm,PETSC_SUBCOMM_CONTIGUOUS));
12189566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectMemory((PetscObject)pc,sizeof(PetscSubcomm)));
12195a7e1895SHong Zhang     }
12205a7e1895SHong Zhang     mpjac->psubcomm = jac->psubcomm;
1221306c2d5bSBarry Smith     subcomm         = PetscSubcommChild(mpjac->psubcomm);
12225a7e1895SHong Zhang 
12235a7e1895SHong Zhang     /* Get matrix blocks of pmat */
12249566063dSJacob Faibussowitsch     PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_INITIAL_MATRIX,&mpjac->submats));
12255a7e1895SHong Zhang 
12265a7e1895SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
12279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1,&jac->ksp));
12289566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm,&jac->ksp[0]));
12299566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(jac->ksp[0],pc->erroriffailure));
12309566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp[0],(PetscObject)pc,1));
12319566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->ksp[0]));
12329566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0],mpjac->submats,mpjac->submats));
12339566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(jac->ksp[0],&mpjac->pc));
12345a7e1895SHong Zhang 
12359566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc,&prefix));
12369566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(jac->ksp[0],prefix));
12379566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(jac->ksp[0],"sub_"));
12389566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(jac->ksp[0],&prefix));
12399566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(mpjac->submats,prefix));
12405a7e1895SHong Zhang 
12415a7e1895SHong Zhang     /* create dummy vectors xsub and ysub */
12429566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mpjac->submats,&m,&n));
12439566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm,1,n,PETSC_DECIDE,NULL,&mpjac->xsub));
12449566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(subcomm,1,m,PETSC_DECIDE,NULL,&mpjac->ysub));
12459566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(mpjac->submats,&vectype));
12469566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->xsub,vectype));
12479566063dSJacob Faibussowitsch     PetscCall(VecSetType(mpjac->ysub,vectype));
12489566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)mpjac->xsub));
12499566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)mpjac->ysub));
12505a7e1895SHong Zhang 
1251fd0b8932SBarry Smith     pc->ops->setuponblocks = PCSetUpOnBlocks_BJacobi_Multiproc;
1252e91c6855SBarry Smith     pc->ops->reset         = PCReset_BJacobi_Multiproc;
12535a7e1895SHong Zhang     pc->ops->destroy       = PCDestroy_BJacobi_Multiproc;
12545a7e1895SHong Zhang     pc->ops->apply         = PCApply_BJacobi_Multiproc;
12557b6e2003SPierre Jolivet     pc->ops->matapply      = PCMatApply_BJacobi_Multiproc;
1256fc08c53fSHong Zhang   } else { /* pc->setupcalled */
1257306c2d5bSBarry Smith     subcomm = PetscSubcommChild(mpjac->psubcomm);
12589e0ae222SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
12595a7e1895SHong Zhang       /* destroy old matrix blocks, then get new matrix blocks */
12609566063dSJacob Faibussowitsch       if (mpjac->submats) PetscCall(MatDestroy(&mpjac->submats));
12619566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_INITIAL_MATRIX,&mpjac->submats));
1262fc08c53fSHong Zhang     } else {
12639566063dSJacob Faibussowitsch       PetscCall(MatGetMultiProcBlock(pc->pmat,subcomm,MAT_REUSE_MATRIX,&mpjac->submats));
12645a7e1895SHong Zhang     }
12659566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(jac->ksp[0],mpjac->submats,mpjac->submats));
12665a7e1895SHong Zhang   }
12675a7e1895SHong Zhang 
1268de0953f6SBarry Smith   if (!wasSetup && pc->setfromoptionscalled) {
12699566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(jac->ksp[0]));
12705a7e1895SHong Zhang   }
12715a7e1895SHong Zhang   PetscFunctionReturn(0);
12725a7e1895SHong Zhang }
1273