xref: /petsc/src/ksp/pc/impls/telescope/telescope.c (revision 1e07b27e81e393854908e91a98c07414449fdbdc)
1*1e07b27eSBarry Smith 
2*1e07b27eSBarry Smith /*
3*1e07b27eSBarry Smith 
4*1e07b27eSBarry Smith  Defines a telescoping preconditioner
5*1e07b27eSBarry Smith 
6*1e07b27eSBarry Smith  Assuming that the parent preconditioner (PC) is defined on a communicator c, this implementation
7*1e07b27eSBarry Smith  creates a child sub-communicator (c') containing less MPI processes than the original parent preconditioner (PC).
8*1e07b27eSBarry Smith 
9*1e07b27eSBarry Smith  During PCSetup, the B operator is scattered onto c'.
10*1e07b27eSBarry Smith  Within PCApply, the RHS vector (x) is scattered into a redundant vector, xred (defined on c').
11*1e07b27eSBarry Smith  Then KSPSolve() is executed on the c' communicator.
12*1e07b27eSBarry Smith 
13*1e07b27eSBarry Smith  The preconditioner is deemed telescopint as it only calls KSPSolve() on a single
14*1e07b27eSBarry Smith  sub-communicator in contrast with PCREDUNDANT which calls KSPSolve() on N sub-communicators.
15*1e07b27eSBarry Smith  This means there will be MPI processes within c, which will be idle during the application of this preconditioner.
16*1e07b27eSBarry Smith 
17*1e07b27eSBarry Smith  Comments:
18*1e07b27eSBarry Smith  - The communicator used within the telescoping preconditioner is defined by a PetscSubcomm using the INTERLACED
19*1e07b27eSBarry Smith  creation routine. We run the sub KSP on only the ranks within the communicator which have a color equal to zero.
20*1e07b27eSBarry Smith 
21*1e07b27eSBarry Smith  - The telescoping preconditioner is aware of nullspaces which are attached to the only B operator.
22*1e07b27eSBarry Smith  In case where B has a n nullspace attached, these nullspaces vectors are extract from B and mapped into
23*1e07b27eSBarry Smith  a new nullspace (defined on the sub-communicator) which is attached to B' (the B operator which was scattered to c')
24*1e07b27eSBarry Smith 
25*1e07b27eSBarry Smith  - The telescoping preconditioner is aware of an attached DM. In the event that the DM is of type DMDA (2D or 3D -
26*1e07b27eSBarry Smith  1D support for 1D DMDAs is not provided), a new DMDA is created on c' (e.g. it is re-partitioned), and this new DM
27*1e07b27eSBarry Smith  is attached the sub KSPSolve(). The design of telescope is such that it should be possible to extend support
28*1e07b27eSBarry Smith  for re-partitioning other DM's (e.g. DMPLEX). The user can supply a flag to ignore attached DMs.
29*1e07b27eSBarry Smith 
30*1e07b27eSBarry Smith  - By default, B' is defined by simply fusing rows from different MPI processes
31*1e07b27eSBarry Smith 
32*1e07b27eSBarry Smith  - When a DMDA is attached to the parent preconditioner, B' is defined by: (i) performing a symmetric permuting of B
33*1e07b27eSBarry Smith  into the ordering defined by the DMDA on c', (ii) extracting the local chunks via MatGetSubMatrices(), (iii) fusing the
34*1e07b27eSBarry Smith  locally (sequential) matrices defined on the ranks common to c and c' into B' using MatCreateMPIMatConcatenateSeqMat()
35*1e07b27eSBarry Smith 
36*1e07b27eSBarry Smith  Limitations/improvements
37*1e07b27eSBarry Smith  - VecPlaceArray could be used within PCApply() to improve efficiency and reduce memory usage.
38*1e07b27eSBarry Smith 
39*1e07b27eSBarry Smith  - The symmetric permutation used when a DMDA is encountered is performed via explicitly assmbleming a permutation matrix P,
40*1e07b27eSBarry Smith  and performing P^T.A.P. Possibly it might be more efficient to use MatPermute(). I opted to use P^T.A.P as it appears
41*1e07b27eSBarry Smith  VecPermute() does not supported for the use case required here. By computing P, I can permute both the operator and RHS in a
42*1e07b27eSBarry Smith  consistent manner.
43*1e07b27eSBarry Smith 
44*1e07b27eSBarry Smith  - Mapping of vectors is performed this way
45*1e07b27eSBarry Smith  Suppose the parent comm size was 4, and we set a reduction factor of 2, thus would give a comm size on c' of 2.
46*1e07b27eSBarry Smith  Using the interlaced creation routine, the ranks in c with color = 0, will be rank 0 and 2.
47*1e07b27eSBarry Smith  We perform the scatter to the sub-comm in the following way,
48*1e07b27eSBarry Smith  [1] Given a vector x defined on comm c
49*1e07b27eSBarry Smith 
50*1e07b27eSBarry Smith    rank(c) : _________ 0 ______  ________ 1 _______  ________ 2 _____________ ___________ 3 __________
51*1e07b27eSBarry Smith          x : [0, 1, 2, 3, 4, 5] [6, 7, 8, 9, 10, 11] [12, 13, 14, 15, 16, 17] [18, 19, 20, 21, 22, 23]
52*1e07b27eSBarry Smith 
53*1e07b27eSBarry Smith  scatter to xtmp defined also on comm c so that we have the following values
54*1e07b27eSBarry Smith 
55*1e07b27eSBarry Smith    rank(c) : ___________________ 0 ________________  _1_  ______________________ 2 _______________________  __3_
56*1e07b27eSBarry Smith       xtmp : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] [ 6 ] [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] [ 18 ]
57*1e07b27eSBarry Smith 
58*1e07b27eSBarry Smith  The entries on rank 1 and 3 (ranks which do not have a color = 0 in c') are filled with the first bs values living on that rank,
59*1e07b27eSBarry Smith  where bs is the block size of the vector.
60*1e07b27eSBarry Smith 
61*1e07b27eSBarry Smith  [2] Copy the value from rank 0, 2 (indices with respect to comm c) into the vector xred which is defined on communicator c'.
62*1e07b27eSBarry Smith  Ranks 0 and 2 are the only ranks in the subcomm which have a color = 0.
63*1e07b27eSBarry Smith 
64*1e07b27eSBarry Smith   rank(c') : ___________________ 0 _______________  ______________________ 1 _____________________
65*1e07b27eSBarry Smith       xred : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
66*1e07b27eSBarry Smith 
67*1e07b27eSBarry Smith */
68*1e07b27eSBarry Smith 
69*1e07b27eSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
70*1e07b27eSBarry Smith #include <petscksp.h> /*I "petscksp.h" I*/
71*1e07b27eSBarry Smith #include <petscdm.h> /*I "petscdm.h" I*/
72*1e07b27eSBarry Smith 
73*1e07b27eSBarry Smith #include "telescope.h"
74*1e07b27eSBarry Smith 
75*1e07b27eSBarry Smith /*
76*1e07b27eSBarry Smith  PCTelescopeSetUp_default()
77*1e07b27eSBarry Smith  PCTelescopeMatCreate_default()
78*1e07b27eSBarry Smith 
79*1e07b27eSBarry Smith  default
80*1e07b27eSBarry Smith 
81*1e07b27eSBarry Smith  // scatter in
82*1e07b27eSBarry Smith  x(comm) -> xtmp(comm)
83*1e07b27eSBarry Smith 
84*1e07b27eSBarry Smith  xred(subcomm) <- xtmp
85*1e07b27eSBarry Smith  yred(subcomm)
86*1e07b27eSBarry Smith 
87*1e07b27eSBarry Smith  yred(subcomm) --> xtmp
88*1e07b27eSBarry Smith 
89*1e07b27eSBarry Smith  // scatter out
90*1e07b27eSBarry Smith  xtmp(comm) -> y(comm)
91*1e07b27eSBarry Smith */
92*1e07b27eSBarry Smith 
93*1e07b27eSBarry Smith PetscBool isActiveRank(PetscSubcomm scomm)
94*1e07b27eSBarry Smith {
95*1e07b27eSBarry Smith   if (scomm->color == 0) { return PETSC_TRUE; }
96*1e07b27eSBarry Smith   else { return PETSC_FALSE; }
97*1e07b27eSBarry Smith }
98*1e07b27eSBarry Smith 
99*1e07b27eSBarry Smith #undef __FUNCT__
100*1e07b27eSBarry Smith #define __FUNCT__ "private_PCTelescopeGetSubDM"
101*1e07b27eSBarry Smith DM private_PCTelescopeGetSubDM(PC_Telescope sred)
102*1e07b27eSBarry Smith {
103*1e07b27eSBarry Smith   DM subdm;
104*1e07b27eSBarry Smith 
105*1e07b27eSBarry Smith   if (!isActiveRank(sred->psubcomm)) { subdm = NULL; }
106*1e07b27eSBarry Smith   else {
107*1e07b27eSBarry Smith     switch (sred->sr_type) {
108*1e07b27eSBarry Smith     case TELESCOPE_DEFAULT: subdm = NULL;
109*1e07b27eSBarry Smith       break;
110*1e07b27eSBarry Smith     case TELESCOPE_DMDA:    subdm = ((PC_Telescope_DMDACtx*)sred->dm_ctx)->dmrepart;
111*1e07b27eSBarry Smith       break;
112*1e07b27eSBarry Smith     case TELESCOPE_DMPLEX:  subdm = NULL;
113*1e07b27eSBarry Smith       break;
114*1e07b27eSBarry Smith     }
115*1e07b27eSBarry Smith   }
116*1e07b27eSBarry Smith   return(subdm);
117*1e07b27eSBarry Smith }
118*1e07b27eSBarry Smith 
119*1e07b27eSBarry Smith #undef __FUNCT__
120*1e07b27eSBarry Smith #define __FUNCT__ "PCTelescopeSetUp_default"
121*1e07b27eSBarry Smith PetscErrorCode PCTelescopeSetUp_default(PC pc,PC_Telescope sred)
122*1e07b27eSBarry Smith {
123*1e07b27eSBarry Smith   PetscErrorCode ierr;
124*1e07b27eSBarry Smith   PetscInt       m,M,bs,st,ed;
125*1e07b27eSBarry Smith   Vec            x,xred,yred,xtmp;
126*1e07b27eSBarry Smith   Mat            B;
127*1e07b27eSBarry Smith   MPI_Comm       comm,subcomm;
128*1e07b27eSBarry Smith   VecScatter     scatter;
129*1e07b27eSBarry Smith   IS             isin;
130*1e07b27eSBarry Smith 
131*1e07b27eSBarry Smith   PetscFunctionBegin;
132*1e07b27eSBarry Smith   ierr = PetscInfo(pc,"PCTelescope: setup (default)\n");CHKERRQ(ierr);
133*1e07b27eSBarry Smith   comm = PetscSubcommParent(sred->psubcomm);
134*1e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
135*1e07b27eSBarry Smith 
136*1e07b27eSBarry Smith   ierr = PCGetOperators(pc,NULL,&B);CHKERRQ(ierr);
137*1e07b27eSBarry Smith   ierr = MatGetSize(B,&M,NULL);CHKERRQ(ierr);
138*1e07b27eSBarry Smith   ierr = MatGetBlockSize(B,&bs);CHKERRQ(ierr);
139*1e07b27eSBarry Smith   ierr = MatCreateVecs(B,&x,NULL);CHKERRQ(ierr);
140*1e07b27eSBarry Smith 
141*1e07b27eSBarry Smith   xred = NULL;
142*1e07b27eSBarry Smith   m = bs;
143*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
144*1e07b27eSBarry Smith     ierr = VecCreate(subcomm,&xred);CHKERRQ(ierr);
145*1e07b27eSBarry Smith     ierr = VecSetSizes(xred,PETSC_DECIDE,M);CHKERRQ(ierr);
146*1e07b27eSBarry Smith     ierr = VecSetBlockSize(xred,bs);CHKERRQ(ierr);
147*1e07b27eSBarry Smith     ierr = VecSetFromOptions(xred);CHKERRQ(ierr);
148*1e07b27eSBarry Smith     ierr = VecGetLocalSize(xred,&m);
149*1e07b27eSBarry Smith   }
150*1e07b27eSBarry Smith 
151*1e07b27eSBarry Smith   yred = NULL;
152*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
153*1e07b27eSBarry Smith     ierr = VecDuplicate(xred,&yred);CHKERRQ(ierr);
154*1e07b27eSBarry Smith   }
155*1e07b27eSBarry Smith 
156*1e07b27eSBarry Smith   ierr = VecCreate(comm,&xtmp);CHKERRQ(ierr);
157*1e07b27eSBarry Smith   ierr = VecSetSizes(xtmp,m,PETSC_DECIDE);CHKERRQ(ierr);
158*1e07b27eSBarry Smith   ierr = VecSetBlockSize(xtmp,bs);CHKERRQ(ierr);
159*1e07b27eSBarry Smith   ierr = VecSetType(xtmp,((PetscObject)x)->type_name);CHKERRQ(ierr);
160*1e07b27eSBarry Smith 
161*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
162*1e07b27eSBarry Smith     ierr = VecGetOwnershipRange(xred,&st,&ed);CHKERRQ(ierr);
163*1e07b27eSBarry Smith     ierr = ISCreateStride(comm,(ed-st),st,1,&isin);CHKERRQ(ierr);
164*1e07b27eSBarry Smith   } else {
165*1e07b27eSBarry Smith     ierr = VecGetOwnershipRange(x,&st,&ed);CHKERRQ(ierr);
166*1e07b27eSBarry Smith     ierr = ISCreateStride(comm,bs,st,1,&isin);CHKERRQ(ierr);
167*1e07b27eSBarry Smith   }
168*1e07b27eSBarry Smith   ierr = ISSetBlockSize(isin,bs);CHKERRQ(ierr);
169*1e07b27eSBarry Smith 
170*1e07b27eSBarry Smith   ierr = VecScatterCreate(x,isin,xtmp,NULL,&scatter);CHKERRQ(ierr);
171*1e07b27eSBarry Smith 
172*1e07b27eSBarry Smith   sred->isin    = isin;
173*1e07b27eSBarry Smith   sred->scatter = scatter;
174*1e07b27eSBarry Smith   sred->xred    = xred;
175*1e07b27eSBarry Smith   sred->yred    = yred;
176*1e07b27eSBarry Smith   sred->xtmp    = xtmp;
177*1e07b27eSBarry Smith   ierr = VecDestroy(&x);CHKERRQ(ierr);
178*1e07b27eSBarry Smith   PetscFunctionReturn(0);
179*1e07b27eSBarry Smith }
180*1e07b27eSBarry Smith 
181*1e07b27eSBarry Smith #undef __FUNCT__
182*1e07b27eSBarry Smith #define __FUNCT__ "PCTelescopeMatCreate_default"
183*1e07b27eSBarry Smith PetscErrorCode PCTelescopeMatCreate_default(PC pc,PC_Telescope sred,MatReuse reuse,Mat *A)
184*1e07b27eSBarry Smith {
185*1e07b27eSBarry Smith   PetscErrorCode ierr;
186*1e07b27eSBarry Smith   MPI_Comm       comm,subcomm;
187*1e07b27eSBarry Smith   Mat            Bred,B;
188*1e07b27eSBarry Smith   PetscInt       nr,nc;
189*1e07b27eSBarry Smith   IS             isrow,iscol;
190*1e07b27eSBarry Smith   Mat            Blocal,*_Blocal;
191*1e07b27eSBarry Smith 
192*1e07b27eSBarry Smith   PetscFunctionBegin;
193*1e07b27eSBarry Smith   ierr = PetscInfo(pc,"PCTelescope: updating the redundant preconditioned operator (default)\n");CHKERRQ(ierr);
194*1e07b27eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
195*1e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
196*1e07b27eSBarry Smith   ierr = PCGetOperators(pc,NULL,&B);CHKERRQ(ierr);
197*1e07b27eSBarry Smith   ierr = MatGetSize(B,&nr,&nc);CHKERRQ(ierr);
198*1e07b27eSBarry Smith   isrow = sred->isin;
199*1e07b27eSBarry Smith   ierr = ISCreateStride(comm,nc,0,1,&iscol);CHKERRQ(ierr);
200*1e07b27eSBarry Smith   ierr = MatGetSubMatrices(B,1,&isrow,&iscol,MAT_INITIAL_MATRIX,&_Blocal);CHKERRQ(ierr);
201*1e07b27eSBarry Smith   Blocal = *_Blocal;
202*1e07b27eSBarry Smith   ierr = PetscFree(_Blocal);CHKERRQ(ierr);
203*1e07b27eSBarry Smith   Bred = NULL;
204*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
205*1e07b27eSBarry Smith     PetscInt mm;
206*1e07b27eSBarry Smith 
207*1e07b27eSBarry Smith     if (reuse != MAT_INITIAL_MATRIX) { Bred = *A; }
208*1e07b27eSBarry Smith 
209*1e07b27eSBarry Smith     ierr = MatGetSize(Blocal,&mm,NULL);CHKERRQ(ierr);
210*1e07b27eSBarry Smith     //ierr = MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,PETSC_DECIDE,reuse,&Bred);CHKERRQ(ierr);
211*1e07b27eSBarry Smith     ierr = MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,mm,reuse,&Bred);CHKERRQ(ierr);
212*1e07b27eSBarry Smith   }
213*1e07b27eSBarry Smith   *A = Bred;
214*1e07b27eSBarry Smith   ierr = ISDestroy(&iscol);CHKERRQ(ierr);
215*1e07b27eSBarry Smith   ierr = MatDestroy(&Blocal);CHKERRQ(ierr);
216*1e07b27eSBarry Smith   PetscFunctionReturn(0);
217*1e07b27eSBarry Smith }
218*1e07b27eSBarry Smith 
219*1e07b27eSBarry Smith #undef __FUNCT__
220*1e07b27eSBarry Smith #define __FUNCT__ "PCTelescopeMatNullSpaceCreate_default"
221*1e07b27eSBarry Smith PetscErrorCode PCTelescopeMatNullSpaceCreate_default(PC pc,PC_Telescope sred,Mat sub_mat)
222*1e07b27eSBarry Smith {
223*1e07b27eSBarry Smith   PetscErrorCode   ierr;
224*1e07b27eSBarry Smith   MatNullSpace     nullspace,sub_nullspace;
225*1e07b27eSBarry Smith   Mat              A,B;
226*1e07b27eSBarry Smith   PetscBool        has_const;
227*1e07b27eSBarry Smith   PetscInt         i,k,n;
228*1e07b27eSBarry Smith   const Vec        *vecs;
229*1e07b27eSBarry Smith   Vec              *sub_vecs;
230*1e07b27eSBarry Smith   MPI_Comm         subcomm;
231*1e07b27eSBarry Smith 
232*1e07b27eSBarry Smith   PetscFunctionBegin;
233*1e07b27eSBarry Smith   ierr = PCGetOperators(pc,&A,&B);CHKERRQ(ierr);
234*1e07b27eSBarry Smith   ierr = MatGetNullSpace(B,&nullspace);CHKERRQ(ierr);
235*1e07b27eSBarry Smith   if (!nullspace) return(0);
236*1e07b27eSBarry Smith 
237*1e07b27eSBarry Smith   ierr = PetscInfo(pc,"PCTelescope: generating nullspace (default)\n");CHKERRQ(ierr);
238*1e07b27eSBarry Smith   subcomm = PetscSubcommChild(sred->psubcomm);
239*1e07b27eSBarry Smith   ierr = MatNullSpaceGetVecs(nullspace,&has_const,&n,&vecs);CHKERRQ(ierr);
240*1e07b27eSBarry Smith 
241*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
242*1e07b27eSBarry Smith     sub_vecs = NULL;
243*1e07b27eSBarry Smith     /* create new vectors */
244*1e07b27eSBarry Smith     if (n != 0) {
245*1e07b27eSBarry Smith       PetscMalloc(sizeof(Vec)*n,&sub_vecs);
246*1e07b27eSBarry Smith       for (k=0; k<n; k++) {
247*1e07b27eSBarry Smith         ierr = VecDuplicate(sred->xred,&sub_vecs[k]);CHKERRQ(ierr);
248*1e07b27eSBarry Smith       }
249*1e07b27eSBarry Smith     }
250*1e07b27eSBarry Smith   }
251*1e07b27eSBarry Smith 
252*1e07b27eSBarry Smith   /* copy entries */
253*1e07b27eSBarry Smith   for (k=0; k<n; k++) {
254*1e07b27eSBarry Smith     const PetscScalar *x_array;
255*1e07b27eSBarry Smith     PetscScalar       *LA_sub_vec;
256*1e07b27eSBarry Smith     PetscInt          st,ed,bs;
257*1e07b27eSBarry Smith 
258*1e07b27eSBarry Smith     /* pull in vector x->xtmp */
259*1e07b27eSBarry Smith     ierr = VecScatterBegin(sred->scatter,vecs[k],sred->xtmp,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
260*1e07b27eSBarry Smith     ierr = VecScatterEnd(sred->scatter,vecs[k],sred->xtmp,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
261*1e07b27eSBarry Smith     /* copy vector entires into xred */
262*1e07b27eSBarry Smith     ierr = VecGetBlockSize(sred->xtmp,&bs);CHKERRQ(ierr);
263*1e07b27eSBarry Smith     ierr = VecGetArrayRead(sred->xtmp,&x_array);CHKERRQ(ierr);
264*1e07b27eSBarry Smith     if (sub_vecs[k]) {
265*1e07b27eSBarry Smith       ierr = VecGetOwnershipRange(sub_vecs[k],&st,&ed);CHKERRQ(ierr);
266*1e07b27eSBarry Smith       ierr = VecGetArray(sub_vecs[k],&LA_sub_vec);CHKERRQ(ierr);
267*1e07b27eSBarry Smith       for (i=0; i<ed-st; i++) {
268*1e07b27eSBarry Smith         LA_sub_vec[i] = x_array[i];
269*1e07b27eSBarry Smith       }
270*1e07b27eSBarry Smith       ierr = VecRestoreArray(sub_vecs[k],&LA_sub_vec);CHKERRQ(ierr);
271*1e07b27eSBarry Smith     }
272*1e07b27eSBarry Smith     ierr = VecRestoreArrayRead(sred->xtmp,&x_array);CHKERRQ(ierr);
273*1e07b27eSBarry Smith   }
274*1e07b27eSBarry Smith 
275*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
276*1e07b27eSBarry Smith     /* create new nullspace for redundant object */
277*1e07b27eSBarry Smith     ierr = MatNullSpaceCreate(subcomm,has_const,n,sub_vecs,&sub_nullspace);CHKERRQ(ierr);
278*1e07b27eSBarry Smith     /* attach redundant nullspace to Bred */
279*1e07b27eSBarry Smith     ierr = MatSetNullSpace(sub_mat,sub_nullspace);CHKERRQ(ierr);
280*1e07b27eSBarry Smith 
281*1e07b27eSBarry Smith     for (k=0; k<n; k++) {
282*1e07b27eSBarry Smith       ierr = VecDestroy(&sub_vecs[k]);CHKERRQ(ierr);
283*1e07b27eSBarry Smith     }
284*1e07b27eSBarry Smith     if (sub_vecs) PetscFree(sub_vecs);
285*1e07b27eSBarry Smith   }
286*1e07b27eSBarry Smith   PetscFunctionReturn(0);
287*1e07b27eSBarry Smith }
288*1e07b27eSBarry Smith 
289*1e07b27eSBarry Smith #undef __FUNCT__
290*1e07b27eSBarry Smith #define __FUNCT__ "PCView_Telescope"
291*1e07b27eSBarry Smith static PetscErrorCode PCView_Telescope(PC pc,PetscViewer viewer)
292*1e07b27eSBarry Smith {
293*1e07b27eSBarry Smith   PC_Telescope     sred = (PC_Telescope)pc->data;
294*1e07b27eSBarry Smith   PetscErrorCode   ierr;
295*1e07b27eSBarry Smith   PetscBool        iascii,isstring;
296*1e07b27eSBarry Smith   PetscViewer      subviewer;
297*1e07b27eSBarry Smith 
298*1e07b27eSBarry Smith   PetscFunctionBegin;
299*1e07b27eSBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
300*1e07b27eSBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr);
301*1e07b27eSBarry Smith   if (iascii) {
302*1e07b27eSBarry Smith     if (!sred->psubcomm) {
303*1e07b27eSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"  Telescope: preconditioner not yet setup\n");CHKERRQ(ierr);
304*1e07b27eSBarry Smith     } else {
305*1e07b27eSBarry Smith       MPI_Comm    comm,subcomm;
306*1e07b27eSBarry Smith       PetscMPIInt comm_size,subcomm_size;
307*1e07b27eSBarry Smith       DM          dm,subdm;
308*1e07b27eSBarry Smith 
309*1e07b27eSBarry Smith       ierr = PCGetDM(pc,&dm);CHKERRQ(ierr);
310*1e07b27eSBarry Smith       subdm = private_PCTelescopeGetSubDM(sred);
311*1e07b27eSBarry Smith       comm = PetscSubcommParent(sred->psubcomm);
312*1e07b27eSBarry Smith       subcomm = PetscSubcommChild(sred->psubcomm);
313*1e07b27eSBarry Smith       ierr = MPI_Comm_size(comm,&comm_size);CHKERRQ(ierr);
314*1e07b27eSBarry Smith       ierr = MPI_Comm_size(subcomm,&subcomm_size);CHKERRQ(ierr);
315*1e07b27eSBarry Smith 
316*1e07b27eSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"  Telescope: parent comm size reduction factor = %D\n",sred->redfactor);CHKERRQ(ierr);
317*1e07b27eSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"  Telescope: comm_size = %d , subcomm_size = %d\n",(int)comm_size,(int)subcomm_size);CHKERRQ(ierr);
318*1e07b27eSBarry Smith       ierr = PetscViewerGetSubViewer(viewer,subcomm,&subviewer);CHKERRQ(ierr);
319*1e07b27eSBarry Smith       if (isActiveRank(sred->psubcomm)) {
320*1e07b27eSBarry Smith         ierr = PetscViewerASCIIPushTab(subviewer);CHKERRQ(ierr);
321*1e07b27eSBarry Smith 
322*1e07b27eSBarry Smith         if (dm && sred->ignore_dm) {
323*1e07b27eSBarry Smith           ierr = PetscViewerASCIIPrintf(subviewer,"  Telescope: ignoring DM\n");CHKERRQ(ierr);
324*1e07b27eSBarry Smith         }
325*1e07b27eSBarry Smith         switch (sred->sr_type) {
326*1e07b27eSBarry Smith         case TELESCOPE_DEFAULT:
327*1e07b27eSBarry Smith           ierr = PetscViewerASCIIPrintf(subviewer,"  Telescope: using default setup\n");CHKERRQ(ierr);
328*1e07b27eSBarry Smith           break;
329*1e07b27eSBarry Smith         case TELESCOPE_DMDA:
330*1e07b27eSBarry Smith           ierr = PetscViewerASCIIPrintf(subviewer,"  Telescope: DMDA detected\n");CHKERRQ(ierr);
331*1e07b27eSBarry Smith           ierr = DMView_DMDAShort(subdm,subviewer);CHKERRQ(ierr);
332*1e07b27eSBarry Smith           break;
333*1e07b27eSBarry Smith         case TELESCOPE_DMPLEX:
334*1e07b27eSBarry Smith           ierr = PetscViewerASCIIPrintf(subviewer,"  Telescope: DMPLEX detected\n");CHKERRQ(ierr);
335*1e07b27eSBarry Smith           break;
336*1e07b27eSBarry Smith         }
337*1e07b27eSBarry Smith 
338*1e07b27eSBarry Smith         ierr = KSPView(sred->ksp,subviewer);CHKERRQ(ierr);
339*1e07b27eSBarry Smith         ierr = PetscViewerASCIIPopTab(subviewer);CHKERRQ(ierr);
340*1e07b27eSBarry Smith       }
341*1e07b27eSBarry Smith       ierr = PetscViewerRestoreSubViewer(viewer,subcomm,&subviewer);CHKERRQ(ierr);
342*1e07b27eSBarry Smith     }
343*1e07b27eSBarry Smith   }
344*1e07b27eSBarry Smith   PetscFunctionReturn(0);
345*1e07b27eSBarry Smith }
346*1e07b27eSBarry Smith 
347*1e07b27eSBarry Smith #undef __FUNCT__
348*1e07b27eSBarry Smith #define __FUNCT__ "PCSetUp_Telescope"
349*1e07b27eSBarry Smith static PetscErrorCode PCSetUp_Telescope(PC pc)
350*1e07b27eSBarry Smith {
351*1e07b27eSBarry Smith   PC_Telescope      sred = (PC_Telescope)pc->data;
352*1e07b27eSBarry Smith   PetscErrorCode    ierr;
353*1e07b27eSBarry Smith   MPI_Comm          comm,subcomm;
354*1e07b27eSBarry Smith   PCTelescopeType   sr_type;
355*1e07b27eSBarry Smith 
356*1e07b27eSBarry Smith   PetscFunctionBegin;
357*1e07b27eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
358*1e07b27eSBarry Smith 
359*1e07b27eSBarry Smith   /* subcomm definition */
360*1e07b27eSBarry Smith   if (!pc->setupcalled) {
361*1e07b27eSBarry Smith     if (!sred->psubcomm) {
362*1e07b27eSBarry Smith       ierr = PetscSubcommCreate(comm,&sred->psubcomm);CHKERRQ(ierr);
363*1e07b27eSBarry Smith       ierr = PetscSubcommSetNumber(sred->psubcomm,sred->redfactor);CHKERRQ(ierr);
364*1e07b27eSBarry Smith       ierr = PetscSubcommSetType(sred->psubcomm,PETSC_SUBCOMM_INTERLACED);CHKERRQ(ierr);
365*1e07b27eSBarry Smith       /* disable runtime switch of psubcomm type, e.g., '-psubcomm_type interlaced */
366*1e07b27eSBarry Smith       /* ierr = PetscSubcommSetFromOptions(sred->psubcomm);CHKERRQ(ierr); */
367*1e07b27eSBarry Smith       ierr = PetscLogObjectMemory((PetscObject)pc,sizeof(PetscSubcomm));CHKERRQ(ierr);
368*1e07b27eSBarry Smith       /* create a new PC that processors in each subcomm have copy of */
369*1e07b27eSBarry Smith       subcomm = PetscSubcommChild(sred->psubcomm);
370*1e07b27eSBarry Smith     }
371*1e07b27eSBarry Smith   } else {
372*1e07b27eSBarry Smith     subcomm = PetscSubcommChild(sred->psubcomm);
373*1e07b27eSBarry Smith   }
374*1e07b27eSBarry Smith 
375*1e07b27eSBarry Smith   /* internal KSP */
376*1e07b27eSBarry Smith   if (!pc->setupcalled) {
377*1e07b27eSBarry Smith     const char *prefix;
378*1e07b27eSBarry Smith 
379*1e07b27eSBarry Smith     if (isActiveRank(sred->psubcomm)) {
380*1e07b27eSBarry Smith       ierr = KSPCreate(subcomm,&sred->ksp);CHKERRQ(ierr);
381*1e07b27eSBarry Smith       ierr = KSPSetErrorIfNotConverged(sred->ksp,pc->erroriffailure);CHKERRQ(ierr);
382*1e07b27eSBarry Smith       ierr = PetscObjectIncrementTabLevel((PetscObject)sred->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
383*1e07b27eSBarry Smith       ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)sred->ksp);CHKERRQ(ierr);
384*1e07b27eSBarry Smith       ierr = KSPSetType(sred->ksp,KSPPREONLY);CHKERRQ(ierr);
385*1e07b27eSBarry Smith       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
386*1e07b27eSBarry Smith       ierr = KSPSetOptionsPrefix(sred->ksp,prefix);CHKERRQ(ierr);
387*1e07b27eSBarry Smith       ierr = KSPAppendOptionsPrefix(sred->ksp,"telescope_");CHKERRQ(ierr);
388*1e07b27eSBarry Smith     }
389*1e07b27eSBarry Smith   }
390*1e07b27eSBarry Smith   /* Determine type of setup/update */
391*1e07b27eSBarry Smith   if (!pc->setupcalled) {
392*1e07b27eSBarry Smith     PetscBool has_dm,same;
393*1e07b27eSBarry Smith     DM        dm;
394*1e07b27eSBarry Smith 
395*1e07b27eSBarry Smith     sr_type = TELESCOPE_DEFAULT;
396*1e07b27eSBarry Smith     has_dm = PETSC_FALSE;
397*1e07b27eSBarry Smith     ierr = PCGetDM(pc,&dm);CHKERRQ(ierr);
398*1e07b27eSBarry Smith     if (dm) { has_dm = PETSC_TRUE; }
399*1e07b27eSBarry Smith     if (has_dm) {
400*1e07b27eSBarry Smith       /* check for dmda */
401*1e07b27eSBarry Smith       ierr = PetscObjectTypeCompare((PetscObject)dm,DMDA,&same);CHKERRQ(ierr);
402*1e07b27eSBarry Smith       if (same) {
403*1e07b27eSBarry Smith         ierr = PetscInfo(pc,"PCTelescope: found DMDA\n");CHKERRQ(ierr);
404*1e07b27eSBarry Smith         sr_type = TELESCOPE_DMDA;
405*1e07b27eSBarry Smith       }
406*1e07b27eSBarry Smith       /* check for dmplex */
407*1e07b27eSBarry Smith       ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&same);CHKERRQ(ierr);
408*1e07b27eSBarry Smith       if (same) {
409*1e07b27eSBarry Smith         PetscInfo(pc,"PCTelescope: found DMPLEX\n");
410*1e07b27eSBarry Smith         sr_type = TELESCOPE_DMPLEX;
411*1e07b27eSBarry Smith       }
412*1e07b27eSBarry Smith     }
413*1e07b27eSBarry Smith 
414*1e07b27eSBarry Smith     if (sred->ignore_dm) {
415*1e07b27eSBarry Smith       PetscInfo(pc,"PCTelescope: ignore DM\n");
416*1e07b27eSBarry Smith       sr_type = TELESCOPE_DEFAULT;
417*1e07b27eSBarry Smith     }
418*1e07b27eSBarry Smith     sred->sr_type = sr_type;
419*1e07b27eSBarry Smith   } else {
420*1e07b27eSBarry Smith     sr_type = sred->sr_type;
421*1e07b27eSBarry Smith   }
422*1e07b27eSBarry Smith 
423*1e07b27eSBarry Smith   /* set function pointers for repartition setup, matrix creation/update, matrix nullspace and reset functionality */
424*1e07b27eSBarry Smith   switch (sr_type) {
425*1e07b27eSBarry Smith   case TELESCOPE_DEFAULT:
426*1e07b27eSBarry Smith     sred->pctelescope_setup_type              = PCTelescopeSetUp_default;
427*1e07b27eSBarry Smith     sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_default;
428*1e07b27eSBarry Smith     sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_default;
429*1e07b27eSBarry Smith     sred->pctelescope_reset_type              = NULL;
430*1e07b27eSBarry Smith     break;
431*1e07b27eSBarry Smith   case TELESCOPE_DMDA:
432*1e07b27eSBarry Smith     pc->ops->apply                          = PCApply_Telescope_dmda;
433*1e07b27eSBarry Smith     sred->pctelescope_setup_type              = PCTelescopeSetUp_dmda;
434*1e07b27eSBarry Smith     sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_dmda;
435*1e07b27eSBarry Smith     sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_dmda;
436*1e07b27eSBarry Smith     sred->pctelescope_reset_type              = PCReset_Telescope_dmda;
437*1e07b27eSBarry Smith     break;
438*1e07b27eSBarry Smith   case TELESCOPE_DMPLEX: SETERRQ(comm,PETSC_ERR_SUP,"Supprt for DMPLEX is currently not available");
439*1e07b27eSBarry Smith     break;
440*1e07b27eSBarry Smith   default: SETERRQ(comm,PETSC_ERR_SUP,"Only supprt for repartitioning DMDA is provided");
441*1e07b27eSBarry Smith     break;
442*1e07b27eSBarry Smith   }
443*1e07b27eSBarry Smith 
444*1e07b27eSBarry Smith   /* setup */
445*1e07b27eSBarry Smith   if (sred->pctelescope_setup_type) {
446*1e07b27eSBarry Smith     ierr = sred->pctelescope_setup_type(pc,sred);CHKERRQ(ierr);
447*1e07b27eSBarry Smith   }
448*1e07b27eSBarry Smith   /* update */
449*1e07b27eSBarry Smith   if (!pc->setupcalled) {
450*1e07b27eSBarry Smith     if (sred->pctelescope_matcreate_type) {
451*1e07b27eSBarry Smith       ierr = sred->pctelescope_matcreate_type(pc,sred,MAT_INITIAL_MATRIX,&sred->Bred);CHKERRQ(ierr);
452*1e07b27eSBarry Smith     }
453*1e07b27eSBarry Smith     if (sred->pctelescope_matnullspacecreate_type) {
454*1e07b27eSBarry Smith       ierr = sred->pctelescope_matnullspacecreate_type(pc,sred,sred->Bred);CHKERRQ(ierr);
455*1e07b27eSBarry Smith     }
456*1e07b27eSBarry Smith   } else {
457*1e07b27eSBarry Smith     if (sred->pctelescope_matcreate_type) {
458*1e07b27eSBarry Smith       ierr = sred->pctelescope_matcreate_type(pc,sred,MAT_REUSE_MATRIX,&sred->Bred);CHKERRQ(ierr);
459*1e07b27eSBarry Smith     }
460*1e07b27eSBarry Smith   }
461*1e07b27eSBarry Smith 
462*1e07b27eSBarry Smith   /* common - no construction */
463*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
464*1e07b27eSBarry Smith     ierr = KSPSetOperators(sred->ksp,sred->Bred,sred->Bred);CHKERRQ(ierr);
465*1e07b27eSBarry Smith     if (pc->setfromoptionscalled && !pc->setupcalled){
466*1e07b27eSBarry Smith       ierr = KSPSetFromOptions(sred->ksp);CHKERRQ(ierr);
467*1e07b27eSBarry Smith     }
468*1e07b27eSBarry Smith   }
469*1e07b27eSBarry Smith   PetscFunctionReturn(0);
470*1e07b27eSBarry Smith }
471*1e07b27eSBarry Smith 
472*1e07b27eSBarry Smith #undef __FUNCT__
473*1e07b27eSBarry Smith #define __FUNCT__ "PCApply_Telescope"
474*1e07b27eSBarry Smith static PetscErrorCode PCApply_Telescope(PC pc,Vec x,Vec y)
475*1e07b27eSBarry Smith {
476*1e07b27eSBarry Smith   PC_Telescope      sred = (PC_Telescope)pc->data;
477*1e07b27eSBarry Smith   PetscErrorCode    ierr;
478*1e07b27eSBarry Smith   Vec               xtmp,xred,yred;
479*1e07b27eSBarry Smith   PetscInt          i,st,ed,bs;
480*1e07b27eSBarry Smith   VecScatter        scatter;
481*1e07b27eSBarry Smith   PetscScalar       *array;
482*1e07b27eSBarry Smith   const PetscScalar *x_array;
483*1e07b27eSBarry Smith 
484*1e07b27eSBarry Smith   PetscFunctionBegin;
485*1e07b27eSBarry Smith   xtmp    = sred->xtmp;
486*1e07b27eSBarry Smith   scatter = sred->scatter;
487*1e07b27eSBarry Smith   xred    = sred->xred;
488*1e07b27eSBarry Smith   yred    = sred->yred;
489*1e07b27eSBarry Smith 
490*1e07b27eSBarry Smith   /* pull in vector x->xtmp */
491*1e07b27eSBarry Smith   ierr = VecScatterBegin(scatter,x,xtmp,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
492*1e07b27eSBarry Smith   ierr = VecScatterEnd(scatter,x,xtmp,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
493*1e07b27eSBarry Smith 
494*1e07b27eSBarry Smith   /* copy vector entires into xred */
495*1e07b27eSBarry Smith   ierr = VecGetBlockSize(xtmp,&bs);CHKERRQ(ierr);
496*1e07b27eSBarry Smith   ierr = VecGetArrayRead(xtmp,&x_array);CHKERRQ(ierr);
497*1e07b27eSBarry Smith   if (xred) {
498*1e07b27eSBarry Smith     PetscScalar *LA_xred;
499*1e07b27eSBarry Smith     ierr = VecGetOwnershipRange(xred,&st,&ed);CHKERRQ(ierr);
500*1e07b27eSBarry Smith     ierr = VecGetArray(xred,&LA_xred);CHKERRQ(ierr);
501*1e07b27eSBarry Smith     for (i=0; i<ed-st; i++) {
502*1e07b27eSBarry Smith       LA_xred[i] = x_array[i];
503*1e07b27eSBarry Smith     }
504*1e07b27eSBarry Smith     ierr = VecRestoreArray(xred,&LA_xred);CHKERRQ(ierr);
505*1e07b27eSBarry Smith   }
506*1e07b27eSBarry Smith   ierr = VecRestoreArrayRead(xtmp,&x_array);CHKERRQ(ierr);
507*1e07b27eSBarry Smith   /* solve */
508*1e07b27eSBarry Smith   if (isActiveRank(sred->psubcomm)) {
509*1e07b27eSBarry Smith     ierr = KSPSolve(sred->ksp,xred,yred);CHKERRQ(ierr);
510*1e07b27eSBarry Smith   }
511*1e07b27eSBarry Smith   /* return vector */
512*1e07b27eSBarry Smith   ierr = VecGetBlockSize(xtmp,&bs);CHKERRQ(ierr);
513*1e07b27eSBarry Smith   ierr = VecGetArray(xtmp,&array);CHKERRQ(ierr);
514*1e07b27eSBarry Smith   if (yred) {
515*1e07b27eSBarry Smith     const PetscScalar *LA_yred;
516*1e07b27eSBarry Smith     ierr = VecGetOwnershipRange(yred,&st,&ed);CHKERRQ(ierr);
517*1e07b27eSBarry Smith     ierr = VecGetArrayRead(yred,&LA_yred);CHKERRQ(ierr);
518*1e07b27eSBarry Smith     for (i=0; i<ed-st; i++) {
519*1e07b27eSBarry Smith       array[i] = LA_yred[i];
520*1e07b27eSBarry Smith     }
521*1e07b27eSBarry Smith     ierr = VecRestoreArrayRead(yred,&LA_yred);CHKERRQ(ierr);
522*1e07b27eSBarry Smith   } else {
523*1e07b27eSBarry Smith     for (i=0; i<bs; i++) {
524*1e07b27eSBarry Smith       array[i] = 0.0;
525*1e07b27eSBarry Smith     }
526*1e07b27eSBarry Smith   }
527*1e07b27eSBarry Smith   ierr = VecRestoreArray(xtmp,&array);CHKERRQ(ierr);
528*1e07b27eSBarry Smith   ierr = VecScatterBegin(scatter,xtmp,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
529*1e07b27eSBarry Smith   ierr = VecScatterEnd(scatter,xtmp,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
530*1e07b27eSBarry Smith   PetscFunctionReturn(0);
531*1e07b27eSBarry Smith }
532*1e07b27eSBarry Smith 
533*1e07b27eSBarry Smith #undef __FUNCT__
534*1e07b27eSBarry Smith #define __FUNCT__ "PCReset_Telescope"
535*1e07b27eSBarry Smith static PetscErrorCode PCReset_Telescope(PC pc)
536*1e07b27eSBarry Smith {
537*1e07b27eSBarry Smith   PC_Telescope   sred = (PC_Telescope)pc->data;
538*1e07b27eSBarry Smith   PetscErrorCode ierr;
539*1e07b27eSBarry Smith 
540*1e07b27eSBarry Smith   ierr = ISDestroy(&sred->isin);CHKERRQ(ierr);
541*1e07b27eSBarry Smith   ierr = VecScatterDestroy(&sred->scatter);CHKERRQ(ierr);
542*1e07b27eSBarry Smith   if (sred->xred) { ierr = VecDestroy(&sred->xred);CHKERRQ(ierr); }
543*1e07b27eSBarry Smith   if (sred->yred) { ierr = VecDestroy(&sred->yred);CHKERRQ(ierr); }
544*1e07b27eSBarry Smith   if (sred->xtmp) { ierr = VecDestroy(&sred->xtmp);CHKERRQ(ierr); }
545*1e07b27eSBarry Smith   if (sred->Bred) { ierr = MatDestroy(&sred->Bred);CHKERRQ(ierr); }
546*1e07b27eSBarry Smith   if (sred->ksp) { ierr = KSPReset(sred->ksp);CHKERRQ(ierr); }
547*1e07b27eSBarry Smith   if (sred->pctelescope_reset_type) {
548*1e07b27eSBarry Smith     ierr = sred->pctelescope_reset_type(pc);CHKERRQ(ierr);
549*1e07b27eSBarry Smith   }
550*1e07b27eSBarry Smith   PetscFunctionReturn(0);
551*1e07b27eSBarry Smith }
552*1e07b27eSBarry Smith 
553*1e07b27eSBarry Smith #undef __FUNCT__
554*1e07b27eSBarry Smith #define __FUNCT__ "PCDestroy_Telescope"
555*1e07b27eSBarry Smith static PetscErrorCode PCDestroy_Telescope(PC pc)
556*1e07b27eSBarry Smith {
557*1e07b27eSBarry Smith   PC_Telescope     sred = (PC_Telescope)pc->data;
558*1e07b27eSBarry Smith   PetscErrorCode   ierr;
559*1e07b27eSBarry Smith 
560*1e07b27eSBarry Smith   PetscFunctionBegin;
561*1e07b27eSBarry Smith   ierr = PCReset_Telescope(pc);CHKERRQ(ierr);
562*1e07b27eSBarry Smith   if (sred->ksp) { ierr = KSPDestroy(&sred->ksp);CHKERRQ(ierr); }
563*1e07b27eSBarry Smith   ierr = PetscSubcommDestroy(&sred->psubcomm);CHKERRQ(ierr);
564*1e07b27eSBarry Smith   if (sred->dm_ctx) PetscFree(sred->dm_ctx);
565*1e07b27eSBarry Smith   PetscFree(pc->data);
566*1e07b27eSBarry Smith   PetscFunctionReturn(0);
567*1e07b27eSBarry Smith }
568*1e07b27eSBarry Smith 
569*1e07b27eSBarry Smith #undef __FUNCT__
570*1e07b27eSBarry Smith #define __FUNCT__ "PCSetFromOptions_Telescope"
571*1e07b27eSBarry Smith static PetscErrorCode PCSetFromOptions_Telescope(PetscOptions *PetscOptionsObject,PC pc)
572*1e07b27eSBarry Smith {
573*1e07b27eSBarry Smith   PC_Telescope     sred = (PC_Telescope)pc->data;
574*1e07b27eSBarry Smith   PetscErrorCode   ierr;
575*1e07b27eSBarry Smith   MPI_Comm         comm;
576*1e07b27eSBarry Smith   PetscMPIInt      size;
577*1e07b27eSBarry Smith 
578*1e07b27eSBarry Smith   PetscFunctionBegin;
579*1e07b27eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
580*1e07b27eSBarry Smith   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
581*1e07b27eSBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"Telescope options");CHKERRQ(ierr);
582*1e07b27eSBarry Smith   ierr = PetscOptionsInt("-pc_telescope_reduction_factor","Factor to reduce comm size by","PCTelescopeSetReductionFactor",sred->redfactor,&sred->redfactor,0);CHKERRQ(ierr);
583*1e07b27eSBarry Smith   if (sred->redfactor > size) SETERRQ(comm,PETSC_ERR_ARG_WRONG,"-pc_telescope_reduction_factor <= comm size");
584*1e07b27eSBarry Smith   ierr = PetscOptionsBool("-pc_telescope_ignore_dm","Ignore any DM attached to the PC","PCTelescopeSetIgnoreDM",sred->ignore_dm,&sred->ignore_dm,0);CHKERRQ(ierr);
585*1e07b27eSBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
586*1e07b27eSBarry Smith   PetscFunctionReturn(0);
587*1e07b27eSBarry Smith }
588*1e07b27eSBarry Smith 
589*1e07b27eSBarry Smith /* PC simplementation specific API's */
590*1e07b27eSBarry Smith 
591*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeGetKSP_Telescope(PC pc,KSP *ksp)
592*1e07b27eSBarry Smith {
593*1e07b27eSBarry Smith   PC_Telescope red = (PC_Telescope)pc->data;
594*1e07b27eSBarry Smith   if (ksp) *ksp = red->ksp;
595*1e07b27eSBarry Smith   return(0);
596*1e07b27eSBarry Smith }
597*1e07b27eSBarry Smith 
598*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeGetReductionFactor_Telescope(PC pc,PetscInt *fact)
599*1e07b27eSBarry Smith {
600*1e07b27eSBarry Smith   PC_Telescope red = (PC_Telescope)pc->data;
601*1e07b27eSBarry Smith   if (fact) *fact = red->redfactor;
602*1e07b27eSBarry Smith   return(0);
603*1e07b27eSBarry Smith }
604*1e07b27eSBarry Smith 
605*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeSetReductionFactor_Telescope(PC pc,PetscInt fact)
606*1e07b27eSBarry Smith {
607*1e07b27eSBarry Smith   PC_Telescope     red = (PC_Telescope)pc->data;
608*1e07b27eSBarry Smith   PetscMPIInt      size;
609*1e07b27eSBarry Smith   PetscErrorCode   ierr;
610*1e07b27eSBarry Smith 
611*1e07b27eSBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size);CHKERRQ(ierr);
612*1e07b27eSBarry Smith   if (fact <= 0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Reduction factor of telescoping PC %D must be positive",fact);
613*1e07b27eSBarry Smith   if (fact > size) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Reduction factor of telescoping PC %D must be <= comm.size",fact);
614*1e07b27eSBarry Smith   red->redfactor = fact;
615*1e07b27eSBarry Smith   return(0);
616*1e07b27eSBarry Smith }
617*1e07b27eSBarry Smith 
618*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeGetIgnoreDM_Telescope(PC pc,PetscBool *v)
619*1e07b27eSBarry Smith {
620*1e07b27eSBarry Smith   PC_Telescope red = (PC_Telescope)pc->data;
621*1e07b27eSBarry Smith   if (v) *v = red->ignore_dm;
622*1e07b27eSBarry Smith   return(0);
623*1e07b27eSBarry Smith }
624*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeSetIgnoreDM_Telescope(PC pc,PetscBool v)
625*1e07b27eSBarry Smith {
626*1e07b27eSBarry Smith   PC_Telescope red = (PC_Telescope)pc->data;
627*1e07b27eSBarry Smith   red->ignore_dm = v;
628*1e07b27eSBarry Smith   return(0);
629*1e07b27eSBarry Smith }
630*1e07b27eSBarry Smith 
631*1e07b27eSBarry Smith static PetscErrorCode PCTelescopeGetDM_Telescope(PC pc,DM *dm)
632*1e07b27eSBarry Smith {
633*1e07b27eSBarry Smith   PC_Telescope red = (PC_Telescope)pc->data;
634*1e07b27eSBarry Smith   *dm = private_PCTelescopeGetSubDM(red);
635*1e07b27eSBarry Smith   return(0);
636*1e07b27eSBarry Smith }
637*1e07b27eSBarry Smith 
638*1e07b27eSBarry Smith /*@
639*1e07b27eSBarry Smith  PCTelescopeGetKSP - Gets the KSP created by the telescoping PC.
640*1e07b27eSBarry Smith 
641*1e07b27eSBarry Smith  Not Collective
642*1e07b27eSBarry Smith 
643*1e07b27eSBarry Smith  Input Parameter:
644*1e07b27eSBarry Smith  .  pc - the preconditioner context
645*1e07b27eSBarry Smith 
646*1e07b27eSBarry Smith  Output Parameter:
647*1e07b27eSBarry Smith  .  subksp - the KSP defined the smaller set of processes
648*1e07b27eSBarry Smith 
649*1e07b27eSBarry Smith  Level: advanced
650*1e07b27eSBarry Smith 
651*1e07b27eSBarry Smith  .keywords: PC, telescopting solve
652*1e07b27eSBarry Smith  @*/
653*1e07b27eSBarry Smith PetscErrorCode PCTelescopeGetKSP(PC pc,KSP *subksp)
654*1e07b27eSBarry Smith {
655*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeGetKSP_C",(PC,KSP*),(pc,subksp));
656*1e07b27eSBarry Smith   return(0);
657*1e07b27eSBarry Smith }
658*1e07b27eSBarry Smith 
659*1e07b27eSBarry Smith /*@
660*1e07b27eSBarry Smith  PCTelescopeGetReductionFactor - Gets the factor by which the original number of processes has been reduced by.
661*1e07b27eSBarry Smith 
662*1e07b27eSBarry Smith  Not Collective
663*1e07b27eSBarry Smith 
664*1e07b27eSBarry Smith  Input Parameter:
665*1e07b27eSBarry Smith  .  pc - the preconditioner context
666*1e07b27eSBarry Smith 
667*1e07b27eSBarry Smith  Output Parameter:
668*1e07b27eSBarry Smith  .  fact - the reduction factor
669*1e07b27eSBarry Smith 
670*1e07b27eSBarry Smith  Level: advanced
671*1e07b27eSBarry Smith 
672*1e07b27eSBarry Smith  .keywords: PC, telescoping solve
673*1e07b27eSBarry Smith  @*/
674*1e07b27eSBarry Smith PetscErrorCode PCTelescopeGetReductionFactor(PC pc,PetscInt *fact)
675*1e07b27eSBarry Smith {
676*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeGetReductionFactor_C",(PC,PetscInt*),(pc,fact));
677*1e07b27eSBarry Smith   return(0);
678*1e07b27eSBarry Smith }
679*1e07b27eSBarry Smith 
680*1e07b27eSBarry Smith /*@
681*1e07b27eSBarry Smith  PCTelescopeSetReductionFactor - Sets the factor by which the original number of processes has been reduced by.
682*1e07b27eSBarry Smith 
683*1e07b27eSBarry Smith  Not Collective
684*1e07b27eSBarry Smith 
685*1e07b27eSBarry Smith  Input Parameter:
686*1e07b27eSBarry Smith  .  pc - the preconditioner context
687*1e07b27eSBarry Smith 
688*1e07b27eSBarry Smith  Output Parameter:
689*1e07b27eSBarry Smith  .  fact - the reduction factor
690*1e07b27eSBarry Smith 
691*1e07b27eSBarry Smith  Level: advanced
692*1e07b27eSBarry Smith 
693*1e07b27eSBarry Smith  .keywords: PC, telescoping solve
694*1e07b27eSBarry Smith  @*/
695*1e07b27eSBarry Smith PetscErrorCode PCTelescopeSetReductionFactor(PC pc,PetscInt fact)
696*1e07b27eSBarry Smith {
697*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeSetReductionFactor_C",(PC,PetscInt),(pc,fact));
698*1e07b27eSBarry Smith   return(0);
699*1e07b27eSBarry Smith }
700*1e07b27eSBarry Smith 
701*1e07b27eSBarry Smith /*@
702*1e07b27eSBarry Smith  PCTelescopeGetIgnoreDM - Get the flag indicating if any DM attached to the PC will be used.
703*1e07b27eSBarry Smith 
704*1e07b27eSBarry Smith  Not Collective
705*1e07b27eSBarry Smith 
706*1e07b27eSBarry Smith  Input Parameter:
707*1e07b27eSBarry Smith  .  pc - the preconditioner context
708*1e07b27eSBarry Smith 
709*1e07b27eSBarry Smith  Output Parameter:
710*1e07b27eSBarry Smith  .  v - the flag
711*1e07b27eSBarry Smith 
712*1e07b27eSBarry Smith  Level: advanced
713*1e07b27eSBarry Smith 
714*1e07b27eSBarry Smith  .keywords: PC, telescoping solve
715*1e07b27eSBarry Smith  @*/
716*1e07b27eSBarry Smith PetscErrorCode PCTelescopeGetIgnoreDM(PC pc,PetscBool *v)
717*1e07b27eSBarry Smith {
718*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeGetIgnoreDM_C",(PC,PetscBool*),(pc,v));
719*1e07b27eSBarry Smith   return(0);
720*1e07b27eSBarry Smith }
721*1e07b27eSBarry Smith 
722*1e07b27eSBarry Smith /*@
723*1e07b27eSBarry Smith  PCTelescopeSetIgnoreDM - Set a flag to ignore any DM attached to the PC.
724*1e07b27eSBarry Smith 
725*1e07b27eSBarry Smith  Not Collective
726*1e07b27eSBarry Smith 
727*1e07b27eSBarry Smith  Input Parameter:
728*1e07b27eSBarry Smith  .  pc - the preconditioner context
729*1e07b27eSBarry Smith 
730*1e07b27eSBarry Smith  Output Parameter:
731*1e07b27eSBarry Smith  .  v - Use PETSC_TRUE to ignore any DM
732*1e07b27eSBarry Smith 
733*1e07b27eSBarry Smith  Level: advanced
734*1e07b27eSBarry Smith 
735*1e07b27eSBarry Smith  .keywords: PC, telescoping solve
736*1e07b27eSBarry Smith  @*/
737*1e07b27eSBarry Smith PetscErrorCode PCTelescopeSetIgnoreDM(PC pc,PetscInt v)
738*1e07b27eSBarry Smith {
739*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeSetIgnoreDM_C",(PC,PetscBool),(pc,v));
740*1e07b27eSBarry Smith   return(0);
741*1e07b27eSBarry Smith }
742*1e07b27eSBarry Smith 
743*1e07b27eSBarry Smith /*@
744*1e07b27eSBarry Smith  PCTelescopeGetDM - Get the re-partitioned DM attached to the sub KSP.
745*1e07b27eSBarry Smith 
746*1e07b27eSBarry Smith  Not Collective
747*1e07b27eSBarry Smith 
748*1e07b27eSBarry Smith  Input Parameter:
749*1e07b27eSBarry Smith  .  pc - the preconditioner context
750*1e07b27eSBarry Smith 
751*1e07b27eSBarry Smith  Output Parameter:
752*1e07b27eSBarry Smith  .  subdm - The re-partitioned DM
753*1e07b27eSBarry Smith 
754*1e07b27eSBarry Smith  Level: advanced
755*1e07b27eSBarry Smith 
756*1e07b27eSBarry Smith  .keywords: PC, telescoping solve
757*1e07b27eSBarry Smith  @*/
758*1e07b27eSBarry Smith PetscErrorCode PCTelescopeGetDM(PC pc,DM *subdm)
759*1e07b27eSBarry Smith {
760*1e07b27eSBarry Smith   PetscTryMethod(pc,"PCTelescopeGetDM_C",(PC,DM*),(pc,subdm));
761*1e07b27eSBarry Smith   return(0);
762*1e07b27eSBarry Smith }
763*1e07b27eSBarry Smith 
764*1e07b27eSBarry Smith /* -------------------------------------------------------------------------------------*/
765*1e07b27eSBarry Smith /*MC
766*1e07b27eSBarry Smith    PCTELESCOPE - Runs a KSP solver on a sub-group of processors. MPI processes not in the sub-communicator are idle during the solve.
767*1e07b27eSBarry Smith 
768*1e07b27eSBarry Smith    Options Database:
769*1e07b27eSBarry Smith +  -pc_telescope_reduction_factor <n> - factor to use communicator size by, for example if you are using 64 MPI processes and
770*1e07b27eSBarry Smith    use an n of 4, the new sub-communicator will be 4 defined with 64/4 processes
771*1e07b27eSBarry Smith -  -pc_telescope_ignore_dm <false> - flag to indicate whether an attached DM should be ignored
772*1e07b27eSBarry Smith 
773*1e07b27eSBarry Smith    Level: advanced
774*1e07b27eSBarry Smith 
775*1e07b27eSBarry Smith    Notes:
776*1e07b27eSBarry Smith    The default KSP is PREONLY. If a DM is attached to the PC, it is re-partitioned on the sub-communicator.
777*1e07b27eSBarry Smith    Both the B mat operator and the right hand side vector are permuted into the new DOF ordering defined by the re-partitioned DM.
778*1e07b27eSBarry Smith    Currently only support for re-partitioning a DMDA is provided.
779*1e07b27eSBarry Smith    Any nullspace attached to the original Bmat operator are extracted, re-partitioned and set on the repartitioned Bmat operator.
780*1e07b27eSBarry Smith    KSPSetComputeOperators() is not propagated to the sub KSP.
781*1e07b27eSBarry Smith    Currently there is no support for the flag -pc_use_amat
782*1e07b27eSBarry Smith 
783*1e07b27eSBarry Smith    Optimizations:
784*1e07b27eSBarry Smith    (i) VecPlaceArray() could be used for scatters between the vectors defined on different sized communicators, thereby slightly reducing memory footprint;
785*1e07b27eSBarry Smith    (ii) Memory re-use and faster set-up would follow if the result of P^T.A.P was not re-allocated each time PCSetUp_Telescope() was called (DMDA).
786*1e07b27eSBarry Smith 
787*1e07b27eSBarry Smith  Contributed by Dave May
788*1e07b27eSBarry Smith 
789*1e07b27eSBarry Smith .seealso:  PCTelescopeGetKSP(), PCTelescopeGetDM(),
790*1e07b27eSBarry Smith  PCTelescopeGetReductionFactor(), PCTelescopeSetReductionFactor(),
791*1e07b27eSBarry Smith  PCTelescopeGetIgnoreDM(), PCTelescopeSetIgnoreDM(), PCREDUNDANT
792*1e07b27eSBarry Smith M*/
793*1e07b27eSBarry Smith #undef __FUNCT__
794*1e07b27eSBarry Smith #define __FUNCT__ "PCCreate_Telescope"
795*1e07b27eSBarry Smith PETSC_EXTERN PetscErrorCode PCCreate_Telescope(PC pc)
796*1e07b27eSBarry Smith {
797*1e07b27eSBarry Smith   PetscErrorCode       ierr;
798*1e07b27eSBarry Smith   struct _PC_Telescope *sred;
799*1e07b27eSBarry Smith 
800*1e07b27eSBarry Smith   PetscFunctionBegin;
801*1e07b27eSBarry Smith   ierr = PetscNewLog(pc,&sred);CHKERRQ(ierr);
802*1e07b27eSBarry Smith   sred->redfactor      = 1;
803*1e07b27eSBarry Smith   sred->ignore_dm      = PETSC_FALSE;
804*1e07b27eSBarry Smith   pc->data             = (void*)sred;
805*1e07b27eSBarry Smith 
806*1e07b27eSBarry Smith   pc->ops->apply          = PCApply_Telescope;
807*1e07b27eSBarry Smith   pc->ops->applytranspose = NULL;
808*1e07b27eSBarry Smith   pc->ops->setup          = PCSetUp_Telescope;
809*1e07b27eSBarry Smith   pc->ops->destroy        = PCDestroy_Telescope;
810*1e07b27eSBarry Smith   pc->ops->reset          = PCReset_Telescope;
811*1e07b27eSBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Telescope;
812*1e07b27eSBarry Smith   pc->ops->view           = PCView_Telescope;
813*1e07b27eSBarry Smith 
814*1e07b27eSBarry Smith   sred->pctelescope_setup_type              = PCTelescopeSetUp_default;
815*1e07b27eSBarry Smith   sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_default;
816*1e07b27eSBarry Smith   sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_default;
817*1e07b27eSBarry Smith   sred->pctelescope_reset_type              = NULL;
818*1e07b27eSBarry Smith 
819*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeGetKSP_C",PCTelescopeGetKSP_Telescope);CHKERRQ(ierr);
820*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeGetReductionFactor_C",PCTelescopeGetReductionFactor_Telescope);CHKERRQ(ierr);
821*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeSetReductionFactor_C",PCTelescopeSetReductionFactor_Telescope);CHKERRQ(ierr);
822*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeGetIgnoreDM_C",PCTelescopeGetIgnoreDM_Telescope);CHKERRQ(ierr);
823*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeSetIgnoreDM_C",PCTelescopeSetIgnoreDM_Telescope);CHKERRQ(ierr);
824*1e07b27eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCTelescopeGetDM_C",PCTelescopeGetDM_Telescope);CHKERRQ(ierr);
825*1e07b27eSBarry Smith   PetscFunctionReturn(0);
826*1e07b27eSBarry Smith }
827