xref: /petsc/src/ksp/pc/impls/telescope/telescope.c (revision bcee047adeeb73090d7e36cc71e39fc287cdbb97)
1 #include <petsc/private/petscimpl.h>
2 #include <petsc/private/matimpl.h>
3 #include <petsc/private/pcimpl.h>
4 #include <petscksp.h> /*I "petscksp.h" I*/
5 #include <petscdm.h>  /*I "petscdm.h" I*/
6 #include "../src/ksp/pc/impls/telescope/telescope.h"
7 
8 static PetscBool  cited      = PETSC_FALSE;
9 static const char citation[] = "@inproceedings{MaySananRuppKnepleySmith2016,\n"
10                                "  title     = {Extreme-Scale Multigrid Components within PETSc},\n"
11                                "  author    = {Dave A. May and Patrick Sanan and Karl Rupp and Matthew G. Knepley and Barry F. Smith},\n"
12                                "  booktitle = {Proceedings of the Platform for Advanced Scientific Computing Conference},\n"
13                                "  series    = {PASC '16},\n"
14                                "  isbn      = {978-1-4503-4126-4},\n"
15                                "  location  = {Lausanne, Switzerland},\n"
16                                "  pages     = {5:1--5:12},\n"
17                                "  articleno = {5},\n"
18                                "  numpages  = {12},\n"
19                                "  url       = {https://doi.acm.org/10.1145/2929908.2929913},\n"
20                                "  doi       = {10.1145/2929908.2929913},\n"
21                                "  acmid     = {2929913},\n"
22                                "  publisher = {ACM},\n"
23                                "  address   = {New York, NY, USA},\n"
24                                "  keywords  = {GPU, HPC, agglomeration, coarse-level solver, multigrid, parallel computing, preconditioning},\n"
25                                "  year      = {2016}\n"
26                                "}\n";
27 
28 /*
29  default setup mode
30 
31  [1a] scatter to (FORWARD)
32  x(comm) -> xtmp(comm)
33  [1b] local copy (to) ranks with color = 0
34  xred(subcomm) <- xtmp
35 
36  [2] solve on sub KSP to obtain yred(subcomm)
37 
38  [3a] local copy (from) ranks with color = 0
39  yred(subcomm) --> xtmp
40  [2b] scatter from (REVERSE)
41  xtmp(comm) -> y(comm)
42 */
43 
44 /*
45   Collective[comm_f]
46   Notes
47    * Using comm_f = MPI_COMM_NULL will result in an error
48    * Using comm_c = MPI_COMM_NULL is valid. If all instances of comm_c are NULL the subcomm is not valid.
49    * If any non NULL comm_c communicator cannot map any of its ranks to comm_f, the subcomm is not valid.
50 */
51 PetscErrorCode PCTelescopeTestValidSubcomm(MPI_Comm comm_f, MPI_Comm comm_c, PetscBool *isvalid)
52 {
53   PetscInt     valid = 1;
54   MPI_Group    group_f, group_c;
55   PetscMPIInt  count, k, size_f = 0, size_c = 0, size_c_sum = 0;
56   PetscMPIInt *ranks_f, *ranks_c;
57 
58   PetscFunctionBegin;
59   PetscCheck(comm_f != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_SUP, "comm_f cannot be MPI_COMM_NULL");
60 
61   PetscCallMPI(MPI_Comm_group(comm_f, &group_f));
62   if (comm_c != MPI_COMM_NULL) PetscCallMPI(MPI_Comm_group(comm_c, &group_c));
63 
64   PetscCallMPI(MPI_Comm_size(comm_f, &size_f));
65   if (comm_c != MPI_COMM_NULL) PetscCallMPI(MPI_Comm_size(comm_c, &size_c));
66 
67   /* check not all comm_c's are NULL */
68   size_c_sum = size_c;
69   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &size_c_sum, 1, MPI_INT, MPI_SUM, comm_f));
70   if (size_c_sum == 0) valid = 0;
71 
72   /* check we can map at least 1 rank in comm_c to comm_f */
73   PetscCall(PetscMalloc1(size_f, &ranks_f));
74   PetscCall(PetscMalloc1(size_c, &ranks_c));
75   for (k = 0; k < size_f; k++) ranks_f[k] = MPI_UNDEFINED;
76   for (k = 0; k < size_c; k++) ranks_c[k] = k;
77 
78   /*
79    MPI_Group_translate_ranks() returns a non-zero exit code if any rank cannot be translated.
80    I do not want the code to terminate immediately if this occurs, rather I want to throw
81    the error later (during PCSetUp_Telescope()) via SETERRQ() with a message indicating
82    that comm_c is not a valid sub-communicator.
83    Hence I purposefully do not call PetscCall() after MPI_Group_translate_ranks().
84   */
85   count = 0;
86   if (comm_c != MPI_COMM_NULL) {
87     (void)MPI_Group_translate_ranks(group_c, size_c, ranks_c, group_f, ranks_f);
88     for (k = 0; k < size_f; k++) {
89       if (ranks_f[k] == MPI_UNDEFINED) count++;
90     }
91   }
92   if (count == size_f) valid = 0;
93 
94   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &valid, 1, MPIU_INT, MPI_MIN, comm_f));
95   if (valid == 1) *isvalid = PETSC_TRUE;
96   else *isvalid = PETSC_FALSE;
97 
98   PetscCall(PetscFree(ranks_f));
99   PetscCall(PetscFree(ranks_c));
100   PetscCallMPI(MPI_Group_free(&group_f));
101   if (comm_c != MPI_COMM_NULL) PetscCallMPI(MPI_Group_free(&group_c));
102   PetscFunctionReturn(PETSC_SUCCESS);
103 }
104 
105 DM private_PCTelescopeGetSubDM(PC_Telescope sred)
106 {
107   DM subdm = NULL;
108 
109   if (!PCTelescope_isActiveRank(sred)) {
110     subdm = NULL;
111   } else {
112     switch (sred->sr_type) {
113     case TELESCOPE_DEFAULT:
114       subdm = NULL;
115       break;
116     case TELESCOPE_DMDA:
117       subdm = ((PC_Telescope_DMDACtx *)sred->dm_ctx)->dmrepart;
118       break;
119     case TELESCOPE_DMPLEX:
120       subdm = NULL;
121       break;
122     case TELESCOPE_COARSEDM:
123       if (sred->ksp) PetscCallAbort(PETSC_COMM_SELF, KSPGetDM(sred->ksp, &subdm));
124       break;
125     }
126   }
127   return subdm;
128 }
129 
130 PetscErrorCode PCTelescopeSetUp_default(PC pc, PC_Telescope sred)
131 {
132   PetscInt   m, M, bs, st, ed;
133   Vec        x, xred, yred, xtmp;
134   Mat        B;
135   MPI_Comm   comm, subcomm;
136   VecScatter scatter;
137   IS         isin;
138   VecType    vectype;
139 
140   PetscFunctionBegin;
141   PetscCall(PetscInfo(pc, "PCTelescope: setup (default)\n"));
142   comm    = PetscSubcommParent(sred->psubcomm);
143   subcomm = PetscSubcommChild(sred->psubcomm);
144 
145   PetscCall(PCGetOperators(pc, NULL, &B));
146   PetscCall(MatGetSize(B, &M, NULL));
147   PetscCall(MatGetBlockSize(B, &bs));
148   PetscCall(MatCreateVecs(B, &x, NULL));
149   PetscCall(MatGetVecType(B, &vectype));
150 
151   xred = NULL;
152   m    = 0;
153   if (PCTelescope_isActiveRank(sred)) {
154     PetscCall(VecCreate(subcomm, &xred));
155     PetscCall(VecSetSizes(xred, PETSC_DECIDE, M));
156     PetscCall(VecSetBlockSize(xred, bs));
157     PetscCall(VecSetType(xred, vectype)); /* Use the preconditioner matrix's vectype by default */
158     PetscCall(VecSetFromOptions(xred));
159     PetscCall(VecGetLocalSize(xred, &m));
160   }
161 
162   yred = NULL;
163   if (PCTelescope_isActiveRank(sred)) PetscCall(VecDuplicate(xred, &yred));
164 
165   PetscCall(VecCreate(comm, &xtmp));
166   PetscCall(VecSetSizes(xtmp, m, PETSC_DECIDE));
167   PetscCall(VecSetBlockSize(xtmp, bs));
168   PetscCall(VecSetType(xtmp, vectype));
169 
170   if (PCTelescope_isActiveRank(sred)) {
171     PetscCall(VecGetOwnershipRange(xred, &st, &ed));
172     PetscCall(ISCreateStride(comm, (ed - st), st, 1, &isin));
173   } else {
174     PetscCall(VecGetOwnershipRange(x, &st, &ed));
175     PetscCall(ISCreateStride(comm, 0, st, 1, &isin));
176   }
177   PetscCall(ISSetBlockSize(isin, bs));
178 
179   PetscCall(VecScatterCreate(x, isin, xtmp, NULL, &scatter));
180 
181   sred->isin    = isin;
182   sred->scatter = scatter;
183   sred->xred    = xred;
184   sred->yred    = yred;
185   sred->xtmp    = xtmp;
186   PetscCall(VecDestroy(&x));
187   PetscFunctionReturn(PETSC_SUCCESS);
188 }
189 
190 PetscErrorCode PCTelescopeMatCreate_default(PC pc, PC_Telescope sred, MatReuse reuse, Mat *A)
191 {
192   MPI_Comm comm, subcomm;
193   Mat      Bred, B;
194   PetscInt nr, nc, bs;
195   IS       isrow, iscol;
196   Mat      Blocal, *_Blocal;
197 
198   PetscFunctionBegin;
199   PetscCall(PetscInfo(pc, "PCTelescope: updating the redundant preconditioned operator (default)\n"));
200   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
201   subcomm = PetscSubcommChild(sred->psubcomm);
202   PetscCall(PCGetOperators(pc, NULL, &B));
203   PetscCall(MatGetSize(B, &nr, &nc));
204   isrow = sred->isin;
205   PetscCall(ISCreateStride(PETSC_COMM_SELF, nc, 0, 1, &iscol));
206   PetscCall(ISSetIdentity(iscol));
207   PetscCall(MatGetBlockSizes(B, NULL, &bs));
208   PetscCall(ISSetBlockSize(iscol, bs));
209   PetscCall(MatSetOption(B, MAT_SUBMAT_SINGLEIS, PETSC_TRUE));
210   PetscCall(MatCreateSubMatrices(B, 1, &isrow, &iscol, MAT_INITIAL_MATRIX, &_Blocal));
211   Blocal = *_Blocal;
212   PetscCall(PetscFree(_Blocal));
213   Bred = NULL;
214   if (PCTelescope_isActiveRank(sred)) {
215     PetscInt mm;
216 
217     if (reuse != MAT_INITIAL_MATRIX) Bred = *A;
218 
219     PetscCall(MatGetSize(Blocal, &mm, NULL));
220     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, Blocal, mm, reuse, &Bred));
221   }
222   *A = Bred;
223   PetscCall(ISDestroy(&iscol));
224   PetscCall(MatDestroy(&Blocal));
225   PetscFunctionReturn(PETSC_SUCCESS);
226 }
227 
228 static PetscErrorCode PCTelescopeSubNullSpaceCreate_Telescope(PC pc, PC_Telescope sred, MatNullSpace nullspace, MatNullSpace *sub_nullspace)
229 {
230   PetscBool  has_const;
231   const Vec *vecs;
232   Vec       *sub_vecs = NULL;
233   PetscInt   i, k, n = 0;
234   MPI_Comm   subcomm;
235 
236   PetscFunctionBegin;
237   subcomm = PetscSubcommChild(sred->psubcomm);
238   PetscCall(MatNullSpaceGetVecs(nullspace, &has_const, &n, &vecs));
239 
240   if (PCTelescope_isActiveRank(sred)) {
241     if (n) PetscCall(VecDuplicateVecs(sred->xred, n, &sub_vecs));
242   }
243 
244   /* copy entries */
245   for (k = 0; k < n; k++) {
246     const PetscScalar *x_array;
247     PetscScalar       *LA_sub_vec;
248     PetscInt           st, ed;
249 
250     /* pull in vector x->xtmp */
251     PetscCall(VecScatterBegin(sred->scatter, vecs[k], sred->xtmp, INSERT_VALUES, SCATTER_FORWARD));
252     PetscCall(VecScatterEnd(sred->scatter, vecs[k], sred->xtmp, INSERT_VALUES, SCATTER_FORWARD));
253     if (sub_vecs) {
254       /* copy vector entries into xred */
255       PetscCall(VecGetArrayRead(sred->xtmp, &x_array));
256       if (sub_vecs[k]) {
257         PetscCall(VecGetOwnershipRange(sub_vecs[k], &st, &ed));
258         PetscCall(VecGetArray(sub_vecs[k], &LA_sub_vec));
259         for (i = 0; i < ed - st; i++) LA_sub_vec[i] = x_array[i];
260         PetscCall(VecRestoreArray(sub_vecs[k], &LA_sub_vec));
261       }
262       PetscCall(VecRestoreArrayRead(sred->xtmp, &x_array));
263     }
264   }
265 
266   if (PCTelescope_isActiveRank(sred)) {
267     /* create new (near) nullspace for redundant object */
268     PetscCall(MatNullSpaceCreate(subcomm, has_const, n, sub_vecs, sub_nullspace));
269     PetscCall(VecDestroyVecs(n, &sub_vecs));
270     PetscCheck(!nullspace->remove, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Propagation of custom remove callbacks not supported when propagating (near) nullspaces with PCTelescope");
271     PetscCheck(!nullspace->rmctx, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Propagation of custom remove callback context not supported when propagating (near) nullspaces with PCTelescope");
272   }
273   PetscFunctionReturn(PETSC_SUCCESS);
274 }
275 
276 static PetscErrorCode PCTelescopeMatNullSpaceCreate_default(PC pc, PC_Telescope sred, Mat sub_mat)
277 {
278   Mat B;
279 
280   PetscFunctionBegin;
281   PetscCall(PCGetOperators(pc, NULL, &B));
282   /* Propagate the nullspace if it exists */
283   {
284     MatNullSpace nullspace, sub_nullspace;
285     PetscCall(MatGetNullSpace(B, &nullspace));
286     if (nullspace) {
287       PetscCall(PetscInfo(pc, "PCTelescope: generating nullspace (default)\n"));
288       PetscCall(PCTelescopeSubNullSpaceCreate_Telescope(pc, sred, nullspace, &sub_nullspace));
289       if (PCTelescope_isActiveRank(sred)) {
290         PetscCall(MatSetNullSpace(sub_mat, sub_nullspace));
291         PetscCall(MatNullSpaceDestroy(&sub_nullspace));
292       }
293     }
294   }
295   /* Propagate the near nullspace if it exists */
296   {
297     MatNullSpace nearnullspace, sub_nearnullspace;
298     PetscCall(MatGetNearNullSpace(B, &nearnullspace));
299     if (nearnullspace) {
300       PetscCall(PetscInfo(pc, "PCTelescope: generating near nullspace (default)\n"));
301       PetscCall(PCTelescopeSubNullSpaceCreate_Telescope(pc, sred, nearnullspace, &sub_nearnullspace));
302       if (PCTelescope_isActiveRank(sred)) {
303         PetscCall(MatSetNearNullSpace(sub_mat, sub_nearnullspace));
304         PetscCall(MatNullSpaceDestroy(&sub_nearnullspace));
305       }
306     }
307   }
308   PetscFunctionReturn(PETSC_SUCCESS);
309 }
310 
311 static PetscErrorCode PCView_Telescope(PC pc, PetscViewer viewer)
312 {
313   PC_Telescope sred = (PC_Telescope)pc->data;
314   PetscBool    iascii, isstring;
315   PetscViewer  subviewer;
316 
317   PetscFunctionBegin;
318   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
319   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
320   if (iascii) {
321     {
322       MPI_Comm    comm, subcomm;
323       PetscMPIInt comm_size, subcomm_size;
324       DM          dm = NULL, subdm = NULL;
325 
326       PetscCall(PCGetDM(pc, &dm));
327       subdm = private_PCTelescopeGetSubDM(sred);
328 
329       if (sred->psubcomm) {
330         comm    = PetscSubcommParent(sred->psubcomm);
331         subcomm = PetscSubcommChild(sred->psubcomm);
332         PetscCallMPI(MPI_Comm_size(comm, &comm_size));
333         PetscCallMPI(MPI_Comm_size(subcomm, &subcomm_size));
334 
335         PetscCall(PetscViewerASCIIPushTab(viewer));
336         PetscCall(PetscViewerASCIIPrintf(viewer, "petsc subcomm: parent comm size reduction factor = %" PetscInt_FMT "\n", sred->redfactor));
337         PetscCall(PetscViewerASCIIPrintf(viewer, "petsc subcomm: parent_size = %d , subcomm_size = %d\n", (int)comm_size, (int)subcomm_size));
338         switch (sred->subcommtype) {
339         case PETSC_SUBCOMM_INTERLACED:
340           PetscCall(PetscViewerASCIIPrintf(viewer, "petsc subcomm: type = %s\n", PetscSubcommTypes[sred->subcommtype]));
341           break;
342         case PETSC_SUBCOMM_CONTIGUOUS:
343           PetscCall(PetscViewerASCIIPrintf(viewer, "petsc subcomm type = %s\n", PetscSubcommTypes[sred->subcommtype]));
344           break;
345         default:
346           SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "General subcomm type not supported by PCTelescope");
347         }
348         PetscCall(PetscViewerASCIIPopTab(viewer));
349       } else {
350         PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
351         subcomm = sred->subcomm;
352         if (!PCTelescope_isActiveRank(sred)) subcomm = PETSC_COMM_SELF;
353 
354         PetscCall(PetscViewerASCIIPushTab(viewer));
355         PetscCall(PetscViewerASCIIPrintf(viewer, "subcomm: using user provided sub-communicator\n"));
356         PetscCall(PetscViewerASCIIPopTab(viewer));
357       }
358 
359       PetscCall(PetscViewerGetSubViewer(viewer, subcomm, &subviewer));
360       if (PCTelescope_isActiveRank(sred)) {
361         PetscCall(PetscViewerASCIIPushTab(subviewer));
362 
363         if (dm && sred->ignore_dm) PetscCall(PetscViewerASCIIPrintf(subviewer, "ignoring DM\n"));
364         if (sred->ignore_kspcomputeoperators) PetscCall(PetscViewerASCIIPrintf(subviewer, "ignoring KSPComputeOperators\n"));
365         switch (sred->sr_type) {
366         case TELESCOPE_DEFAULT:
367           PetscCall(PetscViewerASCIIPrintf(subviewer, "setup type: default\n"));
368           break;
369         case TELESCOPE_DMDA:
370           PetscCall(PetscViewerASCIIPrintf(subviewer, "setup type: DMDA auto-repartitioning\n"));
371           PetscCall(DMView_DA_Short(subdm, subviewer));
372           break;
373         case TELESCOPE_DMPLEX:
374           PetscCall(PetscViewerASCIIPrintf(subviewer, "setup type: DMPLEX auto-repartitioning\n"));
375           break;
376         case TELESCOPE_COARSEDM:
377           PetscCall(PetscViewerASCIIPrintf(subviewer, "setup type: coarse DM\n"));
378           break;
379         }
380 
381         if (dm) {
382           PetscObject obj = (PetscObject)dm;
383           PetscCall(PetscViewerASCIIPrintf(subviewer, "Parent DM object:"));
384           PetscCall(PetscViewerASCIIUseTabs(subviewer, PETSC_FALSE));
385           if (obj->type_name) PetscCall(PetscViewerASCIIPrintf(subviewer, " type = %s;", obj->type_name));
386           if (obj->name) PetscCall(PetscViewerASCIIPrintf(subviewer, " name = %s;", obj->name));
387           if (obj->prefix) PetscCall(PetscViewerASCIIPrintf(subviewer, " prefix = %s", obj->prefix));
388           PetscCall(PetscViewerASCIIPrintf(subviewer, "\n"));
389           PetscCall(PetscViewerASCIIUseTabs(subviewer, PETSC_TRUE));
390         } else {
391           PetscCall(PetscViewerASCIIPrintf(subviewer, "Parent DM object: NULL\n"));
392         }
393         if (subdm) {
394           PetscObject obj = (PetscObject)subdm;
395           PetscCall(PetscViewerASCIIPrintf(subviewer, "Sub DM object:"));
396           PetscCall(PetscViewerASCIIUseTabs(subviewer, PETSC_FALSE));
397           if (obj->type_name) PetscCall(PetscViewerASCIIPrintf(subviewer, " type = %s;", obj->type_name));
398           if (obj->name) PetscCall(PetscViewerASCIIPrintf(subviewer, " name = %s;", obj->name));
399           if (obj->prefix) PetscCall(PetscViewerASCIIPrintf(subviewer, " prefix = %s", obj->prefix));
400           PetscCall(PetscViewerASCIIPrintf(subviewer, "\n"));
401           PetscCall(PetscViewerASCIIUseTabs(subviewer, PETSC_TRUE));
402         } else {
403           PetscCall(PetscViewerASCIIPrintf(subviewer, "Sub DM object: NULL\n"));
404         }
405 
406         PetscCall(KSPView(sred->ksp, subviewer));
407         PetscCall(PetscViewerASCIIPopTab(subviewer));
408       }
409       PetscCall(PetscViewerRestoreSubViewer(viewer, subcomm, &subviewer));
410     }
411   }
412   PetscFunctionReturn(PETSC_SUCCESS);
413 }
414 
415 static PetscErrorCode PCSetUp_Telescope(PC pc)
416 {
417   PC_Telescope    sred = (PC_Telescope)pc->data;
418   MPI_Comm        comm, subcomm = 0;
419   PCTelescopeType sr_type;
420 
421   PetscFunctionBegin;
422   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
423 
424   /* Determine type of setup/update */
425   if (!pc->setupcalled) {
426     PetscBool has_dm, same;
427     DM        dm;
428 
429     sr_type = TELESCOPE_DEFAULT;
430     has_dm  = PETSC_FALSE;
431     PetscCall(PCGetDM(pc, &dm));
432     if (dm) has_dm = PETSC_TRUE;
433     if (has_dm) {
434       /* check for dmda */
435       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &same));
436       if (same) {
437         PetscCall(PetscInfo(pc, "PCTelescope: found DMDA\n"));
438         sr_type = TELESCOPE_DMDA;
439       }
440       /* check for dmplex */
441       PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &same));
442       if (same) {
443         PetscCall(PetscInfo(pc, "PCTelescope: found DMPLEX\n"));
444         sr_type = TELESCOPE_DMPLEX;
445       }
446 
447       if (sred->use_coarse_dm) {
448         PetscCall(PetscInfo(pc, "PCTelescope: using coarse DM\n"));
449         sr_type = TELESCOPE_COARSEDM;
450       }
451 
452       if (sred->ignore_dm) {
453         PetscCall(PetscInfo(pc, "PCTelescope: ignoring DM\n"));
454         sr_type = TELESCOPE_DEFAULT;
455       }
456     }
457     sred->sr_type = sr_type;
458   } else {
459     sr_type = sred->sr_type;
460   }
461 
462   /* set function pointers for repartition setup, matrix creation/update, matrix (near) nullspace, and reset functionality */
463   switch (sr_type) {
464   case TELESCOPE_DEFAULT:
465     sred->pctelescope_setup_type              = PCTelescopeSetUp_default;
466     sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_default;
467     sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_default;
468     sred->pctelescope_reset_type              = NULL;
469     break;
470   case TELESCOPE_DMDA:
471     pc->ops->apply                            = PCApply_Telescope_dmda;
472     pc->ops->applyrichardson                  = PCApplyRichardson_Telescope_dmda;
473     sred->pctelescope_setup_type              = PCTelescopeSetUp_dmda;
474     sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_dmda;
475     sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_dmda;
476     sred->pctelescope_reset_type              = PCReset_Telescope_dmda;
477     break;
478   case TELESCOPE_DMPLEX:
479     SETERRQ(comm, PETSC_ERR_SUP, "Support for DMPLEX is currently not available");
480   case TELESCOPE_COARSEDM:
481     pc->ops->apply                            = PCApply_Telescope_CoarseDM;
482     pc->ops->applyrichardson                  = PCApplyRichardson_Telescope_CoarseDM;
483     sred->pctelescope_setup_type              = PCTelescopeSetUp_CoarseDM;
484     sred->pctelescope_matcreate_type          = NULL;
485     sred->pctelescope_matnullspacecreate_type = NULL; /* PCTelescopeMatNullSpaceCreate_CoarseDM; */
486     sred->pctelescope_reset_type              = PCReset_Telescope_CoarseDM;
487     break;
488   default:
489     SETERRQ(comm, PETSC_ERR_SUP, "Support only provided for: repartitioning an operator; repartitioning a DMDA; or using a coarse DM");
490   }
491 
492   /* subcomm definition */
493   if (!pc->setupcalled) {
494     if ((sr_type == TELESCOPE_DEFAULT) || (sr_type == TELESCOPE_DMDA)) {
495       if (!sred->psubcomm) {
496         PetscCall(PetscSubcommCreate(comm, &sred->psubcomm));
497         PetscCall(PetscSubcommSetNumber(sred->psubcomm, sred->redfactor));
498         PetscCall(PetscSubcommSetType(sred->psubcomm, sred->subcommtype));
499         sred->subcomm = PetscSubcommChild(sred->psubcomm);
500       }
501     } else { /* query PC for DM, check communicators */
502       DM          dm, dm_coarse_partition          = NULL;
503       MPI_Comm    comm_fine, comm_coarse_partition = MPI_COMM_NULL;
504       PetscMPIInt csize_fine = 0, csize_coarse_partition = 0, cs[2], csg[2], cnt = 0;
505       PetscBool   isvalidsubcomm;
506 
507       PetscCall(PCGetDM(pc, &dm));
508       comm_fine = PetscObjectComm((PetscObject)dm);
509       PetscCall(DMGetCoarseDM(dm, &dm_coarse_partition));
510       if (dm_coarse_partition) cnt = 1;
511       PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_INT, MPI_SUM, comm_fine));
512       PetscCheck(cnt != 0, comm_fine, PETSC_ERR_SUP, "Zero instances of a coarse DM were found");
513 
514       PetscCallMPI(MPI_Comm_size(comm_fine, &csize_fine));
515       if (dm_coarse_partition) {
516         comm_coarse_partition = PetscObjectComm((PetscObject)dm_coarse_partition);
517         PetscCallMPI(MPI_Comm_size(comm_coarse_partition, &csize_coarse_partition));
518       }
519 
520       cs[0] = csize_fine;
521       cs[1] = csize_coarse_partition;
522       PetscCallMPI(MPI_Allreduce(cs, csg, 2, MPI_INT, MPI_MAX, comm_fine));
523       PetscCheck(csg[0] != csg[1], comm_fine, PETSC_ERR_SUP, "Coarse DM uses the same size communicator as the parent DM attached to the PC");
524 
525       PetscCall(PCTelescopeTestValidSubcomm(comm_fine, comm_coarse_partition, &isvalidsubcomm));
526       PetscCheck(isvalidsubcomm, comm_fine, PETSC_ERR_SUP, "Coarse DM communicator is not a sub-communicator of parentDM->comm");
527       sred->subcomm = comm_coarse_partition;
528     }
529   }
530   subcomm = sred->subcomm;
531 
532   /* internal KSP */
533   if (!pc->setupcalled) {
534     const char *prefix;
535 
536     if (PCTelescope_isActiveRank(sred)) {
537       PetscCall(KSPCreate(subcomm, &sred->ksp));
538       PetscCall(KSPSetErrorIfNotConverged(sred->ksp, pc->erroriffailure));
539       PetscCall(PetscObjectIncrementTabLevel((PetscObject)sred->ksp, (PetscObject)pc, 1));
540       PetscCall(KSPSetType(sred->ksp, KSPPREONLY));
541       PetscCall(PCGetOptionsPrefix(pc, &prefix));
542       PetscCall(KSPSetOptionsPrefix(sred->ksp, prefix));
543       PetscCall(KSPAppendOptionsPrefix(sred->ksp, "telescope_"));
544     }
545   }
546 
547   /* setup */
548   if (!pc->setupcalled && sred->pctelescope_setup_type) PetscCall(sred->pctelescope_setup_type(pc, sred));
549   /* update */
550   if (!pc->setupcalled) {
551     if (sred->pctelescope_matcreate_type) PetscCall(sred->pctelescope_matcreate_type(pc, sred, MAT_INITIAL_MATRIX, &sred->Bred));
552     if (sred->pctelescope_matnullspacecreate_type) PetscCall(sred->pctelescope_matnullspacecreate_type(pc, sred, sred->Bred));
553   } else {
554     if (sred->pctelescope_matcreate_type) PetscCall(sred->pctelescope_matcreate_type(pc, sred, MAT_REUSE_MATRIX, &sred->Bred));
555   }
556 
557   /* common - no construction */
558   if (PCTelescope_isActiveRank(sred)) {
559     PetscCall(KSPSetOperators(sred->ksp, sred->Bred, sred->Bred));
560     if (pc->setfromoptionscalled && !pc->setupcalled) PetscCall(KSPSetFromOptions(sred->ksp));
561   }
562   PetscFunctionReturn(PETSC_SUCCESS);
563 }
564 
565 static PetscErrorCode PCApply_Telescope(PC pc, Vec x, Vec y)
566 {
567   PC_Telescope       sred = (PC_Telescope)pc->data;
568   Vec                xtmp, xred, yred;
569   PetscInt           i, st, ed;
570   VecScatter         scatter;
571   PetscScalar       *array;
572   const PetscScalar *x_array;
573 
574   PetscFunctionBegin;
575   PetscCall(PetscCitationsRegister(citation, &cited));
576 
577   xtmp    = sred->xtmp;
578   scatter = sred->scatter;
579   xred    = sred->xred;
580   yred    = sred->yred;
581 
582   /* pull in vector x->xtmp */
583   PetscCall(VecScatterBegin(scatter, x, xtmp, INSERT_VALUES, SCATTER_FORWARD));
584   PetscCall(VecScatterEnd(scatter, x, xtmp, INSERT_VALUES, SCATTER_FORWARD));
585 
586   /* copy vector entries into xred */
587   PetscCall(VecGetArrayRead(xtmp, &x_array));
588   if (xred) {
589     PetscScalar *LA_xred;
590     PetscCall(VecGetOwnershipRange(xred, &st, &ed));
591     PetscCall(VecGetArray(xred, &LA_xred));
592     for (i = 0; i < ed - st; i++) LA_xred[i] = x_array[i];
593     PetscCall(VecRestoreArray(xred, &LA_xred));
594   }
595   PetscCall(VecRestoreArrayRead(xtmp, &x_array));
596   /* solve */
597   if (PCTelescope_isActiveRank(sred)) {
598     PetscCall(KSPSolve(sred->ksp, xred, yred));
599     PetscCall(KSPCheckSolve(sred->ksp, pc, yred));
600   }
601   /* return vector */
602   PetscCall(VecGetArray(xtmp, &array));
603   if (yred) {
604     const PetscScalar *LA_yred;
605     PetscCall(VecGetOwnershipRange(yred, &st, &ed));
606     PetscCall(VecGetArrayRead(yred, &LA_yred));
607     for (i = 0; i < ed - st; i++) array[i] = LA_yred[i];
608     PetscCall(VecRestoreArrayRead(yred, &LA_yred));
609   }
610   PetscCall(VecRestoreArray(xtmp, &array));
611   PetscCall(VecScatterBegin(scatter, xtmp, y, INSERT_VALUES, SCATTER_REVERSE));
612   PetscCall(VecScatterEnd(scatter, xtmp, y, INSERT_VALUES, SCATTER_REVERSE));
613   PetscFunctionReturn(PETSC_SUCCESS);
614 }
615 
616 static PetscErrorCode PCApplyRichardson_Telescope(PC pc, Vec x, Vec y, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt its, PetscBool zeroguess, PetscInt *outits, PCRichardsonConvergedReason *reason)
617 {
618   PC_Telescope       sred = (PC_Telescope)pc->data;
619   Vec                xtmp, yred;
620   PetscInt           i, st, ed;
621   VecScatter         scatter;
622   const PetscScalar *x_array;
623   PetscBool          default_init_guess_value;
624 
625   PetscFunctionBegin;
626   xtmp    = sred->xtmp;
627   scatter = sred->scatter;
628   yred    = sred->yred;
629 
630   PetscCheck(its <= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCApplyRichardson_Telescope only supports max_it = 1");
631   *reason = (PCRichardsonConvergedReason)0;
632 
633   if (!zeroguess) {
634     PetscCall(PetscInfo(pc, "PCTelescope: Scattering y for non-zero initial guess\n"));
635     /* pull in vector y->xtmp */
636     PetscCall(VecScatterBegin(scatter, y, xtmp, INSERT_VALUES, SCATTER_FORWARD));
637     PetscCall(VecScatterEnd(scatter, y, xtmp, INSERT_VALUES, SCATTER_FORWARD));
638 
639     /* copy vector entries into xred */
640     PetscCall(VecGetArrayRead(xtmp, &x_array));
641     if (yred) {
642       PetscScalar *LA_yred;
643       PetscCall(VecGetOwnershipRange(yred, &st, &ed));
644       PetscCall(VecGetArray(yred, &LA_yred));
645       for (i = 0; i < ed - st; i++) LA_yred[i] = x_array[i];
646       PetscCall(VecRestoreArray(yred, &LA_yred));
647     }
648     PetscCall(VecRestoreArrayRead(xtmp, &x_array));
649   }
650 
651   if (PCTelescope_isActiveRank(sred)) {
652     PetscCall(KSPGetInitialGuessNonzero(sred->ksp, &default_init_guess_value));
653     if (!zeroguess) PetscCall(KSPSetInitialGuessNonzero(sred->ksp, PETSC_TRUE));
654   }
655 
656   PetscCall(PCApply_Telescope(pc, x, y));
657 
658   if (PCTelescope_isActiveRank(sred)) PetscCall(KSPSetInitialGuessNonzero(sred->ksp, default_init_guess_value));
659 
660   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
661   *outits = 1;
662   PetscFunctionReturn(PETSC_SUCCESS);
663 }
664 
665 static PetscErrorCode PCReset_Telescope(PC pc)
666 {
667   PC_Telescope sred = (PC_Telescope)pc->data;
668 
669   PetscFunctionBegin;
670   PetscCall(ISDestroy(&sred->isin));
671   PetscCall(VecScatterDestroy(&sred->scatter));
672   PetscCall(VecDestroy(&sred->xred));
673   PetscCall(VecDestroy(&sred->yred));
674   PetscCall(VecDestroy(&sred->xtmp));
675   PetscCall(MatDestroy(&sred->Bred));
676   PetscCall(KSPReset(sred->ksp));
677   if (sred->pctelescope_reset_type) PetscCall(sred->pctelescope_reset_type(pc));
678   PetscFunctionReturn(PETSC_SUCCESS);
679 }
680 
681 static PetscErrorCode PCDestroy_Telescope(PC pc)
682 {
683   PC_Telescope sred = (PC_Telescope)pc->data;
684 
685   PetscFunctionBegin;
686   PetscCall(PCReset_Telescope(pc));
687   PetscCall(KSPDestroy(&sred->ksp));
688   PetscCall(PetscSubcommDestroy(&sred->psubcomm));
689   PetscCall(PetscFree(sred->dm_ctx));
690   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetKSP_C", NULL));
691   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetSubcommType_C", NULL));
692   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetSubcommType_C", NULL));
693   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetReductionFactor_C", NULL));
694   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetReductionFactor_C", NULL));
695   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreDM_C", NULL));
696   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreDM_C", NULL));
697   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", NULL));
698   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", NULL));
699   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetDM_C", NULL));
700   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetUseCoarseDM_C", NULL));
701   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetUseCoarseDM_C", NULL));
702   PetscCall(PetscFree(pc->data));
703   PetscFunctionReturn(PETSC_SUCCESS);
704 }
705 
706 static PetscErrorCode PCSetFromOptions_Telescope(PC pc, PetscOptionItems *PetscOptionsObject)
707 {
708   PC_Telescope     sred = (PC_Telescope)pc->data;
709   MPI_Comm         comm;
710   PetscMPIInt      size;
711   PetscBool        flg;
712   PetscSubcommType subcommtype;
713 
714   PetscFunctionBegin;
715   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
716   PetscCallMPI(MPI_Comm_size(comm, &size));
717   PetscOptionsHeadBegin(PetscOptionsObject, "Telescope options");
718   PetscCall(PetscOptionsEnum("-pc_telescope_subcomm_type", "Subcomm type (interlaced or contiguous)", "PCTelescopeSetSubcommType", PetscSubcommTypes, (PetscEnum)sred->subcommtype, (PetscEnum *)&subcommtype, &flg));
719   if (flg) PetscCall(PCTelescopeSetSubcommType(pc, subcommtype));
720   PetscCall(PetscOptionsInt("-pc_telescope_reduction_factor", "Factor to reduce comm size by", "PCTelescopeSetReductionFactor", sred->redfactor, &sred->redfactor, NULL));
721   PetscCheck(sred->redfactor <= size, comm, PETSC_ERR_ARG_WRONG, "-pc_telescope_reduction_factor <= comm size");
722   PetscCall(PetscOptionsBool("-pc_telescope_ignore_dm", "Ignore any DM attached to the PC", "PCTelescopeSetIgnoreDM", sred->ignore_dm, &sred->ignore_dm, NULL));
723   PetscCall(PetscOptionsBool("-pc_telescope_ignore_kspcomputeoperators", "Ignore method used to compute A", "PCTelescopeSetIgnoreKSPComputeOperators", sred->ignore_kspcomputeoperators, &sred->ignore_kspcomputeoperators, NULL));
724   PetscCall(PetscOptionsBool("-pc_telescope_use_coarse_dm", "Define sub-communicator from the coarse DM", "PCTelescopeSetUseCoarseDM", sred->use_coarse_dm, &sred->use_coarse_dm, NULL));
725   PetscOptionsHeadEnd();
726   PetscFunctionReturn(PETSC_SUCCESS);
727 }
728 
729 /* PC simplementation specific API's */
730 
731 static PetscErrorCode PCTelescopeGetKSP_Telescope(PC pc, KSP *ksp)
732 {
733   PC_Telescope red = (PC_Telescope)pc->data;
734   PetscFunctionBegin;
735   if (ksp) *ksp = red->ksp;
736   PetscFunctionReturn(PETSC_SUCCESS);
737 }
738 
739 static PetscErrorCode PCTelescopeGetSubcommType_Telescope(PC pc, PetscSubcommType *subcommtype)
740 {
741   PC_Telescope red = (PC_Telescope)pc->data;
742   PetscFunctionBegin;
743   if (subcommtype) *subcommtype = red->subcommtype;
744   PetscFunctionReturn(PETSC_SUCCESS);
745 }
746 
747 static PetscErrorCode PCTelescopeSetSubcommType_Telescope(PC pc, PetscSubcommType subcommtype)
748 {
749   PC_Telescope red = (PC_Telescope)pc->data;
750 
751   PetscFunctionBegin;
752   PetscCheck(!pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "You cannot change the subcommunicator type for PCTelescope after it has been set up.");
753   red->subcommtype = subcommtype;
754   PetscFunctionReturn(PETSC_SUCCESS);
755 }
756 
757 static PetscErrorCode PCTelescopeGetReductionFactor_Telescope(PC pc, PetscInt *fact)
758 {
759   PC_Telescope red = (PC_Telescope)pc->data;
760   PetscFunctionBegin;
761   if (fact) *fact = red->redfactor;
762   PetscFunctionReturn(PETSC_SUCCESS);
763 }
764 
765 static PetscErrorCode PCTelescopeSetReductionFactor_Telescope(PC pc, PetscInt fact)
766 {
767   PC_Telescope red = (PC_Telescope)pc->data;
768   PetscMPIInt  size;
769 
770   PetscFunctionBegin;
771   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
772   PetscCheck(fact > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Reduction factor of telescoping PC %" PetscInt_FMT " must be positive", fact);
773   PetscCheck(fact <= size, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Reduction factor of telescoping PC %" PetscInt_FMT " must be <= comm.size", fact);
774   red->redfactor = fact;
775   PetscFunctionReturn(PETSC_SUCCESS);
776 }
777 
778 static PetscErrorCode PCTelescopeGetIgnoreDM_Telescope(PC pc, PetscBool *v)
779 {
780   PC_Telescope red = (PC_Telescope)pc->data;
781   PetscFunctionBegin;
782   if (v) *v = red->ignore_dm;
783   PetscFunctionReturn(PETSC_SUCCESS);
784 }
785 
786 static PetscErrorCode PCTelescopeSetIgnoreDM_Telescope(PC pc, PetscBool v)
787 {
788   PC_Telescope red = (PC_Telescope)pc->data;
789   PetscFunctionBegin;
790   red->ignore_dm = v;
791   PetscFunctionReturn(PETSC_SUCCESS);
792 }
793 
794 static PetscErrorCode PCTelescopeGetUseCoarseDM_Telescope(PC pc, PetscBool *v)
795 {
796   PC_Telescope red = (PC_Telescope)pc->data;
797   PetscFunctionBegin;
798   if (v) *v = red->use_coarse_dm;
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 static PetscErrorCode PCTelescopeSetUseCoarseDM_Telescope(PC pc, PetscBool v)
803 {
804   PC_Telescope red = (PC_Telescope)pc->data;
805   PetscFunctionBegin;
806   red->use_coarse_dm = v;
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 static PetscErrorCode PCTelescopeGetIgnoreKSPComputeOperators_Telescope(PC pc, PetscBool *v)
811 {
812   PC_Telescope red = (PC_Telescope)pc->data;
813   PetscFunctionBegin;
814   if (v) *v = red->ignore_kspcomputeoperators;
815   PetscFunctionReturn(PETSC_SUCCESS);
816 }
817 
818 static PetscErrorCode PCTelescopeSetIgnoreKSPComputeOperators_Telescope(PC pc, PetscBool v)
819 {
820   PC_Telescope red = (PC_Telescope)pc->data;
821   PetscFunctionBegin;
822   red->ignore_kspcomputeoperators = v;
823   PetscFunctionReturn(PETSC_SUCCESS);
824 }
825 
826 static PetscErrorCode PCTelescopeGetDM_Telescope(PC pc, DM *dm)
827 {
828   PC_Telescope red = (PC_Telescope)pc->data;
829   PetscFunctionBegin;
830   *dm = private_PCTelescopeGetSubDM(red);
831   PetscFunctionReturn(PETSC_SUCCESS);
832 }
833 
834 /*@
835  PCTelescopeGetKSP - Gets the `KSP` created by the telescoping `PC`.
836 
837  Not Collective
838 
839  Input Parameter:
840 .  pc - the preconditioner context
841 
842  Output Parameter:
843 .  subksp - the `KSP` defined the smaller set of processes
844 
845  Level: advanced
846 
847 .seealso: `PCTELESCOPE`
848 @*/
849 PetscErrorCode PCTelescopeGetKSP(PC pc, KSP *subksp)
850 {
851   PetscFunctionBegin;
852   PetscUseMethod(pc, "PCTelescopeGetKSP_C", (PC, KSP *), (pc, subksp));
853   PetscFunctionReturn(PETSC_SUCCESS);
854 }
855 
856 /*@
857  PCTelescopeGetReductionFactor - Gets the factor by which the original number of MPI ranks  has been reduced by.
858 
859  Not Collective
860 
861  Input Parameter:
862 .  pc - the preconditioner context
863 
864  Output Parameter:
865 .  fact - the reduction factor
866 
867  Level: advanced
868 
869 .seealso: `PCTELESCOPE`, `PCTelescopeSetReductionFactor()`
870 @*/
871 PetscErrorCode PCTelescopeGetReductionFactor(PC pc, PetscInt *fact)
872 {
873   PetscFunctionBegin;
874   PetscUseMethod(pc, "PCTelescopeGetReductionFactor_C", (PC, PetscInt *), (pc, fact));
875   PetscFunctionReturn(PETSC_SUCCESS);
876 }
877 
878 /*@
879  PCTelescopeSetReductionFactor - Sets the factor by which the original number of MPI ranks will been reduced by.
880 
881  Not Collective
882 
883  Input Parameter:
884 .  pc - the preconditioner context
885 
886  Output Parameter:
887 .  fact - the reduction factor
888 
889  Level: advanced
890 
891 .seealso: `PCTELESCOPE`, `PCTelescopeGetReductionFactor()`
892 @*/
893 PetscErrorCode PCTelescopeSetReductionFactor(PC pc, PetscInt fact)
894 {
895   PetscFunctionBegin;
896   PetscTryMethod(pc, "PCTelescopeSetReductionFactor_C", (PC, PetscInt), (pc, fact));
897   PetscFunctionReturn(PETSC_SUCCESS);
898 }
899 
900 /*@
901  PCTelescopeGetIgnoreDM - Get the flag indicating if any `DM` attached to the `PC` will be used.
902 
903  Not Collective
904 
905  Input Parameter:
906 .  pc - the preconditioner context
907 
908  Output Parameter:
909 .  v - the flag
910 
911  Level: advanced
912 
913 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`
914 @*/
915 PetscErrorCode PCTelescopeGetIgnoreDM(PC pc, PetscBool *v)
916 {
917   PetscFunctionBegin;
918   PetscUseMethod(pc, "PCTelescopeGetIgnoreDM_C", (PC, PetscBool *), (pc, v));
919   PetscFunctionReturn(PETSC_SUCCESS);
920 }
921 
922 /*@
923  PCTelescopeSetIgnoreDM - Set a flag to ignore any DM attached to the PC.
924 
925  Not Collective
926 
927  Input Parameter:
928 .  pc - the preconditioner context
929 
930  Output Parameter:
931 .  v - Use PETSC_TRUE to ignore any DM
932 
933  Level: advanced
934 
935 .seealso: `PCTELESCOPE`, `PCTelescopeGetIgnoreDM()`
936 @*/
937 PetscErrorCode PCTelescopeSetIgnoreDM(PC pc, PetscBool v)
938 {
939   PetscFunctionBegin;
940   PetscTryMethod(pc, "PCTelescopeSetIgnoreDM_C", (PC, PetscBool), (pc, v));
941   PetscFunctionReturn(PETSC_SUCCESS);
942 }
943 
944 /*@
945  PCTelescopeGetUseCoarseDM - Get the flag indicating if the coarse `DM` attached to `DM` associated with the `PC` will be used.
946 
947  Not Collective
948 
949  Input Parameter:
950 .  pc - the preconditioner context
951 
952  Output Parameter:
953 .  v - the flag
954 
955  Level: advanced
956 
957 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`
958 @*/
959 PetscErrorCode PCTelescopeGetUseCoarseDM(PC pc, PetscBool *v)
960 {
961   PetscFunctionBegin;
962   PetscUseMethod(pc, "PCTelescopeGetUseCoarseDM_C", (PC, PetscBool *), (pc, v));
963   PetscFunctionReturn(PETSC_SUCCESS);
964 }
965 
966 /*@
967  PCTelescopeSetUseCoarseDM - Set a flag to query the `DM` attached to the `PC` if it also has a coarse `DM`
968 
969  Not Collective
970 
971  Input Parameter:
972 .  pc - the preconditioner context
973 
974  Output Parameter:
975 .  v - Use `PETSC_FALSE` to ignore any coarse `DM`
976 
977  Notes:
978  When you have specified to use a coarse `DM`, the communicator used to create the sub-KSP within `PCTELESCOPE`
979  will be that of the coarse `DM`. Hence the flags -pc_telescope_reduction_factor and
980  -pc_telescope_subcomm_type will no longer have any meaning.
981  It is required that the communicator associated with the parent (fine) and the coarse `DM` are of different sizes.
982  An error will occur of the size of the communicator associated with the coarse `DM`
983  is the same as that of the parent `DM`.
984  Furthermore, it is required that the communicator on the coarse DM is a sub-communicator of the parent.
985  This will be checked at the time the preconditioner is setup and an error will occur if
986  the coarse DM does not define a sub-communicator of that used by the parent DM.
987 
988  The particular Telescope setup invoked when using a coarse DM is agnostic with respect to the type of
989  the `DM` used (e.g. it supports `DMSHELL`, `DMPLEX`, etc).
990 
991  Support is currently only provided for the case when you are using `KSPSetComputeOperators()`
992 
993  The user is required to compose a function with the parent DM to facilitate the transfer of fields (`Vec`) between the different decompositions defined by the fine and coarse `DM`s.
994  In the user code, this is achieved via
995 .vb
996    {
997      DM dm_fine;
998      PetscObjectCompose((PetscObject)dm_fine,"PCTelescopeFieldScatter",your_field_scatter_method);
999    }
1000 .ve
1001  The signature of the user provided field scatter method is
1002 .vb
1003    PetscErrorCode your_field_scatter_method(DM dm_fine,Vec x_fine,ScatterMode mode,DM dm_coarse,Vec x_coarse);
1004 .ve
1005  The user must provide support for both mode = `SCATTER_FORWARD` and mode = `SCATTER_REVERSE`.
1006  `SCATTER_FORWARD` implies the direction of transfer is from the parent (fine) `DM` to the coarse `DM`.
1007 
1008  Optionally, the user may also compose a function with the parent DM to facilitate the transfer
1009  of state variables between the fine and coarse `DM`s.
1010  In the context of a finite element discretization, an example state variable might be
1011  values associated with quadrature points within each element.
1012  A user provided state scatter method is composed via
1013 .vb
1014    {
1015      DM dm_fine;
1016      PetscObjectCompose((PetscObject)dm_fine,"PCTelescopeStateScatter",your_state_scatter_method);
1017    }
1018 .ve
1019  The signature of the user provided state scatter method is
1020 .vb
1021    PetscErrorCode your_state_scatter_method(DM dm_fine,ScatterMode mode,DM dm_coarse);
1022 .ve
1023  `SCATTER_FORWARD` implies the direction of transfer is from the fine `DM` to the coarse `DM`.
1024  The user is only required to support mode = `SCATTER_FORWARD`.
1025  No assumption is made about the data type of the state variables.
1026  These must be managed by the user and must be accessible from the `DM`.
1027 
1028  Care must be taken in defining the user context passed to `KSPSetComputeOperators()` which is to be
1029  associated with the sub-`KSP` residing within `PCTELESCOPE`.
1030  In general, `PCTELESCOPE` assumes that the context on the fine and coarse `DM` used with
1031  `KSPSetComputeOperators()` should be "similar" in type or origin.
1032  Specifically the following rules are used to infer what context on the sub-`KSP` should be.
1033 
1034  First the contexts from the `KSP` and the fine and coarse `DM`s are retrieved.
1035  Note that the special case of a `DMSHELL` context is queried.
1036 
1037 .vb
1038    DMKSPGetComputeOperators(dm_fine,&dmfine_kspfunc,&dmfine_kspctx);
1039    DMGetApplicationContext(dm_fine,&dmfine_appctx);
1040    DMShellGetContext(dm_fine,&dmfine_shellctx);
1041 
1042    DMGetApplicationContext(dm_coarse,&dmcoarse_appctx);
1043    DMShellGetContext(dm_coarse,&dmcoarse_shellctx);
1044 .ve
1045 
1046  The following rules are then enforced:
1047 
1048  1. If dmfine_kspctx = NULL, then we provide a NULL pointer as the context for the sub-KSP:
1049  `KSPSetComputeOperators`(sub_ksp,dmfine_kspfunc,NULL);
1050 
1051  2. If dmfine_kspctx != NULL and dmfine_kspctx == dmfine_appctx,
1052  check that dmcoarse_appctx is also non-NULL. If this is true, then:
1053  `KSPSetComputeOperators`(sub_ksp,dmfine_kspfunc,dmcoarse_appctx);
1054 
1055  3. If dmfine_kspctx != NULL and dmfine_kspctx == dmfine_shellctx,
1056  check that dmcoarse_shellctx is also non-NULL. If this is true, then:
1057  `KSPSetComputeOperators`(sub_ksp,dmfine_kspfunc,dmcoarse_shellctx);
1058 
1059  If neither of the above three tests passed, then `PCTELESCOPE` cannot safely determine what
1060  context should be provided to `KSPSetComputeOperators()` for use with the sub-`KSP`.
1061  In this case, an additional mechanism is provided via a composed function which will return
1062  the actual context to be used. To use this feature you must compose the "getter" function
1063  with the coarse `DM`, e.g.
1064 .vb
1065    {
1066      DM dm_coarse;
1067      PetscObjectCompose((PetscObject)dm_coarse,"PCTelescopeGetCoarseDMKSPContext",your_coarse_context_getter);
1068    }
1069 .ve
1070  The signature of the user provided method is
1071 .vb
1072    PetscErrorCode your_coarse_context_getter(DM dm_coarse,void **your_kspcontext);
1073 .ve
1074 
1075  Level: advanced
1076 
1077 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`
1078 @*/
1079 PetscErrorCode PCTelescopeSetUseCoarseDM(PC pc, PetscBool v)
1080 {
1081   PetscFunctionBegin;
1082   PetscTryMethod(pc, "PCTelescopeSetUseCoarseDM_C", (PC, PetscBool), (pc, v));
1083   PetscFunctionReturn(PETSC_SUCCESS);
1084 }
1085 
1086 /*@
1087  PCTelescopeGetIgnoreKSPComputeOperators - Get the flag indicating if `KSPComputeOperators()` will be used.
1088 
1089  Not Collective
1090 
1091  Input Parameter:
1092 .  pc - the preconditioner context
1093 
1094  Output Parameter:
1095 .  v - the flag
1096 
1097  Level: advanced
1098 
1099 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeSetIgnoreKSPComputeOperators()`
1100 @*/
1101 PetscErrorCode PCTelescopeGetIgnoreKSPComputeOperators(PC pc, PetscBool *v)
1102 {
1103   PetscFunctionBegin;
1104   PetscUseMethod(pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", (PC, PetscBool *), (pc, v));
1105   PetscFunctionReturn(PETSC_SUCCESS);
1106 }
1107 
1108 /*@
1109  PCTelescopeSetIgnoreKSPComputeOperators - Set a flag to ignore `KSPComputeOperators()`.
1110 
1111  Not Collective
1112 
1113  Input Parameter:
1114 .  pc - the preconditioner context
1115 
1116  Output Parameter:
1117 .  v - Use `PETSC_TRUE` to ignore the method (if defined) set via `KSPSetComputeOperators()` on pc
1118 
1119  Level: advanced
1120 
1121 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeGetIgnoreKSPComputeOperators()`
1122 @*/
1123 PetscErrorCode PCTelescopeSetIgnoreKSPComputeOperators(PC pc, PetscBool v)
1124 {
1125   PetscFunctionBegin;
1126   PetscTryMethod(pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", (PC, PetscBool), (pc, v));
1127   PetscFunctionReturn(PETSC_SUCCESS);
1128 }
1129 
1130 /*@
1131  PCTelescopeGetDM - Get the re-partitioned `DM` attached to the sub-`KSP`.
1132 
1133  Not Collective
1134 
1135  Input Parameter:
1136 .  pc - the preconditioner context
1137 
1138  Output Parameter:
1139 .  subdm - The re-partitioned DM
1140 
1141  Level: advanced
1142 
1143 .seealso: `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeGetIgnoreKSPComputeOperators()`
1144 @*/
1145 PetscErrorCode PCTelescopeGetDM(PC pc, DM *subdm)
1146 {
1147   PetscFunctionBegin;
1148   PetscUseMethod(pc, "PCTelescopeGetDM_C", (PC, DM *), (pc, subdm));
1149   PetscFunctionReturn(PETSC_SUCCESS);
1150 }
1151 
1152 /*@
1153  PCTelescopeSetSubcommType - set subcommunicator type (interlaced or contiguous)
1154 
1155  Logically Collective
1156 
1157  Input Parameters:
1158 +  pc - the preconditioner context
1159 -  subcommtype - the subcommunicator type (see `PetscSubcommType`)
1160 
1161  Level: advanced
1162 
1163 .seealso: `PetscSubcommType`, `PetscSubcomm`, `PCTELESCOPE`
1164 @*/
1165 PetscErrorCode PCTelescopeSetSubcommType(PC pc, PetscSubcommType subcommtype)
1166 {
1167   PetscFunctionBegin;
1168   PetscTryMethod(pc, "PCTelescopeSetSubcommType_C", (PC, PetscSubcommType), (pc, subcommtype));
1169   PetscFunctionReturn(PETSC_SUCCESS);
1170 }
1171 
1172 /*@
1173  PCTelescopeGetSubcommType - Get the subcommunicator type (interlaced or contiguous)
1174 
1175  Not Collective
1176 
1177  Input Parameter:
1178 .  pc - the preconditioner context
1179 
1180  Output Parameter:
1181 .  subcommtype - the subcommunicator type (see `PetscSubcommType`)
1182 
1183  Level: advanced
1184 
1185 .seealso: `PetscSubcomm`, `PetscSubcommType`, `PCTELESCOPE`
1186 @*/
1187 PetscErrorCode PCTelescopeGetSubcommType(PC pc, PetscSubcommType *subcommtype)
1188 {
1189   PetscFunctionBegin;
1190   PetscUseMethod(pc, "PCTelescopeGetSubcommType_C", (PC, PetscSubcommType *), (pc, subcommtype));
1191   PetscFunctionReturn(PETSC_SUCCESS);
1192 }
1193 
1194 /*MC
1195    PCTELESCOPE - Runs a `KSP` solver on a sub-communicator. MPI ranks not in the sub-communicator are idle during the solve.
1196 
1197    Options Database Keys:
1198 +  -pc_telescope_reduction_factor <r> - factor to reduce the communicator size by. e.g. with 64 MPI ranks and r=4, the new sub-communicator will have 64/4 = 16 ranks.
1199 .  -pc_telescope_ignore_dm  - flag to indicate whether an attached DM should be ignored.
1200 .  -pc_telescope_subcomm_type <interlaced,contiguous> - defines the selection of MPI ranks on the sub-communicator. see PetscSubcomm for more information.
1201 .  -pc_telescope_ignore_kspcomputeoperators - flag to indicate whether `KSPSetComputeOperators()` should be used on the sub-KSP.
1202 -  -pc_telescope_use_coarse_dm - flag to indicate whether the coarse `DM` should be used to define the sub-communicator.
1203 
1204    Level: advanced
1205 
1206    Notes:
1207    Assuming that the parent preconditioner `PC` is defined on a communicator c, this implementation
1208    creates a child sub-communicator (c') containing fewer MPI ranks than the original parent preconditioner `PC`.
1209    The preconditioner is deemed telescopic as it only calls `KSPSolve()` on a single
1210    sub-communicator, in contrast with `PCREDUNDANT` which calls `KSPSolve()` on N sub-communicators.
1211    This means there will be MPI ranks which will be idle during the application of this preconditioner.
1212    Additionally, in comparison with `PCREDUNDANT`, `PCTELESCOPE` can utilize an attached `DM`.
1213 
1214    The default type of the sub `KSP` (the `KSP` defined on c') is `KSPPREONLY`.
1215 
1216    There are three setup mechanisms for `PCTELESCOPE`. Features support by each type are described below.
1217    In the following, we will refer to the operators B and B', these are the Bmat provided to the `KSP` on the
1218    communicators c and c' respectively.
1219 
1220    [1] Default setup
1221    The sub-communicator c' is created via `PetscSubcommCreate()`.
1222    Explicitly defined nullspace and near nullspace vectors will be propagated from B to B'.
1223    Currently there is no support define nullspaces via a user supplied method (e.g. as passed to `MatNullSpaceSetFunction()`).
1224    No support is provided for `KSPSetComputeOperators()`.
1225    Currently there is no support for the flag -pc_use_amat.
1226 
1227    [2] `DM` aware setup
1228    If a `DM` is attached to the `PC`, it is re-partitioned on the sub-communicator c'.
1229    c' is created via `PetscSubcommCreate()`.
1230    Both the Bmat operator and the right hand side vector are permuted into the new DOF ordering defined by the re-partitioned `DM`.
1231    Currently only support for re-partitioning a `DMDA` is provided.
1232    Any explicitly defined nullspace or near nullspace vectors attached to the original Bmat operator (B) are extracted, re-partitioned and set on the re-partitioned Bmat operator (B').
1233    Currently there is no support define nullspaces via a user supplied method (e.g. as passed to `MatNullSpaceSetFunction()`).
1234    Support is provided for `KSPSetComputeOperators()`. The user provided function and context is propagated to the sub `KSP`.
1235    This is fragile since the user must ensure that their user context is valid for use on c'.
1236    Currently there is no support for the flag -pc_use_amat.
1237 
1238    [3] Coarse `DM` setup
1239    If a `DM` (dmfine) is attached to the `PC`, dmfine is queried for a "coarse" `DM` (call this dmcoarse) via `DMGetCoarseDM()`.
1240    `PCTELESCOPE` will interpret the coarse `DM` as being defined on a sub-communicator of c.
1241    The communicator associated with dmcoarse will define the c' to be used within `PCTELESCOPE`.
1242    `PCTELESCOPE` will check that c' is in fact a sub-communicator of c. If it is not, an error will be reported.
1243    The intention of this setup type is that `PCTELESCOPE` will use an existing (e.g. user defined) communicator hierarchy, say as would be
1244    available with using multi-grid on unstructured meshes.
1245    This setup will not use the command line options -pc_telescope_reduction_factor or -pc_telescope_subcomm_type.
1246    Any explicitly defined nullspace or near nullspace vectors attached to the original Bmat operator (B) are extracted, scattered into the correct ordering consistent with dmcoarse and set on B'.
1247    Currently there is no support define nullspaces via a user supplied method (e.g. as passed to `MatNullSpaceSetFunction()`).
1248    There is no general method to permute field orderings, hence only `KSPSetComputeOperators()` is supported.
1249    The user must use `PetscObjectComposeFunction()` with dmfine to define the method to scatter fields from dmfine to dmcoarse.
1250    Propagation of the user context for `KSPSetComputeOperators()` on the sub `KSP` is attempted by querying the `DM` contexts associated with dmfine and dmcoarse. Alternatively, the user may use `PetscObjectComposeFunction()` with dmcoarse to define a method which will return the appropriate user context for `KSPSetComputeOperators()`.
1251    Currently there is no support for the flag -pc_use_amat.
1252    This setup can be invoked by the option -pc_telescope_use_coarse_dm or by calling `PCTelescopeSetUseCoarseDM`(pc,`PETSC_TRUE`);
1253    Further information about the user-provided methods required by this setup type are described here `PCTelescopeSetUseCoarseDM()`.
1254 
1255    Developer Notes:
1256    During `PCSetup()`, the B operator is scattered onto c'.
1257    Within `PCApply()`, the RHS vector (x) is scattered into a redundant vector, xred (defined on c').
1258    Then, `KSPSolve()` is executed on the c' communicator.
1259 
1260    The communicator used within the telescoping preconditioner is defined by a `PetscSubcomm` using the INTERLACED
1261    creation routine by default (this can be changed with -pc_telescope_subcomm_type). We run the sub `KSP` on only the ranks within the communicator which have a color equal to zero.
1262 
1263    The telescoping preconditioner is aware of nullspaces and near nullspaces which are attached to the B operator.
1264    In the case where B has a (near) nullspace attached, the (near) nullspace vectors are extracted from B and mapped into
1265    a new (near) nullspace, defined on the sub-communicator, which is attached to B' (the B operator which was scattered to c')
1266 
1267    The telescoping preconditioner can re-partition an attached DM if it is a `DMDA` (2D or 3D -
1268    support for 1D `DMDA`s is not provided). If a `DMDA` is found, a topologically equivalent `DMDA` is created on c'
1269    and this new `DM` is attached the sub `KSP`. The design of telescope is such that it should be possible to extend support
1270    for re-partitioning other to DM's (e.g. `DMPLEX`). The user can supply a flag to ignore attached DMs.
1271    Alternatively, user-provided re-partitioned DMs can be used via -pc_telescope_use_coarse_dm.
1272 
1273    With the default setup mode, B' is defined by fusing rows (in order) associated with MPI ranks common to c and c'.
1274 
1275    When a `DMDA` is attached to the parent preconditioner, B' is defined by: (i) performing a symmetric permutation of B
1276    into the ordering defined by the `DMDA` on c', (ii) extracting the local chunks via `MatCreateSubMatrices()`, (iii) fusing the
1277    locally (sequential) matrices defined on the ranks common to c and c' into B' using `MatCreateMPIMatConcatenateSeqMat()`
1278 
1279    Limitations/improvements include the following.
1280    `VecPlaceArray()` could be used within `PCApply()` to improve efficiency and reduce memory usage.
1281    A unified mechanism to query for user contexts as required by `KSPSetComputeOperators()` and `MatNullSpaceSetFunction()`.
1282 
1283    The symmetric permutation used when a `DMDA` is encountered is performed via explicitly assembling a permutation matrix P,
1284    and performing P^T.A.P. Possibly it might be more efficient to use `MatPermute()`. We opted to use P^T.A.P as it appears
1285    `VecPermute()` does not support the use case required here. By computing P, one can permute both the operator and RHS in a
1286    consistent manner.
1287 
1288    Mapping of vectors (default setup mode) is performed in the following way.
1289    Suppose the parent communicator size was 4, and we set a reduction factor of 2; this would give a comm size on c' of 2.
1290    Using the interlaced creation routine, the ranks in c with color = 0 will be rank 0 and 2.
1291    We perform the scatter to the sub-communicator in the following way.
1292    [1] Given a vector x defined on communicator c
1293 
1294 .vb
1295    rank(c)  local values of x
1296    ------- ----------------------------------------
1297         0   [  0.0,  1.0,  2.0,  3.0,  4.0,  5.0 ]
1298         1   [  6.0,  7.0,  8.0,  9.0, 10.0, 11.0 ]
1299         2   [ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0 ]
1300         3   [ 18.0, 19.0, 20.0, 21.0, 22.0, 23.0 ]
1301 .ve
1302 
1303    scatter into xtmp defined also on comm c, so that we have the following values
1304 
1305 .vb
1306    rank(c)  local values of xtmp
1307    ------- ----------------------------------------------------------------------------
1308         0   [  0.0,  1.0,  2.0,  3.0,  4.0,  5.0,  6.0,  7.0,  8.0,  9.0, 10.0, 11.0 ]
1309         1   [ ]
1310         2   [ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0 ]
1311         3   [ ]
1312 .ve
1313 
1314    The entries on rank 1 and 3 (ranks which do not have a color = 0 in c') have no values
1315 
1316    [2] Copy the values from ranks 0, 2 (indices with respect to comm c) into the vector xred which is defined on communicator c'.
1317    Ranks 0 and 2 are the only ranks in the subcomm which have a color = 0.
1318 
1319 .vb
1320    rank(c')  local values of xred
1321    -------- ----------------------------------------------------------------------------
1322          0   [  0.0,  1.0,  2.0,  3.0,  4.0,  5.0,  6.0,  7.0,  8.0,  9.0, 10.0, 11.0 ]
1323          1   [ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0 ]
1324 .ve
1325 
1326   Contributed by Dave May
1327 
1328   Reference:
1329   Dave A. May, Patrick Sanan, Karl Rupp, Matthew G. Knepley, and Barry F. Smith, "Extreme-Scale Multigrid Components within PETSc". 2016. In Proceedings of the Platform for Advanced Scientific Computing Conference (PASC '16). DOI: 10.1145/2929908.2929913
1330 
1331 .seealso: `PCTelescopeGetKSP()`, `PCTelescopeGetDM()`, `PCTelescopeGetReductionFactor()`, `PCTelescopeSetReductionFactor()`, `PCTelescopeGetIgnoreDM()`, `PCTelescopeSetIgnoreDM()`, `PCREDUNDANT`
1332 M*/
1333 PETSC_EXTERN PetscErrorCode PCCreate_Telescope(PC pc)
1334 {
1335   struct _PC_Telescope *sred;
1336 
1337   PetscFunctionBegin;
1338   PetscCall(PetscNew(&sred));
1339   sred->psubcomm                   = NULL;
1340   sred->subcommtype                = PETSC_SUBCOMM_INTERLACED;
1341   sred->subcomm                    = MPI_COMM_NULL;
1342   sred->redfactor                  = 1;
1343   sred->ignore_dm                  = PETSC_FALSE;
1344   sred->ignore_kspcomputeoperators = PETSC_FALSE;
1345   sred->use_coarse_dm              = PETSC_FALSE;
1346   pc->data                         = (void *)sred;
1347 
1348   pc->ops->apply           = PCApply_Telescope;
1349   pc->ops->applytranspose  = NULL;
1350   pc->ops->applyrichardson = PCApplyRichardson_Telescope;
1351   pc->ops->setup           = PCSetUp_Telescope;
1352   pc->ops->destroy         = PCDestroy_Telescope;
1353   pc->ops->reset           = PCReset_Telescope;
1354   pc->ops->setfromoptions  = PCSetFromOptions_Telescope;
1355   pc->ops->view            = PCView_Telescope;
1356 
1357   sred->pctelescope_setup_type              = PCTelescopeSetUp_default;
1358   sred->pctelescope_matcreate_type          = PCTelescopeMatCreate_default;
1359   sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_default;
1360   sred->pctelescope_reset_type              = NULL;
1361 
1362   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetKSP_C", PCTelescopeGetKSP_Telescope));
1363   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetSubcommType_C", PCTelescopeGetSubcommType_Telescope));
1364   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetSubcommType_C", PCTelescopeSetSubcommType_Telescope));
1365   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetReductionFactor_C", PCTelescopeGetReductionFactor_Telescope));
1366   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetReductionFactor_C", PCTelescopeSetReductionFactor_Telescope));
1367   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreDM_C", PCTelescopeGetIgnoreDM_Telescope));
1368   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreDM_C", PCTelescopeSetIgnoreDM_Telescope));
1369   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", PCTelescopeGetIgnoreKSPComputeOperators_Telescope));
1370   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", PCTelescopeSetIgnoreKSPComputeOperators_Telescope));
1371   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetDM_C", PCTelescopeGetDM_Telescope));
1372   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetUseCoarseDM_C", PCTelescopeGetUseCoarseDM_Telescope));
1373   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetUseCoarseDM_C", PCTelescopeSetUseCoarseDM_Telescope));
1374   PetscFunctionReturn(PETSC_SUCCESS);
1375 }
1376