xref: /petsc/src/ksp/pc/impls/telescope/telescope_dmda.c (revision 9566063d113dddea24716c546802770db7481bc0)
11e07b27eSBarry Smith 
2120bdd93SDave May #include <petsc/private/matimpl.h>
31e07b27eSBarry Smith #include <petsc/private/pcimpl.h>
45e897e82SDave May #include <petsc/private/dmimpl.h>
51e07b27eSBarry Smith #include <petscksp.h>           /*I "petscksp.h" I*/
61e07b27eSBarry Smith #include <petscdm.h>
71e07b27eSBarry Smith #include <petscdmda.h>
81e07b27eSBarry Smith 
9575a0592SBarry Smith #include "../src/ksp/pc/impls/telescope/telescope.h"
101e07b27eSBarry Smith 
11bf00f589SPatrick Sanan static PetscBool  cited = PETSC_FALSE;
12bf00f589SPatrick Sanan static const char citation[] =
13bf00f589SPatrick Sanan "@inproceedings{MaySananRuppKnepleySmith2016,\n"
14bf00f589SPatrick Sanan "  title     = {Extreme-Scale Multigrid Components within PETSc},\n"
15bf00f589SPatrick Sanan "  author    = {Dave A. May and Patrick Sanan and Karl Rupp and Matthew G. Knepley and Barry F. Smith},\n"
16bf00f589SPatrick Sanan "  booktitle = {Proceedings of the Platform for Advanced Scientific Computing Conference},\n"
17bf00f589SPatrick Sanan "  series    = {PASC '16},\n"
18bf00f589SPatrick Sanan "  isbn      = {978-1-4503-4126-4},\n"
19bf00f589SPatrick Sanan "  location  = {Lausanne, Switzerland},\n"
20bf00f589SPatrick Sanan "  pages     = {5:1--5:12},\n"
21bf00f589SPatrick Sanan "  articleno = {5},\n"
22bf00f589SPatrick Sanan "  numpages  = {12},\n"
23a8d69d7bSBarry Smith "  url       = {https://doi.acm.org/10.1145/2929908.2929913},\n"
24bf00f589SPatrick Sanan "  doi       = {10.1145/2929908.2929913},\n"
25bf00f589SPatrick Sanan "  acmid     = {2929913},\n"
26bf00f589SPatrick Sanan "  publisher = {ACM},\n"
27bf00f589SPatrick Sanan "  address   = {New York, NY, USA},\n"
28bf00f589SPatrick Sanan "  keywords  = {GPU, HPC, agglomeration, coarse-level solver, multigrid, parallel computing, preconditioning},\n"
29bf00f589SPatrick Sanan "  year      = {2016}\n"
30bf00f589SPatrick Sanan "}\n";
31bf00f589SPatrick Sanan 
3257f12427SDave May static PetscErrorCode _DMDADetermineRankFromGlobalIJK(PetscInt dim,PetscInt i,PetscInt j,PetscInt k,
331e07b27eSBarry Smith                                                       PetscInt Mp,PetscInt Np,PetscInt Pp,
341e07b27eSBarry Smith                                                       PetscInt start_i[],PetscInt start_j[],PetscInt start_k[],
351e07b27eSBarry Smith                                                       PetscInt span_i[],PetscInt span_j[],PetscInt span_k[],
361e07b27eSBarry Smith                                                       PetscMPIInt *_pi,PetscMPIInt *_pj,PetscMPIInt *_pk,PetscMPIInt *rank_re)
371e07b27eSBarry Smith {
381e07b27eSBarry Smith   PetscInt pi,pj,pk,n;
391e07b27eSBarry Smith 
401e07b27eSBarry Smith   PetscFunctionBegin;
41137d0469SJed Brown   *rank_re = -1;
42137d0469SJed Brown   if (_pi) *_pi = -1;
43137d0469SJed Brown   if (_pj) *_pj = -1;
44137d0469SJed Brown   if (_pk) *_pk = -1;
451e07b27eSBarry Smith   pi = pj = pk = -1;
461e07b27eSBarry Smith   if (_pi) {
471e07b27eSBarry Smith     for (n=0; n<Mp; n++) {
481e07b27eSBarry Smith       if ((i >= start_i[n]) && (i < start_i[n]+span_i[n])) {
491e07b27eSBarry Smith         pi = n;
501e07b27eSBarry Smith         break;
511e07b27eSBarry Smith       }
521e07b27eSBarry Smith     }
532c71b3e2SJacob Faibussowitsch     PetscCheckFalse(pi == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pi cannot be determined : range %D, val %D",Mp,i);
541e07b27eSBarry Smith     *_pi = pi;
551e07b27eSBarry Smith   }
561e07b27eSBarry Smith 
571e07b27eSBarry Smith   if (_pj) {
581e07b27eSBarry Smith     for (n=0; n<Np; n++) {
591e07b27eSBarry Smith       if ((j >= start_j[n]) && (j < start_j[n]+span_j[n])) {
601e07b27eSBarry Smith         pj = n;
611e07b27eSBarry Smith         break;
621e07b27eSBarry Smith       }
631e07b27eSBarry Smith     }
642c71b3e2SJacob Faibussowitsch     PetscCheckFalse(pj == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pj cannot be determined : range %D, val %D",Np,j);
651e07b27eSBarry Smith     *_pj = pj;
661e07b27eSBarry Smith   }
671e07b27eSBarry Smith 
681e07b27eSBarry Smith   if (_pk) {
691e07b27eSBarry Smith     for (n=0; n<Pp; n++) {
701e07b27eSBarry Smith       if ((k >= start_k[n]) && (k < start_k[n]+span_k[n])) {
711e07b27eSBarry Smith         pk = n;
721e07b27eSBarry Smith         break;
731e07b27eSBarry Smith       }
741e07b27eSBarry Smith     }
752c71b3e2SJacob Faibussowitsch     PetscCheckFalse(pk == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pk cannot be determined : range %D, val %D",Pp,k);
761e07b27eSBarry Smith     *_pk = pk;
771e07b27eSBarry Smith   }
781e07b27eSBarry Smith 
791e07b27eSBarry Smith   switch (dim) {
801e07b27eSBarry Smith   case 1:
811e07b27eSBarry Smith     *rank_re = pi;
821e07b27eSBarry Smith     break;
831e07b27eSBarry Smith   case 2:
841e07b27eSBarry Smith     *rank_re = pi + pj * Mp;
851e07b27eSBarry Smith     break;
861e07b27eSBarry Smith   case 3:
871e07b27eSBarry Smith     *rank_re = pi + pj * Mp + pk * (Mp*Np);
881e07b27eSBarry Smith     break;
891e07b27eSBarry Smith   }
901e07b27eSBarry Smith   PetscFunctionReturn(0);
911e07b27eSBarry Smith }
921e07b27eSBarry Smith 
9357f12427SDave May static PetscErrorCode _DMDADetermineGlobalS0(PetscInt dim,PetscMPIInt rank_re,PetscInt Mp_re,PetscInt Np_re,PetscInt Pp_re,
941e07b27eSBarry Smith                                       PetscInt range_i_re[],PetscInt range_j_re[],PetscInt range_k_re[],PetscInt *s0)
951e07b27eSBarry Smith {
96c6a0d831SBarry Smith   PetscInt i,j,k,start_IJK = 0;
971e07b27eSBarry Smith   PetscInt rank_ijk;
981e07b27eSBarry Smith 
991e07b27eSBarry Smith   PetscFunctionBegin;
1001e07b27eSBarry Smith   switch (dim) {
1011e07b27eSBarry Smith   case 1:
1021e07b27eSBarry Smith     for (i=0; i<Mp_re; i++) {
1031e07b27eSBarry Smith       rank_ijk = i;
1041e07b27eSBarry Smith       if (rank_ijk < rank_re) {
1051e07b27eSBarry Smith         start_IJK += range_i_re[i];
1061e07b27eSBarry Smith       }
1071e07b27eSBarry Smith     }
1081e07b27eSBarry Smith     break;
1091e07b27eSBarry Smith     case 2:
1101e07b27eSBarry Smith     for (j=0; j<Np_re; j++) {
1111e07b27eSBarry Smith       for (i=0; i<Mp_re; i++) {
1121e07b27eSBarry Smith         rank_ijk = i + j*Mp_re;
1131e07b27eSBarry Smith         if (rank_ijk < rank_re) {
1141e07b27eSBarry Smith           start_IJK += range_i_re[i]*range_j_re[j];
1151e07b27eSBarry Smith         }
1161e07b27eSBarry Smith       }
1171e07b27eSBarry Smith     }
1181e07b27eSBarry Smith     break;
1191e07b27eSBarry Smith     case 3:
1201e07b27eSBarry Smith     for (k=0; k<Pp_re; k++) {
1211e07b27eSBarry Smith       for (j=0; j<Np_re; j++) {
1221e07b27eSBarry Smith         for (i=0; i<Mp_re; i++) {
1231e07b27eSBarry Smith           rank_ijk = i + j*Mp_re + k*Mp_re*Np_re;
1241e07b27eSBarry Smith           if (rank_ijk < rank_re) {
1251e07b27eSBarry Smith             start_IJK += range_i_re[i]*range_j_re[j]*range_k_re[k];
1261e07b27eSBarry Smith           }
1271e07b27eSBarry Smith         }
1281e07b27eSBarry Smith       }
1291e07b27eSBarry Smith     }
1301e07b27eSBarry Smith     break;
1311e07b27eSBarry Smith   }
1321e07b27eSBarry Smith   *s0 = start_IJK;
1331e07b27eSBarry Smith   PetscFunctionReturn(0);
1341e07b27eSBarry Smith }
1351e07b27eSBarry Smith 
13657f12427SDave May static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors2d(PC_Telescope sred,DM dm,DM subdm)
1371e07b27eSBarry Smith {
1381e07b27eSBarry Smith   DM             cdm;
1391e07b27eSBarry Smith   Vec            coor,coor_natural,perm_coors;
1401e07b27eSBarry Smith   PetscInt       i,j,si,sj,ni,nj,M,N,Ml,Nl,c,nidx;
1411e07b27eSBarry Smith   PetscInt       *fine_indices;
1421e07b27eSBarry Smith   IS             is_fine,is_local;
1431e07b27eSBarry Smith   VecScatter     sctx;
1441e07b27eSBarry Smith 
1451e07b27eSBarry Smith   PetscFunctionBegin;
146*9566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinates(dm,&coor));
1471e07b27eSBarry Smith   if (!coor) return(0);
14857f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
149*9566063dSJacob Faibussowitsch     PetscCall(DMDASetUniformCoordinates(subdm,0.0,1.0,0.0,1.0,0.0,1.0));
1501e07b27eSBarry Smith   }
1511e07b27eSBarry Smith   /* Get the coordinate vector from the distributed array */
152*9566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&cdm));
153*9566063dSJacob Faibussowitsch   PetscCall(DMDACreateNaturalVector(cdm,&coor_natural));
1541e07b27eSBarry Smith 
155*9566063dSJacob Faibussowitsch   PetscCall(DMDAGlobalToNaturalBegin(cdm,coor,INSERT_VALUES,coor_natural));
156*9566063dSJacob Faibussowitsch   PetscCall(DMDAGlobalToNaturalEnd(cdm,coor,INSERT_VALUES,coor_natural));
1571e07b27eSBarry Smith 
1581e07b27eSBarry Smith   /* get indices of the guys I want to grab */
159*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&M,&N,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
16057f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
161*9566063dSJacob Faibussowitsch     PetscCall(DMDAGetCorners(subdm,&si,&sj,NULL,&ni,&nj,NULL));
16215dd08bcSBarry Smith     Ml = ni;
16315dd08bcSBarry Smith     Nl = nj;
1641e07b27eSBarry Smith   } else {
165c41e779fSDave May     si = sj = 0;
166c41e779fSDave May     ni = nj = 0;
1673ac26c5eSBarry Smith     Ml = Nl = 0;
1681e07b27eSBarry Smith   }
1691e07b27eSBarry Smith 
170*9566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(Ml*Nl*2,&fine_indices));
1711e07b27eSBarry Smith   c = 0;
17257f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
1731e07b27eSBarry Smith     for (j=sj; j<sj+nj; j++) {
1741e07b27eSBarry Smith       for (i=si; i<si+ni; i++) {
1751e07b27eSBarry Smith         nidx = (i) + (j)*M;
1761e07b27eSBarry Smith         fine_indices[c  ] = 2 * nidx     ;
1771e07b27eSBarry Smith         fine_indices[c+1] = 2 * nidx + 1 ;
1781e07b27eSBarry Smith         c = c + 2;
1791e07b27eSBarry Smith       }
1801e07b27eSBarry Smith     }
1812c71b3e2SJacob Faibussowitsch     PetscCheckFalse(c != Ml*Nl*2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"c %D should equal 2 * Ml %D * Nl %D",c,Ml,Nl);
1821e07b27eSBarry Smith   }
1831e07b27eSBarry Smith 
1841e07b27eSBarry Smith   /* generate scatter */
185*9566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm),Ml*Nl*2,fine_indices,PETSC_USE_POINTER,&is_fine));
186*9566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,Ml*Nl*2,0,1,&is_local));
1871e07b27eSBarry Smith 
1881e07b27eSBarry Smith   /* scatter */
189*9566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF,&perm_coors));
190*9566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(perm_coors,PETSC_DECIDE,Ml*Nl*2));
191*9566063dSJacob Faibussowitsch   PetscCall(VecSetType(perm_coors,VECSEQ));
1921e07b27eSBarry Smith 
193*9566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(coor_natural,is_fine,perm_coors,is_local,&sctx));
194*9566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD));
195*9566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(  sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD));
1961e07b27eSBarry Smith   /* access */
19757f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
1981e07b27eSBarry Smith     Vec               _coors;
1991e07b27eSBarry Smith     const PetscScalar *LA_perm;
2001e07b27eSBarry Smith     PetscScalar       *LA_coors;
2011e07b27eSBarry Smith 
202*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(subdm,&_coors));
203*9566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(perm_coors,&LA_perm));
204*9566063dSJacob Faibussowitsch     PetscCall(VecGetArray(_coors,&LA_coors));
2051e07b27eSBarry Smith     for (i=0; i<Ml*Nl*2; i++) {
2061e07b27eSBarry Smith       LA_coors[i] = LA_perm[i];
2071e07b27eSBarry Smith     }
208*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(_coors,&LA_coors));
209*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(perm_coors,&LA_perm));
2101e07b27eSBarry Smith   }
2111e07b27eSBarry Smith 
2121e07b27eSBarry Smith   /* update local coords */
21357f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
2141e07b27eSBarry Smith     DM  _dmc;
2151e07b27eSBarry Smith     Vec _coors,_coors_local;
216*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(subdm,&_dmc));
217*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(subdm,&_coors));
218*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(subdm,&_coors_local));
219*9566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(_dmc,_coors,INSERT_VALUES,_coors_local));
220*9566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(_dmc,_coors,INSERT_VALUES,_coors_local));
2211e07b27eSBarry Smith   }
222*9566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sctx));
223*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_fine));
224*9566063dSJacob Faibussowitsch   PetscCall(PetscFree(fine_indices));
225*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_local));
226*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&perm_coors));
227*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coor_natural));
2281e07b27eSBarry Smith   PetscFunctionReturn(0);
2291e07b27eSBarry Smith }
2301e07b27eSBarry Smith 
23157f12427SDave May static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors3d(PC_Telescope sred,DM dm,DM subdm)
2321e07b27eSBarry Smith {
2331e07b27eSBarry Smith   DM             cdm;
2341e07b27eSBarry Smith   Vec            coor,coor_natural,perm_coors;
2351e07b27eSBarry Smith   PetscInt       i,j,k,si,sj,sk,ni,nj,nk,M,N,P,Ml,Nl,Pl,c,nidx;
2361e07b27eSBarry Smith   PetscInt       *fine_indices;
2371e07b27eSBarry Smith   IS             is_fine,is_local;
2381e07b27eSBarry Smith   VecScatter     sctx;
2391e07b27eSBarry Smith 
2401e07b27eSBarry Smith   PetscFunctionBegin;
241*9566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinates(dm,&coor));
2421e07b27eSBarry Smith   if (!coor) PetscFunctionReturn(0);
2431e07b27eSBarry Smith 
24457f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
245*9566063dSJacob Faibussowitsch     PetscCall(DMDASetUniformCoordinates(subdm,0.0,1.0,0.0,1.0,0.0,1.0));
2461e07b27eSBarry Smith   }
2471e07b27eSBarry Smith 
2481e07b27eSBarry Smith   /* Get the coordinate vector from the distributed array */
249*9566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&cdm));
250*9566063dSJacob Faibussowitsch   PetscCall(DMDACreateNaturalVector(cdm,&coor_natural));
251*9566063dSJacob Faibussowitsch   PetscCall(DMDAGlobalToNaturalBegin(cdm,coor,INSERT_VALUES,coor_natural));
252*9566063dSJacob Faibussowitsch   PetscCall(DMDAGlobalToNaturalEnd(cdm,coor,INSERT_VALUES,coor_natural));
2531e07b27eSBarry Smith 
2541e07b27eSBarry Smith   /* get indices of the guys I want to grab */
255*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&M,&N,&P,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
2561e07b27eSBarry Smith 
25757f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
258*9566063dSJacob Faibussowitsch     PetscCall(DMDAGetCorners(subdm,&si,&sj,&sk,&ni,&nj,&nk));
259553d0ae9SBarry Smith     Ml = ni;
260553d0ae9SBarry Smith     Nl = nj;
261553d0ae9SBarry Smith     Pl = nk;
2621e07b27eSBarry Smith   } else {
263c41e779fSDave May     si = sj = sk = 0;
264c41e779fSDave May     ni = nj = nk = 0;
2653ac26c5eSBarry Smith     Ml = Nl = Pl = 0;
2661e07b27eSBarry Smith   }
2671e07b27eSBarry Smith 
268*9566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(Ml*Nl*Pl*3,&fine_indices));
2691e07b27eSBarry Smith 
2701e07b27eSBarry Smith   c = 0;
27157f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
2721e07b27eSBarry Smith     for (k=sk; k<sk+nk; k++) {
2731e07b27eSBarry Smith       for (j=sj; j<sj+nj; j++) {
2741e07b27eSBarry Smith         for (i=si; i<si+ni; i++) {
2751e07b27eSBarry Smith           nidx = (i) + (j)*M + (k)*M*N;
2761e07b27eSBarry Smith           fine_indices[c  ] = 3 * nidx     ;
2771e07b27eSBarry Smith           fine_indices[c+1] = 3 * nidx + 1 ;
2781e07b27eSBarry Smith           fine_indices[c+2] = 3 * nidx + 2 ;
2791e07b27eSBarry Smith           c = c + 3;
2801e07b27eSBarry Smith         }
2811e07b27eSBarry Smith       }
2821e07b27eSBarry Smith     }
2831e07b27eSBarry Smith   }
2841e07b27eSBarry Smith 
2851e07b27eSBarry Smith   /* generate scatter */
286*9566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm),Ml*Nl*Pl*3,fine_indices,PETSC_USE_POINTER,&is_fine));
287*9566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,Ml*Nl*Pl*3,0,1,&is_local));
2881e07b27eSBarry Smith 
2891e07b27eSBarry Smith   /* scatter */
290*9566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF,&perm_coors));
291*9566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(perm_coors,PETSC_DECIDE,Ml*Nl*Pl*3));
292*9566063dSJacob Faibussowitsch   PetscCall(VecSetType(perm_coors,VECSEQ));
293*9566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(coor_natural,is_fine,perm_coors,is_local,&sctx));
294*9566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD));
295*9566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(  sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD));
2961e07b27eSBarry Smith 
2971e07b27eSBarry Smith   /* access */
29857f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
2991e07b27eSBarry Smith     Vec               _coors;
3001e07b27eSBarry Smith     const PetscScalar *LA_perm;
3011e07b27eSBarry Smith     PetscScalar       *LA_coors;
3021e07b27eSBarry Smith 
303*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(subdm,&_coors));
304*9566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(perm_coors,&LA_perm));
305*9566063dSJacob Faibussowitsch     PetscCall(VecGetArray(_coors,&LA_coors));
3061e07b27eSBarry Smith     for (i=0; i<Ml*Nl*Pl*3; i++) {
3071e07b27eSBarry Smith       LA_coors[i] = LA_perm[i];
3081e07b27eSBarry Smith     }
309*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(_coors,&LA_coors));
310*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(perm_coors,&LA_perm));
3111e07b27eSBarry Smith   }
3121e07b27eSBarry Smith 
3131e07b27eSBarry Smith   /* update local coords */
31457f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
3151e07b27eSBarry Smith     DM  _dmc;
3161e07b27eSBarry Smith     Vec _coors,_coors_local;
3171e07b27eSBarry Smith 
318*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(subdm,&_dmc));
319*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(subdm,&_coors));
320*9566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(subdm,&_coors_local));
321*9566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(_dmc,_coors,INSERT_VALUES,_coors_local));
322*9566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(_dmc,_coors,INSERT_VALUES,_coors_local));
3231e07b27eSBarry Smith   }
3241e07b27eSBarry Smith 
325*9566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sctx));
326*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_fine));
327*9566063dSJacob Faibussowitsch   PetscCall(PetscFree(fine_indices));
328*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_local));
329*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&perm_coors));
330*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coor_natural));
3311e07b27eSBarry Smith   PetscFunctionReturn(0);
3321e07b27eSBarry Smith }
3331e07b27eSBarry Smith 
33457f12427SDave May static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx)
3351e07b27eSBarry Smith {
3361e07b27eSBarry Smith   PetscInt       dim;
3371e07b27eSBarry Smith   DM             dm,subdm;
3381e07b27eSBarry Smith   PetscSubcomm   psubcomm;
3391e07b27eSBarry Smith   MPI_Comm       comm;
3401e07b27eSBarry Smith   Vec            coor;
3411e07b27eSBarry Smith 
3421e07b27eSBarry Smith   PetscFunctionBegin;
343*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
344*9566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinates(dm,&coor));
3451e07b27eSBarry Smith   if (!coor) PetscFunctionReturn(0);
3461e07b27eSBarry Smith   psubcomm = sred->psubcomm;
3471e07b27eSBarry Smith   comm = PetscSubcommParent(psubcomm);
3481e07b27eSBarry Smith   subdm = ctx->dmrepart;
3491e07b27eSBarry Smith 
350*9566063dSJacob Faibussowitsch   PetscCall(PetscInfo(pc,"PCTelescope: setting up the coordinates (DMDA)\n"));
351*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
3521e07b27eSBarry Smith   switch (dim) {
353b458e8f1SJose E. Roman   case 1:
354b458e8f1SJose E. Roman     SETERRQ(comm,PETSC_ERR_SUP,"Telescope: DMDA (1D) repartitioning not provided");
355*9566063dSJacob Faibussowitsch   case 2: PetscCall(PCTelescopeSetUp_dmda_repart_coors2d(sred,dm,subdm));
3561e07b27eSBarry Smith     break;
357*9566063dSJacob Faibussowitsch   case 3: PetscCall(PCTelescopeSetUp_dmda_repart_coors3d(sred,dm,subdm));
3581e07b27eSBarry Smith     break;
3591e07b27eSBarry Smith   }
3601e07b27eSBarry Smith   PetscFunctionReturn(0);
3611e07b27eSBarry Smith }
3621e07b27eSBarry Smith 
3631e07b27eSBarry Smith /* setup repartitioned dm */
3641e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_dmda_repart(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx)
3651e07b27eSBarry Smith {
3661e07b27eSBarry Smith   DM                    dm;
3671e07b27eSBarry Smith   PetscInt              dim,nx,ny,nz,ndof,nsw,sum,k;
3681e07b27eSBarry Smith   DMBoundaryType        bx,by,bz;
3691e07b27eSBarry Smith   DMDAStencilType       stencil;
3701e07b27eSBarry Smith   const PetscInt        *_range_i_re;
3711e07b27eSBarry Smith   const PetscInt        *_range_j_re;
3721e07b27eSBarry Smith   const PetscInt        *_range_k_re;
3731e07b27eSBarry Smith   DMDAInterpolationType itype;
3741e07b27eSBarry Smith   PetscInt              refine_x,refine_y,refine_z;
3751e07b27eSBarry Smith   MPI_Comm              comm,subcomm;
3761e07b27eSBarry Smith   const char            *prefix;
3771e07b27eSBarry Smith 
3781e07b27eSBarry Smith   PetscFunctionBegin;
3791e07b27eSBarry Smith   comm = PetscSubcommParent(sred->psubcomm);
3801e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
381*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
3821e07b27eSBarry Smith 
383*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,&dim,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,&nsw,&bx,&by,&bz,&stencil));
384*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInterpolationType(dm,&itype));
385*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetRefinementFactor(dm,&refine_x,&refine_y,&refine_z));
3861e07b27eSBarry Smith 
3871e07b27eSBarry Smith   ctx->dmrepart = NULL;
3881e07b27eSBarry Smith   _range_i_re = _range_j_re = _range_k_re = NULL;
3891e07b27eSBarry Smith   /* Create DMDA on the child communicator */
39057f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
3911e07b27eSBarry Smith     switch (dim) {
3921e07b27eSBarry Smith     case 1:
393*9566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (1D)\n"));
394*9566063dSJacob Faibussowitsch       /* PetscCall(DMDACreate1d(subcomm,bx,nx,ndof,nsw,NULL,&ctx->dmrepart)); */
3951e07b27eSBarry Smith       ny = nz = 1;
3961e07b27eSBarry Smith       by = bz = DM_BOUNDARY_NONE;
3971e07b27eSBarry Smith       break;
3981e07b27eSBarry Smith     case 2:
399*9566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (2D)\n"));
400*9566063dSJacob Faibussowitsch       /* PetscCall(DMDACreate2d(subcomm,bx,by,stencil,nx,ny, PETSC_DECIDE,PETSC_DECIDE,
401*9566063dSJacob Faibussowitsch          ndof,nsw, NULL,NULL,&ctx->dmrepart)); */
4021e07b27eSBarry Smith       nz = 1;
4031e07b27eSBarry Smith       bz = DM_BOUNDARY_NONE;
4041e07b27eSBarry Smith       break;
4051e07b27eSBarry Smith     case 3:
406*9566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (3D)\n"));
407*9566063dSJacob Faibussowitsch       /* PetscCall(DMDACreate3d(subcomm,bx,by,bz,stencil,nx,ny,nz,
408*9566063dSJacob Faibussowitsch          PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE, ndof,nsw, NULL,NULL,NULL,&ctx->dmrepart)); */
4091e07b27eSBarry Smith       break;
4101e07b27eSBarry Smith     }
4111e07b27eSBarry Smith     /*
4121e07b27eSBarry Smith      The API DMDACreate1d(), DMDACreate2d(), DMDACreate3d() does not allow us to set/append
4131e07b27eSBarry Smith      a unique option prefix for the DM, thus I prefer to expose the contents of these API's here.
4141e07b27eSBarry Smith      This allows users to control the partitioning of the subDM.
4151e07b27eSBarry Smith     */
416*9566063dSJacob Faibussowitsch     PetscCall(DMDACreate(subcomm,&ctx->dmrepart));
4171e07b27eSBarry Smith     /* Set unique option prefix name */
418*9566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(sred->ksp,&prefix));
419*9566063dSJacob Faibussowitsch     PetscCall(DMSetOptionsPrefix(ctx->dmrepart,prefix));
420*9566063dSJacob Faibussowitsch     PetscCall(DMAppendOptionsPrefix(ctx->dmrepart,"repart_"));
4211e07b27eSBarry Smith     /* standard setup from DMDACreate{1,2,3}d() */
422*9566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(ctx->dmrepart,dim));
423*9566063dSJacob Faibussowitsch     PetscCall(DMDASetSizes(ctx->dmrepart,nx,ny,nz));
424*9566063dSJacob Faibussowitsch     PetscCall(DMDASetNumProcs(ctx->dmrepart,PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE));
425*9566063dSJacob Faibussowitsch     PetscCall(DMDASetBoundaryType(ctx->dmrepart,bx,by,bz));
426*9566063dSJacob Faibussowitsch     PetscCall(DMDASetDof(ctx->dmrepart,ndof));
427*9566063dSJacob Faibussowitsch     PetscCall(DMDASetStencilType(ctx->dmrepart,stencil));
428*9566063dSJacob Faibussowitsch     PetscCall(DMDASetStencilWidth(ctx->dmrepart,nsw));
429*9566063dSJacob Faibussowitsch     PetscCall(DMDASetOwnershipRanges(ctx->dmrepart,NULL,NULL,NULL));
430*9566063dSJacob Faibussowitsch     PetscCall(DMSetFromOptions(ctx->dmrepart));
431*9566063dSJacob Faibussowitsch     PetscCall(DMSetUp(ctx->dmrepart));
4321e07b27eSBarry Smith     /* Set refinement factors and interpolation type from the partent */
433*9566063dSJacob Faibussowitsch     PetscCall(DMDASetRefinementFactor(ctx->dmrepart,refine_x,refine_y,refine_z));
434*9566063dSJacob Faibussowitsch     PetscCall(DMDASetInterpolationType(ctx->dmrepart,itype));
4351e07b27eSBarry Smith 
436*9566063dSJacob Faibussowitsch     PetscCall(DMDAGetInfo(ctx->dmrepart,NULL,NULL,NULL,NULL,&ctx->Mp_re,&ctx->Np_re,&ctx->Pp_re,NULL,NULL,NULL,NULL,NULL,NULL));
437*9566063dSJacob Faibussowitsch     PetscCall(DMDAGetOwnershipRanges(ctx->dmrepart,&_range_i_re,&_range_j_re,&_range_k_re));
4385e897e82SDave May 
4395e897e82SDave May     ctx->dmrepart->ops->creatematrix = dm->ops->creatematrix;
4405e897e82SDave May     ctx->dmrepart->ops->createdomaindecomposition = dm->ops->createdomaindecomposition;
4411e07b27eSBarry Smith   }
4421e07b27eSBarry Smith 
4431e07b27eSBarry Smith   /* generate ranges for repartitioned dm */
4441e07b27eSBarry Smith   /* note - assume rank 0 always participates */
445071fcb05SBarry Smith   /* TODO: use a single MPI call */
446*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&ctx->Mp_re,1,MPIU_INT,0,comm));
447*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&ctx->Np_re,1,MPIU_INT,0,comm));
448*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&ctx->Pp_re,1,MPIU_INT,0,comm));
4491e07b27eSBarry Smith 
450*9566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(ctx->Mp_re,&ctx->range_i_re,ctx->Np_re,&ctx->range_j_re,ctx->Pp_re,&ctx->range_k_re));
4511e07b27eSBarry Smith 
452*9566063dSJacob Faibussowitsch   if (_range_i_re) PetscCall(PetscArraycpy(ctx->range_i_re,_range_i_re,ctx->Mp_re));
453*9566063dSJacob Faibussowitsch   if (_range_j_re) PetscCall(PetscArraycpy(ctx->range_j_re,_range_j_re,ctx->Np_re));
454*9566063dSJacob Faibussowitsch   if (_range_k_re) PetscCall(PetscArraycpy(ctx->range_k_re,_range_k_re,ctx->Pp_re));
4551e07b27eSBarry Smith 
456071fcb05SBarry Smith   /* TODO: use a single MPI call */
457*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(ctx->range_i_re,ctx->Mp_re,MPIU_INT,0,comm));
458*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(ctx->range_j_re,ctx->Np_re,MPIU_INT,0,comm));
459*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(ctx->range_k_re,ctx->Pp_re,MPIU_INT,0,comm));
4601e07b27eSBarry Smith 
461*9566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->Mp_re,&ctx->start_i_re,ctx->Np_re,&ctx->start_j_re,ctx->Pp_re,&ctx->start_k_re));
4621e07b27eSBarry Smith 
4631e07b27eSBarry Smith   sum = 0;
4641e07b27eSBarry Smith   for (k=0; k<ctx->Mp_re; k++) {
4651e07b27eSBarry Smith     ctx->start_i_re[k] = sum;
4661e07b27eSBarry Smith     sum += ctx->range_i_re[k];
4671e07b27eSBarry Smith   }
4681e07b27eSBarry Smith 
4691e07b27eSBarry Smith   sum = 0;
4701e07b27eSBarry Smith   for (k=0; k<ctx->Np_re; k++) {
4711e07b27eSBarry Smith     ctx->start_j_re[k] = sum;
4721e07b27eSBarry Smith     sum += ctx->range_j_re[k];
4731e07b27eSBarry Smith   }
4741e07b27eSBarry Smith 
4751e07b27eSBarry Smith   sum = 0;
4761e07b27eSBarry Smith   for (k=0; k<ctx->Pp_re; k++) {
4771e07b27eSBarry Smith     ctx->start_k_re[k] = sum;
4781e07b27eSBarry Smith     sum += ctx->range_k_re[k];
4791e07b27eSBarry Smith   }
4801e07b27eSBarry Smith 
481ba1c3560SDave May   /* attach repartitioned dm to child ksp */
482ba1c3560SDave May   {
483ba1c3560SDave May     PetscErrorCode (*dmksp_func)(KSP,Mat,Mat,void*);
484ba1c3560SDave May     void           *dmksp_ctx;
485ba1c3560SDave May 
486*9566063dSJacob Faibussowitsch     PetscCall(DMKSPGetComputeOperators(dm,&dmksp_func,&dmksp_ctx));
487ba1c3560SDave May 
4881e07b27eSBarry Smith     /* attach dm to ksp on sub communicator */
48957f12427SDave May     if (PCTelescope_isActiveRank(sred)) {
490*9566063dSJacob Faibussowitsch       PetscCall(KSPSetDM(sred->ksp,ctx->dmrepart));
491ba1c3560SDave May 
492c5db1f53SDave May       if (!dmksp_func || sred->ignore_kspcomputeoperators) {
493*9566063dSJacob Faibussowitsch         PetscCall(KSPSetDMActive(sred->ksp,PETSC_FALSE));
494ba1c3560SDave May       } else {
495ba1c3560SDave May         /* sub ksp inherits dmksp_func and context provided by user */
496*9566063dSJacob Faibussowitsch         PetscCall(KSPSetComputeOperators(sred->ksp,dmksp_func,dmksp_ctx));
497*9566063dSJacob Faibussowitsch         PetscCall(KSPSetDMActive(sred->ksp,PETSC_TRUE));
498ba1c3560SDave May       }
499ba1c3560SDave May     }
5001e07b27eSBarry Smith   }
5011e07b27eSBarry Smith   PetscFunctionReturn(0);
5021e07b27eSBarry Smith }
5031e07b27eSBarry Smith 
5041e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_dmda_permutation_3d(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx)
5051e07b27eSBarry Smith {
5061e07b27eSBarry Smith   PetscErrorCode ierr;
5071e07b27eSBarry Smith   DM             dm;
5081e07b27eSBarry Smith   MPI_Comm       comm;
5091e07b27eSBarry Smith   Mat            Pscalar,P;
5101e07b27eSBarry Smith   PetscInt       ndof;
5111e07b27eSBarry Smith   PetscInt       i,j,k,location,startI[3],endI[3],lenI[3],nx,ny,nz;
5121e07b27eSBarry Smith   PetscInt       sr,er,Mr;
5131e07b27eSBarry Smith   Vec            V;
5141e07b27eSBarry Smith 
5151e07b27eSBarry Smith   PetscFunctionBegin;
516*9566063dSJacob Faibussowitsch   PetscCall(PetscInfo(pc,"PCTelescope: setting up the permutation matrix (DMDA-3D)\n"));
517*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
5181e07b27eSBarry Smith 
519*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
520*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,NULL,NULL,NULL,NULL,NULL));
5211e07b27eSBarry Smith 
522*9566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dm,&V));
523*9566063dSJacob Faibussowitsch   PetscCall(VecGetSize(V,&Mr));
524*9566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(V,&sr,&er));
525*9566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dm,&V));
5261e07b27eSBarry Smith   sr = sr / ndof;
5271e07b27eSBarry Smith   er = er / ndof;
5281e07b27eSBarry Smith   Mr = Mr / ndof;
5291e07b27eSBarry Smith 
530*9566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm,&Pscalar));
531*9566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Pscalar,(er-sr),(er-sr),Mr,Mr));
532*9566063dSJacob Faibussowitsch   PetscCall(MatSetType(Pscalar,MATAIJ));
533*9566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(Pscalar,1,NULL));
534*9566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(Pscalar,1,NULL,1,NULL));
5351e07b27eSBarry Smith 
536*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dm,NULL,NULL,NULL,&lenI[0],&lenI[1],&lenI[2]));
537*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dm,&startI[0],&startI[1],&startI[2],&endI[0],&endI[1],&endI[2]));
5381e07b27eSBarry Smith   endI[0] += startI[0];
5391e07b27eSBarry Smith   endI[1] += startI[1];
5401e07b27eSBarry Smith   endI[2] += startI[2];
5411e07b27eSBarry Smith 
5421e07b27eSBarry Smith   for (k=startI[2]; k<endI[2]; k++) {
5431e07b27eSBarry Smith     for (j=startI[1]; j<endI[1]; j++) {
5441e07b27eSBarry Smith       for (i=startI[0]; i<endI[0]; i++) {
5451e07b27eSBarry Smith         PetscMPIInt rank_ijk_re,rank_reI[3];
5461e07b27eSBarry Smith         PetscInt    s0_re;
547c6a0d831SBarry Smith         PetscInt    ii,jj,kk,local_ijk_re,mapped_ijk;
5481e07b27eSBarry Smith         PetscInt    lenI_re[3];
5491e07b27eSBarry Smith 
5501e07b27eSBarry Smith         location = (i - startI[0]) + (j - startI[1])*lenI[0] + (k - startI[2])*lenI[0]*lenI[1];
5511e07b27eSBarry Smith         ierr = _DMDADetermineRankFromGlobalIJK(3,i,j,k,   ctx->Mp_re,ctx->Np_re,ctx->Pp_re,
5521e07b27eSBarry Smith                                                ctx->start_i_re,ctx->start_j_re,ctx->start_k_re,
5531e07b27eSBarry Smith                                                ctx->range_i_re,ctx->range_j_re,ctx->range_k_re,
554*9566063dSJacob Faibussowitsch                                                &rank_reI[0],&rank_reI[1],&rank_reI[2],&rank_ijk_re);PetscCall(ierr);
555*9566063dSJacob Faibussowitsch         PetscCall(_DMDADetermineGlobalS0(3,rank_ijk_re, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, &s0_re));
5561e07b27eSBarry Smith         ii = i - ctx->start_i_re[ rank_reI[0] ];
5572c71b3e2SJacob Faibussowitsch         PetscCheckFalse(ii < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error ii");
5581e07b27eSBarry Smith         jj = j - ctx->start_j_re[ rank_reI[1] ];
5592c71b3e2SJacob Faibussowitsch         PetscCheckFalse(jj < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error jj");
5601e07b27eSBarry Smith         kk = k - ctx->start_k_re[ rank_reI[2] ];
5612c71b3e2SJacob Faibussowitsch         PetscCheckFalse(kk < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error kk");
5621e07b27eSBarry Smith         lenI_re[0] = ctx->range_i_re[ rank_reI[0] ];
5631e07b27eSBarry Smith         lenI_re[1] = ctx->range_j_re[ rank_reI[1] ];
5641e07b27eSBarry Smith         lenI_re[2] = ctx->range_k_re[ rank_reI[2] ];
5651e07b27eSBarry Smith         local_ijk_re = ii + jj * lenI_re[0] + kk * lenI_re[0] * lenI_re[1];
5661e07b27eSBarry Smith         mapped_ijk = s0_re + local_ijk_re;
567*9566063dSJacob Faibussowitsch         PetscCall(MatSetValue(Pscalar,sr+location,mapped_ijk,1.0,INSERT_VALUES));
5681e07b27eSBarry Smith       }
5691e07b27eSBarry Smith     }
5701e07b27eSBarry Smith   }
571*9566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Pscalar,MAT_FINAL_ASSEMBLY));
572*9566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Pscalar,MAT_FINAL_ASSEMBLY));
573*9566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(Pscalar,ndof,&P));
574*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Pscalar));
5751e07b27eSBarry Smith   ctx->permutation = P;
5761e07b27eSBarry Smith   PetscFunctionReturn(0);
5771e07b27eSBarry Smith }
5781e07b27eSBarry Smith 
5791e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_dmda_permutation_2d(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx)
5801e07b27eSBarry Smith {
5811e07b27eSBarry Smith   PetscErrorCode ierr;
5821e07b27eSBarry Smith   DM             dm;
5831e07b27eSBarry Smith   MPI_Comm       comm;
5841e07b27eSBarry Smith   Mat            Pscalar,P;
5851e07b27eSBarry Smith   PetscInt       ndof;
5861e07b27eSBarry Smith   PetscInt       i,j,location,startI[2],endI[2],lenI[2],nx,ny,nz;
5871e07b27eSBarry Smith   PetscInt       sr,er,Mr;
5881e07b27eSBarry Smith   Vec            V;
5891e07b27eSBarry Smith 
5901e07b27eSBarry Smith   PetscFunctionBegin;
591*9566063dSJacob Faibussowitsch   PetscCall(PetscInfo(pc,"PCTelescope: setting up the permutation matrix (DMDA-2D)\n"));
592*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
593*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
594*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,NULL,NULL,NULL,NULL,NULL));
595*9566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dm,&V));
596*9566063dSJacob Faibussowitsch   PetscCall(VecGetSize(V,&Mr));
597*9566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(V,&sr,&er));
598*9566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dm,&V));
5991e07b27eSBarry Smith   sr = sr / ndof;
6001e07b27eSBarry Smith   er = er / ndof;
6011e07b27eSBarry Smith   Mr = Mr / ndof;
6021e07b27eSBarry Smith 
603*9566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm,&Pscalar));
604*9566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Pscalar,(er-sr),(er-sr),Mr,Mr));
605*9566063dSJacob Faibussowitsch   PetscCall(MatSetType(Pscalar,MATAIJ));
606*9566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(Pscalar,1,NULL));
607*9566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(Pscalar,1,NULL,1,NULL));
6081e07b27eSBarry Smith 
609*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dm,NULL,NULL,NULL,&lenI[0],&lenI[1],NULL));
610*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dm,&startI[0],&startI[1],NULL,&endI[0],&endI[1],NULL));
6111e07b27eSBarry Smith   endI[0] += startI[0];
6121e07b27eSBarry Smith   endI[1] += startI[1];
6131e07b27eSBarry Smith 
6141e07b27eSBarry Smith   for (j=startI[1]; j<endI[1]; j++) {
6151e07b27eSBarry Smith     for (i=startI[0]; i<endI[0]; i++) {
6161e07b27eSBarry Smith       PetscMPIInt rank_ijk_re,rank_reI[3];
6171e07b27eSBarry Smith       PetscInt    s0_re;
618c6a0d831SBarry Smith       PetscInt    ii,jj,local_ijk_re,mapped_ijk;
6191e07b27eSBarry Smith       PetscInt    lenI_re[3];
6201e07b27eSBarry Smith 
6211e07b27eSBarry Smith       location = (i - startI[0]) + (j - startI[1])*lenI[0];
6221e07b27eSBarry Smith       ierr = _DMDADetermineRankFromGlobalIJK(2,i,j,0,   ctx->Mp_re,ctx->Np_re,ctx->Pp_re,
6231e07b27eSBarry Smith                                              ctx->start_i_re,ctx->start_j_re,ctx->start_k_re,
6241e07b27eSBarry Smith                                              ctx->range_i_re,ctx->range_j_re,ctx->range_k_re,
625*9566063dSJacob Faibussowitsch                                              &rank_reI[0],&rank_reI[1],NULL,&rank_ijk_re);PetscCall(ierr);
6261e07b27eSBarry Smith 
627*9566063dSJacob Faibussowitsch       PetscCall(_DMDADetermineGlobalS0(2,rank_ijk_re, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, &s0_re));
6281e07b27eSBarry Smith 
6291e07b27eSBarry Smith       ii = i - ctx->start_i_re[ rank_reI[0] ];
6302c71b3e2SJacob Faibussowitsch       PetscCheckFalse(ii < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm2d] index error ii");
6311e07b27eSBarry Smith       jj = j - ctx->start_j_re[ rank_reI[1] ];
6322c71b3e2SJacob Faibussowitsch       PetscCheckFalse(jj < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm2d] index error jj");
6331e07b27eSBarry Smith 
6341e07b27eSBarry Smith       lenI_re[0] = ctx->range_i_re[ rank_reI[0] ];
6351e07b27eSBarry Smith       lenI_re[1] = ctx->range_j_re[ rank_reI[1] ];
6361e07b27eSBarry Smith       local_ijk_re = ii + jj * lenI_re[0];
6371e07b27eSBarry Smith       mapped_ijk = s0_re + local_ijk_re;
638*9566063dSJacob Faibussowitsch       PetscCall(MatSetValue(Pscalar,sr+location,mapped_ijk,1.0,INSERT_VALUES));
6391e07b27eSBarry Smith     }
6401e07b27eSBarry Smith   }
641*9566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Pscalar,MAT_FINAL_ASSEMBLY));
642*9566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Pscalar,MAT_FINAL_ASSEMBLY));
643*9566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(Pscalar,ndof,&P));
644*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Pscalar));
6451e07b27eSBarry Smith   ctx->permutation = P;
6461e07b27eSBarry Smith   PetscFunctionReturn(0);
6471e07b27eSBarry Smith }
6481e07b27eSBarry Smith 
6491e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_dmda_scatters(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx)
6501e07b27eSBarry Smith {
6511e07b27eSBarry Smith   Vec            xred,yred,xtmp,x,xp;
6521e07b27eSBarry Smith   VecScatter     scatter;
6531e07b27eSBarry Smith   IS             isin;
6541e07b27eSBarry Smith   Mat            B;
6551e07b27eSBarry Smith   PetscInt       m,bs,st,ed;
6561e07b27eSBarry Smith   MPI_Comm       comm;
6571e07b27eSBarry Smith 
6581e07b27eSBarry Smith   PetscFunctionBegin;
659*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
660*9566063dSJacob Faibussowitsch   PetscCall(PCGetOperators(pc,NULL,&B));
661*9566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(B,&x,NULL));
662*9566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(B,&bs));
663*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(x,&xp));
6643ac26c5eSBarry Smith   m = 0;
6651e07b27eSBarry Smith   xred = NULL;
6661e07b27eSBarry Smith   yred = NULL;
66757f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
668*9566063dSJacob Faibussowitsch     PetscCall(DMCreateGlobalVector(ctx->dmrepart,&xred));
669*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(xred,&yred));
670*9566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xred,&st,&ed));
671*9566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(comm,ed-st,st,1,&isin));
672*9566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xred,&m));
6731e07b27eSBarry Smith   } else {
674*9566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(x,&st,&ed));
675*9566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(comm,0,st,1,&isin));
6761e07b27eSBarry Smith   }
677*9566063dSJacob Faibussowitsch   PetscCall(ISSetBlockSize(isin,bs));
678*9566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm,&xtmp));
679*9566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(xtmp,m,PETSC_DECIDE));
680*9566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(xtmp,bs));
681*9566063dSJacob Faibussowitsch   PetscCall(VecSetType(xtmp,((PetscObject)x)->type_name));
682*9566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x,isin,xtmp,NULL,&scatter));
6831e07b27eSBarry Smith   sred->xred    = xred;
6841e07b27eSBarry Smith   sred->yred    = yred;
6851e07b27eSBarry Smith   sred->isin    = isin;
6861e07b27eSBarry Smith   sred->scatter = scatter;
6871e07b27eSBarry Smith   sred->xtmp    = xtmp;
6881e07b27eSBarry Smith 
6891e07b27eSBarry Smith   ctx->xp       = xp;
690*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
6911e07b27eSBarry Smith   PetscFunctionReturn(0);
6921e07b27eSBarry Smith }
6931e07b27eSBarry Smith 
6941e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_dmda(PC pc,PC_Telescope sred)
6951e07b27eSBarry Smith {
6961e07b27eSBarry Smith   PC_Telescope_DMDACtx *ctx;
6971e07b27eSBarry Smith   PetscInt             dim;
6981e07b27eSBarry Smith   DM                   dm;
6991e07b27eSBarry Smith   MPI_Comm             comm;
7001e07b27eSBarry Smith 
7011e07b27eSBarry Smith   PetscFunctionBegin;
702*9566063dSJacob Faibussowitsch   PetscCall(PetscInfo(pc,"PCTelescope: setup (DMDA)\n"));
703*9566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ctx));
7041e07b27eSBarry Smith   sred->dm_ctx = (void*)ctx;
7051e07b27eSBarry Smith 
706*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
707*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
708*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
7091e07b27eSBarry Smith 
7101e07b27eSBarry Smith   PCTelescopeSetUp_dmda_repart(pc,sred,ctx);
7111e07b27eSBarry Smith   PCTelescopeSetUp_dmda_repart_coors(pc,sred,ctx);
7121e07b27eSBarry Smith   switch (dim) {
713b458e8f1SJose E. Roman   case 1:
714b458e8f1SJose E. Roman     SETERRQ(comm,PETSC_ERR_SUP,"Telescope: DMDA (1D) repartitioning not provided");
715*9566063dSJacob Faibussowitsch   case 2: PetscCall(PCTelescopeSetUp_dmda_permutation_2d(pc,sred,ctx));
7161e07b27eSBarry Smith     break;
717*9566063dSJacob Faibussowitsch   case 3: PetscCall(PCTelescopeSetUp_dmda_permutation_3d(pc,sred,ctx));
7181e07b27eSBarry Smith     break;
7191e07b27eSBarry Smith   }
720*9566063dSJacob Faibussowitsch   PetscCall(PCTelescopeSetUp_dmda_scatters(pc,sred,ctx));
7211e07b27eSBarry Smith   PetscFunctionReturn(0);
7221e07b27eSBarry Smith }
7231e07b27eSBarry Smith 
724ba1c3560SDave May PetscErrorCode PCTelescopeMatCreate_dmda_dmactivefalse(PC pc,PC_Telescope sred,MatReuse reuse,Mat *A)
7251e07b27eSBarry Smith {
7261e07b27eSBarry Smith   PC_Telescope_DMDACtx *ctx;
7271e07b27eSBarry Smith   MPI_Comm             comm,subcomm;
7281e07b27eSBarry Smith   Mat                  Bperm,Bred,B,P;
7291e07b27eSBarry Smith   PetscInt             nr,nc;
7301e07b27eSBarry Smith   IS                   isrow,iscol;
7311e07b27eSBarry Smith   Mat                  Blocal,*_Blocal;
7321e07b27eSBarry Smith 
7331e07b27eSBarry Smith   PetscFunctionBegin;
734*9566063dSJacob Faibussowitsch   PetscCall(PetscInfo(pc,"PCTelescope: updating the redundant preconditioned operator (DMDA)\n"));
735*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
7361e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
7371e07b27eSBarry Smith   ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx;
7381e07b27eSBarry Smith 
739*9566063dSJacob Faibussowitsch   PetscCall(PCGetOperators(pc,NULL,&B));
740*9566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B,&nr,&nc));
7411e07b27eSBarry Smith 
7421e07b27eSBarry Smith   P = ctx->permutation;
743*9566063dSJacob Faibussowitsch   PetscCall(MatPtAP(B,P,MAT_INITIAL_MATRIX,1.1,&Bperm));
7441e07b27eSBarry Smith 
7451e07b27eSBarry Smith   /* Get submatrices */
7461e07b27eSBarry Smith   isrow = sred->isin;
747*9566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(comm,nc,0,1,&iscol));
7481e07b27eSBarry Smith 
749*9566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Bperm,1,&isrow,&iscol,MAT_INITIAL_MATRIX,&_Blocal));
7501e07b27eSBarry Smith   Blocal = *_Blocal;
7511e07b27eSBarry Smith   Bred = NULL;
75257f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
7531e07b27eSBarry Smith     PetscInt mm;
7541e07b27eSBarry Smith 
7551e07b27eSBarry Smith     if (reuse != MAT_INITIAL_MATRIX) {Bred = *A;}
756*9566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Blocal,&mm,NULL));
757*9566063dSJacob Faibussowitsch     /* PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,PETSC_DECIDE,reuse,&Bred)); */
758*9566063dSJacob Faibussowitsch     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,mm,reuse,&Bred));
7591e07b27eSBarry Smith   }
7601e07b27eSBarry Smith   *A = Bred;
7611e07b27eSBarry Smith 
762*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscol));
763*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Bperm));
764*9566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1,&_Blocal));
7651e07b27eSBarry Smith   PetscFunctionReturn(0);
7661e07b27eSBarry Smith }
7671e07b27eSBarry Smith 
768ba1c3560SDave May PetscErrorCode PCTelescopeMatCreate_dmda(PC pc,PC_Telescope sred,MatReuse reuse,Mat *A)
769ba1c3560SDave May {
770ba1c3560SDave May   DM             dm;
771ba1c3560SDave May   PetscErrorCode (*dmksp_func)(KSP,Mat,Mat,void*);
772ba1c3560SDave May   void           *dmksp_ctx;
773ba1c3560SDave May 
774ba1c3560SDave May   PetscFunctionBegin;
775*9566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc,&dm));
776*9566063dSJacob Faibussowitsch   PetscCall(DMKSPGetComputeOperators(dm,&dmksp_func,&dmksp_ctx));
777dc9ee9fdSDave May   /* We assume that dmksp_func = NULL, is equivalent to dmActive = PETSC_FALSE */
7787c5279cbSDave May   if (dmksp_func && !sred->ignore_kspcomputeoperators) {
779ba1c3560SDave May     DM  dmrepart;
78028323a89SDave May     Mat Ak;
781ba1c3560SDave May 
782ba1c3560SDave May     *A = NULL;
78357f12427SDave May     if (PCTelescope_isActiveRank(sred)) {
784*9566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(sred->ksp,&dmrepart));
785ba1c3560SDave May       if (reuse == MAT_INITIAL_MATRIX) {
786*9566063dSJacob Faibussowitsch         PetscCall(DMCreateMatrix(dmrepart,&Ak));
787ba1c3560SDave May         *A = Ak;
788ba1c3560SDave May       } else if (reuse == MAT_REUSE_MATRIX) {
789ba1c3560SDave May         Ak = *A;
790ba1c3560SDave May       }
7915c5dbb1cSDave May       /*
7925c5dbb1cSDave May        There is no need to explicitly assemble the operator now,
7935c5dbb1cSDave May        the sub-KSP will call the method provided to KSPSetComputeOperators() during KSPSetUp()
7945c5dbb1cSDave May       */
795ba1c3560SDave May     }
796ba1c3560SDave May   } else {
797*9566063dSJacob Faibussowitsch     PetscCall(PCTelescopeMatCreate_dmda_dmactivefalse(pc,sred,reuse,A));
798ba1c3560SDave May   }
799ba1c3560SDave May   PetscFunctionReturn(0);
800ba1c3560SDave May }
801ba1c3560SDave May 
802392968a1SPatrick Sanan PetscErrorCode PCTelescopeSubNullSpaceCreate_dmda_Telescope(PC pc,PC_Telescope sred,MatNullSpace nullspace,MatNullSpace *sub_nullspace)
8031e07b27eSBarry Smith {
8041e07b27eSBarry Smith   PetscBool            has_const;
805a947c41eSDave May   PetscInt             i,k,n = 0;
8061e07b27eSBarry Smith   const Vec            *vecs;
807c41e779fSDave May   Vec                  *sub_vecs = NULL;
8081e07b27eSBarry Smith   MPI_Comm             subcomm;
8091e07b27eSBarry Smith   PC_Telescope_DMDACtx *ctx;
8101e07b27eSBarry Smith 
8111e07b27eSBarry Smith   PetscFunctionBegin;
8121e07b27eSBarry Smith   ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx;
8131e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
814*9566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(nullspace,&has_const,&n,&vecs));
8151e07b27eSBarry Smith 
81657f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
8171e07b27eSBarry Smith     /* create new vectors */
818e3acf2f7SBarry Smith     if (n) {
819*9566063dSJacob Faibussowitsch       PetscCall(VecDuplicateVecs(sred->xred,n,&sub_vecs));
8201e07b27eSBarry Smith     }
8211e07b27eSBarry Smith   }
8221e07b27eSBarry Smith 
8231e07b27eSBarry Smith   /* copy entries */
8241e07b27eSBarry Smith   for (k=0; k<n; k++) {
8251e07b27eSBarry Smith     const PetscScalar *x_array;
8261e07b27eSBarry Smith     PetscScalar       *LA_sub_vec;
82713c30530SDave May     PetscInt          st,ed;
8281e07b27eSBarry Smith 
8291e07b27eSBarry Smith     /* permute vector into ordering associated with re-partitioned dmda */
830*9566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(ctx->permutation,vecs[k],ctx->xp));
8311e07b27eSBarry Smith 
8321e07b27eSBarry Smith     /* pull in vector x->xtmp */
833*9566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sred->scatter,ctx->xp,sred->xtmp,INSERT_VALUES,SCATTER_FORWARD));
834*9566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sred->scatter,ctx->xp,sred->xtmp,INSERT_VALUES,SCATTER_FORWARD));
8351e07b27eSBarry Smith 
836392968a1SPatrick Sanan     /* copy vector entries into xred */
837*9566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(sred->xtmp,&x_array));
838ea2b237eSDave May     if (sub_vecs) {
839ea2b237eSDave May       if (sub_vecs[k]) {
840*9566063dSJacob Faibussowitsch         PetscCall(VecGetOwnershipRange(sub_vecs[k],&st,&ed));
841*9566063dSJacob Faibussowitsch         PetscCall(VecGetArray(sub_vecs[k],&LA_sub_vec));
8421e07b27eSBarry Smith         for (i=0; i<ed-st; i++) {
8431e07b27eSBarry Smith           LA_sub_vec[i] = x_array[i];
8441e07b27eSBarry Smith         }
845*9566063dSJacob Faibussowitsch         PetscCall(VecRestoreArray(sub_vecs[k],&LA_sub_vec));
8461e07b27eSBarry Smith       }
847ea2b237eSDave May     }
848*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(sred->xtmp,&x_array));
8491e07b27eSBarry Smith   }
8501e07b27eSBarry Smith 
85157f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
852d8b9d5b7SPatrick Sanan     /* create new (near) nullspace for redundant object */
853*9566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceCreate(subcomm,has_const,n,sub_vecs,sub_nullspace));
854*9566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(n,&sub_vecs));
85528b400f6SJacob Faibussowitsch     PetscCheck(!nullspace->remove,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Propagation of custom remove callbacks not supported when propagating (near) nullspaces with PCTelescope");
85628b400f6SJacob Faibussowitsch     PetscCheck(!nullspace->rmctx,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Propagation of custom remove callback context not supported when propagating (near) nullspaces with PCTelescope");
857d8b9d5b7SPatrick Sanan   }
858392968a1SPatrick Sanan   PetscFunctionReturn(0);
859392968a1SPatrick Sanan }
860392968a1SPatrick Sanan 
861392968a1SPatrick Sanan PetscErrorCode PCTelescopeMatNullSpaceCreate_dmda(PC pc,PC_Telescope sred,Mat sub_mat)
862392968a1SPatrick Sanan {
863392968a1SPatrick Sanan   Mat            B;
864392968a1SPatrick Sanan 
865392968a1SPatrick Sanan   PetscFunctionBegin;
866*9566063dSJacob Faibussowitsch   PetscCall(PCGetOperators(pc,NULL,&B));
867392968a1SPatrick Sanan   {
868392968a1SPatrick Sanan     MatNullSpace nullspace,sub_nullspace;
869*9566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(B,&nullspace));
870392968a1SPatrick Sanan     if (nullspace) {
871*9566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc,"PCTelescope: generating nullspace (DMDA)\n"));
872*9566063dSJacob Faibussowitsch       PetscCall(PCTelescopeSubNullSpaceCreate_dmda_Telescope(pc,sred,nullspace,&sub_nullspace));
87357f12427SDave May       if (PCTelescope_isActiveRank(sred)) {
874*9566063dSJacob Faibussowitsch         PetscCall(MatSetNullSpace(sub_mat,sub_nullspace));
875*9566063dSJacob Faibussowitsch         PetscCall(MatNullSpaceDestroy(&sub_nullspace));
8761e07b27eSBarry Smith       }
877392968a1SPatrick Sanan     }
878392968a1SPatrick Sanan   }
879392968a1SPatrick Sanan   {
880392968a1SPatrick Sanan     MatNullSpace nearnullspace,sub_nearnullspace;
881*9566063dSJacob Faibussowitsch     PetscCall(MatGetNearNullSpace(B,&nearnullspace));
882392968a1SPatrick Sanan     if (nearnullspace) {
883*9566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc,"PCTelescope: generating near nullspace (DMDA)\n"));
884*9566063dSJacob Faibussowitsch       PetscCall(PCTelescopeSubNullSpaceCreate_dmda_Telescope(pc,sred,nearnullspace,&sub_nearnullspace));
88557f12427SDave May       if (PCTelescope_isActiveRank(sred)) {
886*9566063dSJacob Faibussowitsch         PetscCall(MatSetNearNullSpace(sub_mat,sub_nearnullspace));
887*9566063dSJacob Faibussowitsch         PetscCall(MatNullSpaceDestroy(&sub_nearnullspace));
888392968a1SPatrick Sanan       }
889392968a1SPatrick Sanan     }
890392968a1SPatrick Sanan   }
8911e07b27eSBarry Smith   PetscFunctionReturn(0);
8921e07b27eSBarry Smith }
8931e07b27eSBarry Smith 
8941e07b27eSBarry Smith PetscErrorCode PCApply_Telescope_dmda(PC pc,Vec x,Vec y)
8951e07b27eSBarry Smith {
8961e07b27eSBarry Smith   PC_Telescope         sred = (PC_Telescope)pc->data;
8971e07b27eSBarry Smith   Mat                  perm;
8981e07b27eSBarry Smith   Vec                  xtmp,xp,xred,yred;
89913c30530SDave May   PetscInt             i,st,ed;
9001e07b27eSBarry Smith   VecScatter           scatter;
9011e07b27eSBarry Smith   PetscScalar          *array;
9021e07b27eSBarry Smith   const PetscScalar    *x_array;
9031e07b27eSBarry Smith   PC_Telescope_DMDACtx *ctx;
9041e07b27eSBarry Smith 
9051e07b27eSBarry Smith   ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx;
9061e07b27eSBarry Smith   xtmp    = sred->xtmp;
9071e07b27eSBarry Smith   scatter = sred->scatter;
9081e07b27eSBarry Smith   xred    = sred->xred;
9091e07b27eSBarry Smith   yred    = sred->yred;
9101e07b27eSBarry Smith   perm    = ctx->permutation;
9111e07b27eSBarry Smith   xp      = ctx->xp;
9121e07b27eSBarry Smith 
9131e07b27eSBarry Smith   PetscFunctionBegin;
914*9566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(citation,&cited));
91514c9fce5SDave May 
9161e07b27eSBarry Smith   /* permute vector into ordering associated with re-partitioned dmda */
917*9566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(perm,x,xp));
9181e07b27eSBarry Smith 
9191e07b27eSBarry Smith   /* pull in vector x->xtmp */
920*9566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD));
921*9566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD));
9221e07b27eSBarry Smith 
923a5b23f4aSJose E. Roman   /* copy vector entries into xred */
924*9566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(xtmp,&x_array));
9251e07b27eSBarry Smith   if (xred) {
9261e07b27eSBarry Smith     PetscScalar *LA_xred;
927*9566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xred,&st,&ed));
9281e07b27eSBarry Smith 
929*9566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xred,&LA_xred));
9301e07b27eSBarry Smith     for (i=0; i<ed-st; i++) {
9311e07b27eSBarry Smith       LA_xred[i] = x_array[i];
9321e07b27eSBarry Smith     }
933*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xred,&LA_xred));
9341e07b27eSBarry Smith   }
935*9566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(xtmp,&x_array));
9361e07b27eSBarry Smith 
9371e07b27eSBarry Smith   /* solve */
93857f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
939*9566063dSJacob Faibussowitsch     PetscCall(KSPSolve(sred->ksp,xred,yred));
940*9566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(sred->ksp,pc,yred));
9411e07b27eSBarry Smith   }
9421e07b27eSBarry Smith 
9431e07b27eSBarry Smith   /* return vector */
944*9566063dSJacob Faibussowitsch   PetscCall(VecGetArray(xtmp,&array));
9451e07b27eSBarry Smith   if (yred) {
9461e07b27eSBarry Smith     const PetscScalar *LA_yred;
947*9566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(yred,&st,&ed));
948*9566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(yred,&LA_yred));
9491e07b27eSBarry Smith     for (i=0; i<ed-st; i++) {
9501e07b27eSBarry Smith       array[i] = LA_yred[i];
9511e07b27eSBarry Smith     }
952*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(yred,&LA_yred));
9531e07b27eSBarry Smith   }
954*9566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(xtmp,&array));
955*9566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(scatter,xtmp,xp,INSERT_VALUES,SCATTER_REVERSE));
956*9566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(scatter,xtmp,xp,INSERT_VALUES,SCATTER_REVERSE));
957*9566063dSJacob Faibussowitsch   PetscCall(MatMult(perm,xp,y));
9581e07b27eSBarry Smith   PetscFunctionReturn(0);
9591e07b27eSBarry Smith }
9601e07b27eSBarry Smith 
961f650675bSDave May PetscErrorCode PCApplyRichardson_Telescope_dmda(PC pc,Vec x,Vec y,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason)
962f650675bSDave May {
963f650675bSDave May   PC_Telescope         sred = (PC_Telescope)pc->data;
964f650675bSDave May   Mat                  perm;
965a1d91a28SDave May   Vec                  xtmp,xp,yred;
966f650675bSDave May   PetscInt             i,st,ed;
967f650675bSDave May   VecScatter           scatter;
968f650675bSDave May   const PetscScalar    *x_array;
969c41e779fSDave May   PetscBool            default_init_guess_value = PETSC_FALSE;
970f650675bSDave May   PC_Telescope_DMDACtx *ctx;
971f650675bSDave May 
97257f12427SDave May   PetscFunctionBegin;
973f650675bSDave May   ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx;
974f650675bSDave May   xtmp    = sred->xtmp;
975f650675bSDave May   scatter = sred->scatter;
976f650675bSDave May   yred    = sred->yred;
977f650675bSDave May   perm    = ctx->permutation;
978f650675bSDave May   xp      = ctx->xp;
979f650675bSDave May 
9802c71b3e2SJacob Faibussowitsch   PetscCheckFalse(its > 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"PCApplyRichardson_Telescope_dmda only supports max_it = 1");
981f650675bSDave May   *reason = (PCRichardsonConvergedReason)0;
982f650675bSDave May 
983f650675bSDave May   if (!zeroguess) {
984*9566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc,"PCTelescopeDMDA: Scattering y for non-zero-initial guess\n"));
985f650675bSDave May     /* permute vector into ordering associated with re-partitioned dmda */
986*9566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(perm,y,xp));
987f650675bSDave May 
988f650675bSDave May     /* pull in vector x->xtmp */
989*9566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD));
990*9566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD));
991f650675bSDave May 
992a5b23f4aSJose E. Roman     /* copy vector entries into xred */
993*9566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(xtmp,&x_array));
994f650675bSDave May     if (yred) {
995f650675bSDave May       PetscScalar *LA_yred;
996*9566063dSJacob Faibussowitsch       PetscCall(VecGetOwnershipRange(yred,&st,&ed));
997*9566063dSJacob Faibussowitsch       PetscCall(VecGetArray(yred,&LA_yred));
998f650675bSDave May       for (i=0; i<ed-st; i++) {
999f650675bSDave May         LA_yred[i] = x_array[i];
1000f650675bSDave May       }
1001*9566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(yred,&LA_yred));
1002f650675bSDave May     }
1003*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(xtmp,&x_array));
1004f650675bSDave May   }
1005f650675bSDave May 
100657f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
1007*9566063dSJacob Faibussowitsch     PetscCall(KSPGetInitialGuessNonzero(sred->ksp,&default_init_guess_value));
1008*9566063dSJacob Faibussowitsch     if (!zeroguess) PetscCall(KSPSetInitialGuessNonzero(sred->ksp,PETSC_TRUE));
1009f650675bSDave May   }
1010f650675bSDave May 
1011*9566063dSJacob Faibussowitsch   PetscCall(PCApply_Telescope_dmda(pc,x,y));
1012f650675bSDave May 
101357f12427SDave May   if (PCTelescope_isActiveRank(sred)) {
1014*9566063dSJacob Faibussowitsch     PetscCall(KSPSetInitialGuessNonzero(sred->ksp,default_init_guess_value));
1015f650675bSDave May   }
1016f650675bSDave May 
1017f650675bSDave May   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1018f650675bSDave May   *outits = 1;
1019f650675bSDave May   PetscFunctionReturn(0);
1020f650675bSDave May }
1021f650675bSDave May 
10221e07b27eSBarry Smith PetscErrorCode PCReset_Telescope_dmda(PC pc)
10231e07b27eSBarry Smith {
10241e07b27eSBarry Smith   PC_Telescope         sred = (PC_Telescope)pc->data;
10251e07b27eSBarry Smith   PC_Telescope_DMDACtx *ctx;
10261e07b27eSBarry Smith 
10271e07b27eSBarry Smith   PetscFunctionBegin;
10281e07b27eSBarry Smith   ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx;
1029*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->xp));
1030*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->permutation));
1031*9566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dmrepart));
1032*9566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ctx->range_i_re,ctx->range_j_re,ctx->range_k_re));
1033*9566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ctx->start_i_re,ctx->start_j_re,ctx->start_k_re));
10341e07b27eSBarry Smith   PetscFunctionReturn(0);
10351e07b27eSBarry Smith }
10361e07b27eSBarry Smith 
10378ef9ca65SPatrick Sanan PetscErrorCode DMView_DA_Short_3d(DM dm,PetscViewer v)
10381e07b27eSBarry Smith {
10391e07b27eSBarry Smith   PetscInt       M,N,P,m,n,p,ndof,nsw;
10401e07b27eSBarry Smith   MPI_Comm       comm;
10411e07b27eSBarry Smith   PetscMPIInt    size;
10421e07b27eSBarry Smith   const char*    prefix;
10431e07b27eSBarry Smith 
10441e07b27eSBarry Smith   PetscFunctionBegin;
1045*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
1046*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm,&size));
1047*9566063dSJacob Faibussowitsch   PetscCall(DMGetOptionsPrefix(dm,&prefix));
1048*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&M,&N,&P,&m,&n,&p,&ndof,&nsw,NULL,NULL,NULL,NULL));
1049*9566063dSJacob Faibussowitsch   if (prefix) PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object:    (%s)    %d MPI processes\n",prefix,size));
1050*9566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object:    %d MPI processes\n",size));
1051*9566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(v,"  M %D N %D P %D m %D n %D p %D dof %D overlap %D\n",M,N,P,m,n,p,ndof,nsw));
10521e07b27eSBarry Smith   PetscFunctionReturn(0);
10531e07b27eSBarry Smith }
10541e07b27eSBarry Smith 
10558ef9ca65SPatrick Sanan PetscErrorCode DMView_DA_Short_2d(DM dm,PetscViewer v)
10561e07b27eSBarry Smith {
10571e07b27eSBarry Smith   PetscInt       M,N,m,n,ndof,nsw;
10581e07b27eSBarry Smith   MPI_Comm       comm;
10591e07b27eSBarry Smith   PetscMPIInt    size;
10601e07b27eSBarry Smith   const char*    prefix;
10611e07b27eSBarry Smith 
10621e07b27eSBarry Smith   PetscFunctionBegin;
1063*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
1064*9566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm,&size));
1065*9566063dSJacob Faibussowitsch   PetscCall(DMGetOptionsPrefix(dm,&prefix));
1066*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,NULL,&M,&N,NULL,&m,&n,NULL,&ndof,&nsw,NULL,NULL,NULL,NULL));
1067*9566063dSJacob Faibussowitsch   if (prefix) PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object:    (%s)    %d MPI processes\n",prefix,size));
1068*9566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object:    %d MPI processes\n",size));
1069*9566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(v,"  M %D N %D m %D n %D dof %D overlap %D\n",M,N,m,n,ndof,nsw));
10701e07b27eSBarry Smith   PetscFunctionReturn(0);
10711e07b27eSBarry Smith }
10721e07b27eSBarry Smith 
10738ef9ca65SPatrick Sanan PetscErrorCode DMView_DA_Short(DM dm,PetscViewer v)
10741e07b27eSBarry Smith {
10751e07b27eSBarry Smith   PetscInt       dim;
10761e07b27eSBarry Smith 
10771e07b27eSBarry Smith   PetscFunctionBegin;
1078*9566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
10791e07b27eSBarry Smith   switch (dim) {
1080*9566063dSJacob Faibussowitsch   case 2: PetscCall(DMView_DA_Short_2d(dm,v));
10811e07b27eSBarry Smith     break;
1082*9566063dSJacob Faibussowitsch   case 3: PetscCall(DMView_DA_Short_3d(dm,v));
10831e07b27eSBarry Smith     break;
10841e07b27eSBarry Smith   }
10851e07b27eSBarry Smith   PetscFunctionReturn(0);
10861e07b27eSBarry Smith }
1087