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 static 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(MPIU_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 PetscCallMPI(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 static 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 static 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)); /* Use the vectype of the matrix used to construct the preconditioner by default */ 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)); 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 static 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 isascii, isstring; 315 PetscViewer subviewer; 316 317 PetscFunctionBegin; 318 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 319 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring)); 320 if (isascii) { 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", comm_size, 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 = PETSC_TRUE; 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(MPIU_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(MPIU_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(KSPSetNestLevel(sred->ksp, pc->kspnestlevel)); 539 PetscCall(KSPSetErrorIfNotConverged(sred->ksp, pc->erroriffailure)); 540 PetscCall(PetscObjectIncrementTabLevel((PetscObject)sred->ksp, (PetscObject)pc, 1)); 541 PetscCall(KSPSetType(sred->ksp, KSPPREONLY)); 542 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 543 PetscCall(KSPSetOptionsPrefix(sred->ksp, prefix)); 544 PetscCall(KSPAppendOptionsPrefix(sred->ksp, "telescope_")); 545 } 546 } 547 548 /* setup */ 549 if (!pc->setupcalled && sred->pctelescope_setup_type) PetscCall(sred->pctelescope_setup_type(pc, sred)); 550 /* update */ 551 if (!pc->setupcalled) { 552 if (sred->pctelescope_matcreate_type) PetscCall(sred->pctelescope_matcreate_type(pc, sred, MAT_INITIAL_MATRIX, &sred->Bred)); 553 if (sred->pctelescope_matnullspacecreate_type) PetscCall(sred->pctelescope_matnullspacecreate_type(pc, sred, sred->Bred)); 554 } else { 555 if (sred->pctelescope_matcreate_type) PetscCall(sred->pctelescope_matcreate_type(pc, sred, MAT_REUSE_MATRIX, &sred->Bred)); 556 } 557 558 /* common - no construction */ 559 if (PCTelescope_isActiveRank(sred)) { 560 PetscCall(KSPSetOperators(sred->ksp, sred->Bred, sred->Bred)); 561 if (pc->setfromoptionscalled && !pc->setupcalled) PetscCall(KSPSetFromOptions(sred->ksp)); 562 } 563 PetscFunctionReturn(PETSC_SUCCESS); 564 } 565 566 static PetscErrorCode PCApply_Telescope(PC pc, Vec x, Vec y) 567 { 568 PC_Telescope sred = (PC_Telescope)pc->data; 569 Vec xtmp, xred, yred; 570 PetscInt i, st, ed; 571 VecScatter scatter; 572 PetscScalar *array; 573 const PetscScalar *x_array; 574 575 PetscFunctionBegin; 576 PetscCall(PetscCitationsRegister(citation, &cited)); 577 578 xtmp = sred->xtmp; 579 scatter = sred->scatter; 580 xred = sred->xred; 581 yred = sred->yred; 582 583 /* pull in vector x->xtmp */ 584 PetscCall(VecScatterBegin(scatter, x, xtmp, INSERT_VALUES, SCATTER_FORWARD)); 585 PetscCall(VecScatterEnd(scatter, x, xtmp, INSERT_VALUES, SCATTER_FORWARD)); 586 587 /* copy vector entries into xred */ 588 PetscCall(VecGetArrayRead(xtmp, &x_array)); 589 if (xred) { 590 PetscScalar *LA_xred; 591 PetscCall(VecGetOwnershipRange(xred, &st, &ed)); 592 PetscCall(VecGetArray(xred, &LA_xred)); 593 for (i = 0; i < ed - st; i++) LA_xred[i] = x_array[i]; 594 PetscCall(VecRestoreArray(xred, &LA_xred)); 595 } 596 PetscCall(VecRestoreArrayRead(xtmp, &x_array)); 597 /* solve */ 598 if (PCTelescope_isActiveRank(sred)) { 599 PetscCall(KSPSolve(sred->ksp, xred, yred)); 600 PetscCall(KSPCheckSolve(sred->ksp, pc, yred)); 601 } 602 /* return vector */ 603 PetscCall(VecGetArray(xtmp, &array)); 604 if (yred) { 605 const PetscScalar *LA_yred; 606 PetscCall(VecGetOwnershipRange(yred, &st, &ed)); 607 PetscCall(VecGetArrayRead(yred, &LA_yred)); 608 for (i = 0; i < ed - st; i++) array[i] = LA_yred[i]; 609 PetscCall(VecRestoreArrayRead(yred, &LA_yred)); 610 } 611 PetscCall(VecRestoreArray(xtmp, &array)); 612 PetscCall(VecScatterBegin(scatter, xtmp, y, INSERT_VALUES, SCATTER_REVERSE)); 613 PetscCall(VecScatterEnd(scatter, xtmp, y, INSERT_VALUES, SCATTER_REVERSE)); 614 PetscFunctionReturn(PETSC_SUCCESS); 615 } 616 617 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) 618 { 619 PC_Telescope sred = (PC_Telescope)pc->data; 620 Vec xtmp, yred; 621 PetscInt i, st, ed; 622 VecScatter scatter; 623 const PetscScalar *x_array; 624 PetscBool default_init_guess_value; 625 626 PetscFunctionBegin; 627 xtmp = sred->xtmp; 628 scatter = sred->scatter; 629 yred = sred->yred; 630 631 PetscCheck(its <= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCApplyRichardson_Telescope only supports max_it = 1"); 632 *reason = (PCRichardsonConvergedReason)0; 633 634 if (!zeroguess) { 635 PetscCall(PetscInfo(pc, "PCTelescope: Scattering y for non-zero initial guess\n")); 636 /* pull in vector y->xtmp */ 637 PetscCall(VecScatterBegin(scatter, y, xtmp, INSERT_VALUES, SCATTER_FORWARD)); 638 PetscCall(VecScatterEnd(scatter, y, xtmp, INSERT_VALUES, SCATTER_FORWARD)); 639 640 /* copy vector entries into xred */ 641 PetscCall(VecGetArrayRead(xtmp, &x_array)); 642 if (yred) { 643 PetscScalar *LA_yred; 644 PetscCall(VecGetOwnershipRange(yred, &st, &ed)); 645 PetscCall(VecGetArray(yred, &LA_yred)); 646 for (i = 0; i < ed - st; i++) LA_yred[i] = x_array[i]; 647 PetscCall(VecRestoreArray(yred, &LA_yred)); 648 } 649 PetscCall(VecRestoreArrayRead(xtmp, &x_array)); 650 } 651 652 if (PCTelescope_isActiveRank(sred)) { 653 PetscCall(KSPGetInitialGuessNonzero(sred->ksp, &default_init_guess_value)); 654 if (!zeroguess) PetscCall(KSPSetInitialGuessNonzero(sred->ksp, PETSC_TRUE)); 655 } 656 657 PetscCall(PCApply_Telescope(pc, x, y)); 658 659 if (PCTelescope_isActiveRank(sred)) PetscCall(KSPSetInitialGuessNonzero(sred->ksp, default_init_guess_value)); 660 661 if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 662 *outits = 1; 663 PetscFunctionReturn(PETSC_SUCCESS); 664 } 665 666 static PetscErrorCode PCReset_Telescope(PC pc) 667 { 668 PC_Telescope sred = (PC_Telescope)pc->data; 669 670 PetscFunctionBegin; 671 PetscCall(ISDestroy(&sred->isin)); 672 PetscCall(VecScatterDestroy(&sred->scatter)); 673 PetscCall(VecDestroy(&sred->xred)); 674 PetscCall(VecDestroy(&sred->yred)); 675 PetscCall(VecDestroy(&sred->xtmp)); 676 PetscCall(MatDestroy(&sred->Bred)); 677 PetscCall(KSPReset(sred->ksp)); 678 if (sred->pctelescope_reset_type) PetscCall(sred->pctelescope_reset_type(pc)); 679 PetscFunctionReturn(PETSC_SUCCESS); 680 } 681 682 static PetscErrorCode PCDestroy_Telescope(PC pc) 683 { 684 PC_Telescope sred = (PC_Telescope)pc->data; 685 686 PetscFunctionBegin; 687 PetscCall(PCReset_Telescope(pc)); 688 PetscCall(KSPDestroy(&sred->ksp)); 689 PetscCall(PetscSubcommDestroy(&sred->psubcomm)); 690 PetscCall(PetscFree(sred->dm_ctx)); 691 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetKSP_C", NULL)); 692 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetSubcommType_C", NULL)); 693 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetSubcommType_C", NULL)); 694 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetReductionFactor_C", NULL)); 695 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetReductionFactor_C", NULL)); 696 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreDM_C", NULL)); 697 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreDM_C", NULL)); 698 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", NULL)); 699 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", NULL)); 700 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetDM_C", NULL)); 701 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetUseCoarseDM_C", NULL)); 702 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetUseCoarseDM_C", NULL)); 703 PetscCall(PetscFree(pc->data)); 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 static PetscErrorCode PCSetFromOptions_Telescope(PC pc, PetscOptionItems PetscOptionsObject) 708 { 709 PC_Telescope sred = (PC_Telescope)pc->data; 710 MPI_Comm comm; 711 PetscMPIInt size; 712 PetscBool flg; 713 PetscSubcommType subcommtype; 714 715 PetscFunctionBegin; 716 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 717 PetscCallMPI(MPI_Comm_size(comm, &size)); 718 PetscOptionsHeadBegin(PetscOptionsObject, "Telescope options"); 719 PetscCall(PetscOptionsEnum("-pc_telescope_subcomm_type", "Subcomm type (interlaced or contiguous)", "PCTelescopeSetSubcommType", PetscSubcommTypes, (PetscEnum)sred->subcommtype, (PetscEnum *)&subcommtype, &flg)); 720 if (flg) PetscCall(PCTelescopeSetSubcommType(pc, subcommtype)); 721 PetscCall(PetscOptionsInt("-pc_telescope_reduction_factor", "Factor to reduce comm size by", "PCTelescopeSetReductionFactor", sred->redfactor, &sred->redfactor, NULL)); 722 PetscCheck(sred->redfactor <= size, comm, PETSC_ERR_ARG_WRONG, "-pc_telescope_reduction_factor <= comm size"); 723 PetscCall(PetscOptionsBool("-pc_telescope_ignore_dm", "Ignore any DM attached to the PC", "PCTelescopeSetIgnoreDM", sred->ignore_dm, &sred->ignore_dm, NULL)); 724 PetscCall(PetscOptionsBool("-pc_telescope_ignore_kspcomputeoperators", "Ignore method used to compute A", "PCTelescopeSetIgnoreKSPComputeOperators", sred->ignore_kspcomputeoperators, &sred->ignore_kspcomputeoperators, NULL)); 725 PetscCall(PetscOptionsBool("-pc_telescope_use_coarse_dm", "Define sub-communicator from the coarse DM", "PCTelescopeSetUseCoarseDM", sred->use_coarse_dm, &sred->use_coarse_dm, NULL)); 726 PetscOptionsHeadEnd(); 727 PetscFunctionReturn(PETSC_SUCCESS); 728 } 729 730 /* PC simplementation specific API's */ 731 732 static PetscErrorCode PCTelescopeGetKSP_Telescope(PC pc, KSP *ksp) 733 { 734 PC_Telescope red = (PC_Telescope)pc->data; 735 736 PetscFunctionBegin; 737 if (ksp) *ksp = red->ksp; 738 PetscFunctionReturn(PETSC_SUCCESS); 739 } 740 741 static PetscErrorCode PCTelescopeGetSubcommType_Telescope(PC pc, PetscSubcommType *subcommtype) 742 { 743 PC_Telescope red = (PC_Telescope)pc->data; 744 745 PetscFunctionBegin; 746 if (subcommtype) *subcommtype = red->subcommtype; 747 PetscFunctionReturn(PETSC_SUCCESS); 748 } 749 750 static PetscErrorCode PCTelescopeSetSubcommType_Telescope(PC pc, PetscSubcommType subcommtype) 751 { 752 PC_Telescope red = (PC_Telescope)pc->data; 753 754 PetscFunctionBegin; 755 PetscCheck(!pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "You cannot change the subcommunicator type for PCTelescope after it has been set up."); 756 red->subcommtype = subcommtype; 757 PetscFunctionReturn(PETSC_SUCCESS); 758 } 759 760 static PetscErrorCode PCTelescopeGetReductionFactor_Telescope(PC pc, PetscInt *fact) 761 { 762 PC_Telescope red = (PC_Telescope)pc->data; 763 764 PetscFunctionBegin; 765 if (fact) *fact = red->redfactor; 766 PetscFunctionReturn(PETSC_SUCCESS); 767 } 768 769 static PetscErrorCode PCTelescopeSetReductionFactor_Telescope(PC pc, PetscInt fact) 770 { 771 PC_Telescope red = (PC_Telescope)pc->data; 772 PetscMPIInt size; 773 774 PetscFunctionBegin; 775 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size)); 776 PetscCheck(fact > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Reduction factor of telescoping PC %" PetscInt_FMT " must be positive", fact); 777 PetscCheck(fact <= size, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Reduction factor of telescoping PC %" PetscInt_FMT " must be <= comm.size", fact); 778 red->redfactor = fact; 779 PetscFunctionReturn(PETSC_SUCCESS); 780 } 781 782 static PetscErrorCode PCTelescopeGetIgnoreDM_Telescope(PC pc, PetscBool *v) 783 { 784 PC_Telescope red = (PC_Telescope)pc->data; 785 786 PetscFunctionBegin; 787 if (v) *v = red->ignore_dm; 788 PetscFunctionReturn(PETSC_SUCCESS); 789 } 790 791 static PetscErrorCode PCTelescopeSetIgnoreDM_Telescope(PC pc, PetscBool v) 792 { 793 PC_Telescope red = (PC_Telescope)pc->data; 794 795 PetscFunctionBegin; 796 red->ignore_dm = v; 797 PetscFunctionReturn(PETSC_SUCCESS); 798 } 799 800 static PetscErrorCode PCTelescopeGetUseCoarseDM_Telescope(PC pc, PetscBool *v) 801 { 802 PC_Telescope red = (PC_Telescope)pc->data; 803 804 PetscFunctionBegin; 805 if (v) *v = red->use_coarse_dm; 806 PetscFunctionReturn(PETSC_SUCCESS); 807 } 808 809 static PetscErrorCode PCTelescopeSetUseCoarseDM_Telescope(PC pc, PetscBool v) 810 { 811 PC_Telescope red = (PC_Telescope)pc->data; 812 813 PetscFunctionBegin; 814 red->use_coarse_dm = v; 815 PetscFunctionReturn(PETSC_SUCCESS); 816 } 817 818 static PetscErrorCode PCTelescopeGetIgnoreKSPComputeOperators_Telescope(PC pc, PetscBool *v) 819 { 820 PC_Telescope red = (PC_Telescope)pc->data; 821 822 PetscFunctionBegin; 823 if (v) *v = red->ignore_kspcomputeoperators; 824 PetscFunctionReturn(PETSC_SUCCESS); 825 } 826 827 static PetscErrorCode PCTelescopeSetIgnoreKSPComputeOperators_Telescope(PC pc, PetscBool v) 828 { 829 PC_Telescope red = (PC_Telescope)pc->data; 830 831 PetscFunctionBegin; 832 red->ignore_kspcomputeoperators = v; 833 PetscFunctionReturn(PETSC_SUCCESS); 834 } 835 836 static PetscErrorCode PCTelescopeGetDM_Telescope(PC pc, DM *dm) 837 { 838 PC_Telescope red = (PC_Telescope)pc->data; 839 840 PetscFunctionBegin; 841 *dm = private_PCTelescopeGetSubDM(red); 842 PetscFunctionReturn(PETSC_SUCCESS); 843 } 844 845 /*@ 846 PCTelescopeGetKSP - Gets the `KSP` created by the telescoping `PC`. 847 848 Not Collective 849 850 Input Parameter: 851 . pc - the preconditioner context 852 853 Output Parameter: 854 . subksp - the `KSP` defined on the smaller set of processes 855 856 Level: advanced 857 858 .seealso: [](ch_ksp), `PC`, `KSP`, `PCTELESCOPE` 859 @*/ 860 PetscErrorCode PCTelescopeGetKSP(PC pc, KSP *subksp) 861 { 862 PetscFunctionBegin; 863 PetscUseMethod(pc, "PCTelescopeGetKSP_C", (PC, KSP *), (pc, subksp)); 864 PetscFunctionReturn(PETSC_SUCCESS); 865 } 866 867 /*@ 868 PCTelescopeGetReductionFactor - Gets the factor by which the original number of MPI processes has been reduced by that was set by 869 `PCTelescopeSetReductionFactor()` 870 871 Not Collective 872 873 Input Parameter: 874 . pc - the preconditioner context 875 876 Output Parameter: 877 . fact - the reduction factor 878 879 Level: advanced 880 881 .seealso: [](ch_ksp), `PC`, `PCTELESCOPE`, `PCTelescopeSetReductionFactor()` 882 @*/ 883 PetscErrorCode PCTelescopeGetReductionFactor(PC pc, PetscInt *fact) 884 { 885 PetscFunctionBegin; 886 PetscUseMethod(pc, "PCTelescopeGetReductionFactor_C", (PC, PetscInt *), (pc, fact)); 887 PetscFunctionReturn(PETSC_SUCCESS); 888 } 889 890 /*@ 891 PCTelescopeSetReductionFactor - Sets the factor by which the original number of MPI processes will been reduced by when 892 constructing the subcommunicator to be used with the `PCTELESCOPE`. 893 894 Not Collective 895 896 Input Parameter: 897 . pc - the preconditioner context 898 899 Output Parameter: 900 . fact - the reduction factor 901 902 Level: advanced 903 904 .seealso: [](ch_ksp), `PCTELESCOPE`, `PCTelescopeGetReductionFactor()` 905 @*/ 906 PetscErrorCode PCTelescopeSetReductionFactor(PC pc, PetscInt fact) 907 { 908 PetscFunctionBegin; 909 PetscTryMethod(pc, "PCTelescopeSetReductionFactor_C", (PC, PetscInt), (pc, fact)); 910 PetscFunctionReturn(PETSC_SUCCESS); 911 } 912 913 /*@ 914 PCTelescopeGetIgnoreDM - Get the flag indicating if any `DM` attached to the `PC` will be used in constructing the `PC` on the 915 reduced number of MPI processes 916 917 Not Collective 918 919 Input Parameter: 920 . pc - the preconditioner context 921 922 Output Parameter: 923 . v - the flag 924 925 Level: advanced 926 927 .seealso: [](ch_ksp), `DM`, `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()` 928 @*/ 929 PetscErrorCode PCTelescopeGetIgnoreDM(PC pc, PetscBool *v) 930 { 931 PetscFunctionBegin; 932 PetscUseMethod(pc, "PCTelescopeGetIgnoreDM_C", (PC, PetscBool *), (pc, v)); 933 PetscFunctionReturn(PETSC_SUCCESS); 934 } 935 936 /*@ 937 PCTelescopeSetIgnoreDM - Set a flag to ignore any `DM` attached to the `PC` when constructing the `PC` on the 938 reduced number of MPI processes 939 940 Not Collective 941 942 Input Parameter: 943 . pc - the preconditioner context 944 945 Output Parameter: 946 . v - Use `PETSC_TRUE` to ignore any `DM` 947 948 Level: advanced 949 950 .seealso: [](ch_ksp), `DM`, `PCTELESCOPE`, `PCTelescopeGetIgnoreDM()` 951 @*/ 952 PetscErrorCode PCTelescopeSetIgnoreDM(PC pc, PetscBool v) 953 { 954 PetscFunctionBegin; 955 PetscTryMethod(pc, "PCTelescopeSetIgnoreDM_C", (PC, PetscBool), (pc, v)); 956 PetscFunctionReturn(PETSC_SUCCESS); 957 } 958 959 /*@ 960 PCTelescopeGetUseCoarseDM - Get the flag indicating if the coarse `DM` attached to `DM` associated with the `PC` will be used in constructing 961 the `PC` on the reduced number of MPI processes 962 963 Not Collective 964 965 Input Parameter: 966 . pc - the preconditioner context 967 968 Output Parameter: 969 . v - the flag 970 971 Level: advanced 972 973 .seealso: [](ch_ksp), `DM`, `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()` 974 @*/ 975 PetscErrorCode PCTelescopeGetUseCoarseDM(PC pc, PetscBool *v) 976 { 977 PetscFunctionBegin; 978 PetscUseMethod(pc, "PCTelescopeGetUseCoarseDM_C", (PC, PetscBool *), (pc, v)); 979 PetscFunctionReturn(PETSC_SUCCESS); 980 } 981 982 /*@ 983 PCTelescopeSetUseCoarseDM - Set a flag to query the `DM` attached to the `PC` if it also has a coarse `DM` and utilize that `DM` 984 in constructing the `PC` on the reduced number of MPI processes 985 986 Not Collective 987 988 Input Parameter: 989 . pc - the preconditioner context 990 991 Output Parameter: 992 . v - Use `PETSC_FALSE` to ignore any coarse `DM` 993 994 Level: advanced 995 996 Notes: 997 When you have specified to use a coarse `DM`, the communicator used to create the sub-`KSP` within `PCTELESCOPE` 998 will be that of the coarse `DM`. Hence the flags `-pc_telescope_reduction_factor` and 999 `-pc_telescope_subcomm_type` will not be used. 1000 1001 It is required that the communicator associated with the parent (fine) and the coarse `DM` are of different sizes. 1002 An error will occur of the size if the communicator associated with the coarse `DM` is the same as that of the parent `DM`. 1003 Furthermore, it is required that the communicator on the coarse `DM` is a sub-communicator of the parent. 1004 This will be checked at the time the preconditioner is setup and an error will occur if 1005 the coarse `DM` does not define a sub-communicator of that used by the parent `DM`. 1006 1007 The particular Telescope setup invoked when using a coarse `DM` is agnostic with respect to the type of 1008 the `DM` used (e.g. it supports `DMSHELL`, `DMPLEX`, etc). 1009 1010 Support is currently only provided for the case when you are using `KSPSetComputeOperators()` 1011 1012 The user is required to compose a function with the parent `DM` to facilitate the transfer of fields (`Vec`) 1013 between the different decompositions defined by the fine and coarse `DM`s. 1014 In the user code, this is achieved via 1015 .vb 1016 { 1017 DM dm_fine; 1018 PetscObjectCompose((PetscObject)dm_fine,"PCTelescopeFieldScatter",your_field_scatter_method); 1019 } 1020 .ve 1021 The signature of the user provided field scatter method is 1022 .vb 1023 PetscErrorCode your_field_scatter_method(DM dm_fine,Vec x_fine,ScatterMode mode,DM dm_coarse,Vec x_coarse); 1024 .ve 1025 The user must provide support for both mode `SCATTER_FORWARD` and mode `SCATTER_REVERSE`. 1026 `SCATTER_FORWARD` implies the direction of transfer is from the parent (fine) `DM` to the coarse `DM`. 1027 1028 Optionally, the user may also compose a function with the parent `DM` to facilitate the transfer 1029 of state variables between the fine and coarse `DM`s. 1030 In the context of a finite element discretization, an example state variable might be 1031 values associated with quadrature points within each element. 1032 A user provided state scatter method is composed via 1033 .vb 1034 { 1035 DM dm_fine; 1036 PetscObjectCompose((PetscObject)dm_fine,"PCTelescopeStateScatter",your_state_scatter_method); 1037 } 1038 .ve 1039 The signature of the user provided state scatter method is 1040 .vb 1041 PetscErrorCode your_state_scatter_method(DM dm_fine,ScatterMode mode,DM dm_coarse); 1042 .ve 1043 `SCATTER_FORWARD` implies the direction of transfer is from the fine `DM` to the coarse `DM`. 1044 The user is only required to support mode = `SCATTER_FORWARD`. 1045 No assumption is made about the data type of the state variables. 1046 These must be managed by the user and must be accessible from the `DM`. 1047 1048 Care must be taken in defining the user context passed to `KSPSetComputeOperators()` which is to be 1049 associated with the sub-`KSP` residing within `PCTELESCOPE`. 1050 In general, `PCTELESCOPE` assumes that the context on the fine and coarse `DM` used with 1051 `KSPSetComputeOperators()` should be "similar" in type or origin. 1052 Specifically the following rules are used to infer what context on the sub-`KSP` should be. 1053 1054 First the contexts from the `KSP` and the fine and coarse `DM`s are retrieved. 1055 Note that the special case of a `DMSHELL` context is queried. 1056 1057 .vb 1058 DMKSPGetComputeOperators(dm_fine,&dmfine_kspfunc,&dmfine_kspctx); 1059 DMGetApplicationContext(dm_fine,&dmfine_appctx); 1060 DMShellGetContext(dm_fine,&dmfine_shellctx); 1061 1062 DMGetApplicationContext(dm_coarse,&dmcoarse_appctx); 1063 DMShellGetContext(dm_coarse,&dmcoarse_shellctx); 1064 .ve 1065 1066 The following rules are then enforced\: 1067 1068 1. If `dmfine_kspctx` = `NULL`, then we provide a `NULL` pointer as the context for the sub-`KSP`\: 1069 `KSPSetComputeOperators`(`sub_ksp`,`dmfine_kspfunc`,`NULL`); 1070 1071 2. If `dmfine_kspctx` != `NULL` and `dmfine_kspctx` == `dmfine_appctx`, 1072 1073 check that `dmcoarse_appctx` is also non-`NULL`. If this is true, then\: 1074 `KSPSetComputeOperators`(`sub_ksp`,`dmfine_kspfunc`,`dmcoarse_appctx`); 1075 1076 3. If `dmfine_kspctx` != `NULL` and `dmfine_kspctx` == `dmfine_shellctx`, 1077 1078 check that `dmcoarse_shellctx` is also non-`NULL`. If this is true, then\: 1079 `KSPSetComputeOperators`(`sub_ksp`,`dmfine_kspfunc`,`dmcoarse_shellctx`); 1080 1081 If neither of the above three tests passed, then `PCTELESCOPE` cannot safely determine what 1082 context should be provided to `KSPSetComputeOperators()` for use with the sub-`KSP`. 1083 In this case, an additional mechanism is provided via a composed function which will return 1084 the actual context to be used. To use this feature you must compose the "getter" function 1085 with the coarse `DM`, e.g. 1086 .vb 1087 { 1088 DM dm_coarse; 1089 PetscObjectCompose((PetscObject)dm_coarse,"PCTelescopeGetCoarseDMKSPContext",your_coarse_context_getter); 1090 } 1091 .ve 1092 The signature of the user provided method is 1093 .vb 1094 PetscErrorCode your_coarse_context_getter(DM dm_coarse,void **your_kspcontext); 1095 .ve 1096 1097 .seealso: [](ch_ksp), `DM`, `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()` 1098 @*/ 1099 PetscErrorCode PCTelescopeSetUseCoarseDM(PC pc, PetscBool v) 1100 { 1101 PetscFunctionBegin; 1102 PetscTryMethod(pc, "PCTelescopeSetUseCoarseDM_C", (PC, PetscBool), (pc, v)); 1103 PetscFunctionReturn(PETSC_SUCCESS); 1104 } 1105 1106 /*@ 1107 PCTelescopeGetIgnoreKSPComputeOperators - Get the flag indicating if `KSPComputeOperators()` will be used to construct 1108 the matrix on the reduced number of MPI processes 1109 1110 Not Collective 1111 1112 Input Parameter: 1113 . pc - the preconditioner context 1114 1115 Output Parameter: 1116 . v - the flag 1117 1118 Level: advanced 1119 1120 .seealso: [](ch_ksp), `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeSetIgnoreKSPComputeOperators()` 1121 @*/ 1122 PetscErrorCode PCTelescopeGetIgnoreKSPComputeOperators(PC pc, PetscBool *v) 1123 { 1124 PetscFunctionBegin; 1125 PetscUseMethod(pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", (PC, PetscBool *), (pc, v)); 1126 PetscFunctionReturn(PETSC_SUCCESS); 1127 } 1128 1129 /*@ 1130 PCTelescopeSetIgnoreKSPComputeOperators - Set a flag to have `PCTELESCOPE` ignore the function provided to `KSPComputeOperators()` in 1131 constructint the matrix on the reduced number of MPI processes 1132 1133 Not Collective 1134 1135 Input Parameter: 1136 . pc - the preconditioner context 1137 1138 Output Parameter: 1139 . v - Use `PETSC_TRUE` to ignore the function (if defined) set via `KSPSetComputeOperators()` on `pc` 1140 1141 Level: advanced 1142 1143 .seealso: [](ch_ksp), `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeGetIgnoreKSPComputeOperators()` 1144 @*/ 1145 PetscErrorCode PCTelescopeSetIgnoreKSPComputeOperators(PC pc, PetscBool v) 1146 { 1147 PetscFunctionBegin; 1148 PetscTryMethod(pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", (PC, PetscBool), (pc, v)); 1149 PetscFunctionReturn(PETSC_SUCCESS); 1150 } 1151 1152 /*@ 1153 PCTelescopeGetDM - Get the re-partitioned `DM` attached to the sub-`KSP`. 1154 1155 Not Collective 1156 1157 Input Parameter: 1158 . pc - the preconditioner context 1159 1160 Output Parameter: 1161 . subdm - The re-partitioned `DM` 1162 1163 Level: advanced 1164 1165 .seealso: [](ch_ksp), `DM`, `PCTELESCOPE`, `PCTelescopeSetIgnoreDM()`, `PCTelescopeSetUseCoarseDM()`, `PCTelescopeGetIgnoreKSPComputeOperators()` 1166 @*/ 1167 PetscErrorCode PCTelescopeGetDM(PC pc, DM *subdm) 1168 { 1169 PetscFunctionBegin; 1170 PetscUseMethod(pc, "PCTelescopeGetDM_C", (PC, DM *), (pc, subdm)); 1171 PetscFunctionReturn(PETSC_SUCCESS); 1172 } 1173 1174 /*@ 1175 PCTelescopeSetSubcommType - set subcommunicator type `PetscSubcommType` (interlaced or contiguous) to be used when 1176 the subcommunicator is generated from the given `PC` 1177 1178 Logically Collective 1179 1180 Input Parameters: 1181 + pc - the preconditioner context 1182 - subcommtype - the subcommunicator type (see `PetscSubcommType`) 1183 1184 Level: advanced 1185 1186 .seealso: [](ch_ksp), `PetscSubcommType`, `PetscSubcomm`, `PCTELESCOPE`, `PCTelescopeGetSubcommType()` 1187 @*/ 1188 PetscErrorCode PCTelescopeSetSubcommType(PC pc, PetscSubcommType subcommtype) 1189 { 1190 PetscFunctionBegin; 1191 PetscTryMethod(pc, "PCTelescopeSetSubcommType_C", (PC, PetscSubcommType), (pc, subcommtype)); 1192 PetscFunctionReturn(PETSC_SUCCESS); 1193 } 1194 1195 /*@ 1196 PCTelescopeGetSubcommType - Get the subcommunicator type `PetscSubcommType` (interlaced or contiguous) set with `PCTelescopeSetSubcommType()` 1197 1198 Not Collective 1199 1200 Input Parameter: 1201 . pc - the preconditioner context 1202 1203 Output Parameter: 1204 . subcommtype - the subcommunicator type (see `PetscSubcommType`) 1205 1206 Level: advanced 1207 1208 .seealso: [](ch_ksp), `PetscSubcomm`, `PetscSubcommType`, `PCTELESCOPE`, `PCTelescopeSetSubcommType()` 1209 @*/ 1210 PetscErrorCode PCTelescopeGetSubcommType(PC pc, PetscSubcommType *subcommtype) 1211 { 1212 PetscFunctionBegin; 1213 PetscUseMethod(pc, "PCTelescopeGetSubcommType_C", (PC, PetscSubcommType *), (pc, subcommtype)); 1214 PetscFunctionReturn(PETSC_SUCCESS); 1215 } 1216 1217 /*MC 1218 PCTELESCOPE - Runs a `KSP` solver on a sub-communicator {cite}`maysananruppknepleysmith2016` of the communicator used by the original `KSP`. 1219 MPI processes not in the sub-communicator are idle during the solve. Usually used to solve the smaller coarser grid problems in multigrid 1220 (`PCMG`) that could not be efficiently solved on the entire communication 1221 1222 Options Database Keys: 1223 + -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. 1224 . -pc_telescope_ignore_dm - flag to indicate whether an attached `DM` should be ignored in constructing the new `PC` 1225 . -pc_telescope_subcomm_type <interlaced,contiguous> - defines the selection of MPI processes on the sub-communicator. see `PetscSubcomm` for more information. 1226 . -pc_telescope_ignore_kspcomputeoperators - flag to indicate whether `KSPSetComputeOperators()` should be used on the sub-`KSP`. 1227 - -pc_telescope_use_coarse_dm - flag to indicate whether the coarse `DM` should be used to define the sub-communicator. 1228 1229 Level: advanced 1230 1231 Notes: 1232 Assuming that the parent preconditioner `PC` is defined on a communicator c, this implementation 1233 creates a child sub-communicator (c') containing fewer MPI processes than the original parent preconditioner `PC`. 1234 The preconditioner is deemed telescopic as it only calls `KSPSolve()` on a single 1235 sub-communicator, in contrast with `PCREDUNDANT` which calls `KSPSolve()` on N sub-communicators. 1236 This means there will be MPI processes which will be idle during the application of this preconditioner. 1237 Additionally, in comparison with `PCREDUNDANT`, `PCTELESCOPE` can utilize an attached `DM` to construct `DM` dependent preconditioner, such as `PCMG` 1238 1239 The default type `KSPType` of the sub `KSP` (the `KSP` defined on c') is `KSPPREONLY`. 1240 1241 There are three setup mechanisms for `PCTELESCOPE`. Features support by each type are described below. 1242 In the following, we will refer to the operators B and B', these are the `Bmat` provided to the `KSP` on the 1243 communicators c and c' respectively. 1244 1245 [1] Default setup 1246 The sub-communicator c' is created via `PetscSubcommCreate()`. 1247 Any explicitly defined nullspace and near nullspace vectors attached to B with `MatSetNullSpace()` and `MatSetNearNullSpace()` are transferred to B'. 1248 Currently there is no support for nullspaces provided with `MatNullSpaceSetFunction()`). 1249 No support is provided for `KSPSetComputeOperators()`. 1250 Currently there is no support for the flag `-pc_use_amat`. 1251 1252 [2] `DM` aware setup 1253 The sub-communicator c' is created via `PetscSubcommCreate()`. 1254 If a `DM` is attached to the `PC`, it is re-partitioned on the sub-communicator c'. 1255 Both the `Bmat` operator and the right-hand side vector are permuted into the new DOF ordering defined by the re-partitioned `DM`. 1256 Currently only support for re-partitioning a `DMDA` is provided. 1257 Any explicitly defined nullspace or near nullspace vectors attached to the original B with `MatSetNullSpace()` 1258 and `MatSetNearNullSpace()` are extracted, re-partitioned and set on B' 1259 (currently there is no support for nullspaces provided with `MatNullSpaceSetFunction()`). 1260 Support is provided for `KSPSetComputeOperators()`. The user provided function and context is propagated to the sub `KSP`. 1261 This is fragile since the user must ensure that their user context is valid for use on c'. 1262 Currently there is no support for the flag `-pc_use_amat`. 1263 1264 [3] Coarse `DM` setup 1265 If a `DM` (dmfine) is attached to the `PC`, dmfine is queried for a "coarse" `DM` (call this dmcoarse) via `DMGetCoarseDM()`. 1266 `PCTELESCOPE` will interpret the coarse `DM` as being defined on a sub-communicator of c. 1267 The communicator associated with dmcoarse will define the c' to be used within `PCTELESCOPE`. 1268 `PCTELESCOPE` will check that c' is in fact a sub-communicator of c. If it is not, an error will be reported. 1269 The intention of this setup type is that `PCTELESCOPE` will use an existing (e.g. user defined) communicator hierarchy, say as would be 1270 available with using multi-grid on unstructured meshes. 1271 This setup will not use the command line options `-pc_telescope_reduction_factor` or `-pc_telescope_subcomm_type`. 1272 Any explicitly defined nullspace or near nullspace vectors attached to the B are extracted, scattered into the correct ordering consistent 1273 with dmcoarse and set on B' 1274 (currently there is no support for nullspaces provided with `MatNullSpaceSetFunction()`). 1275 There is no general method to permute field orderings, hence only `KSPSetComputeOperators()` is supported. 1276 The user must use `PetscObjectComposeFunction()` with dmfine to define the method to scatter fields from dmfine to dmcoarse. 1277 Propagation of the user context for `KSPSetComputeOperators()` on the sub `KSP` is attempted by querying the `DM` contexts associated with 1278 dmfine and dmcoarse. Alternatively, the user may use `PetscObjectComposeFunction()` with dmcoarse to define a method which will return the appropriate user context for `KSPSetComputeOperators()`. 1279 Currently there is no support for the flag `-pc_use_amat`. 1280 This setup can be invoked by the option `-pc_telescope_use_coarse_dm` or by calling `PCTelescopeSetUseCoarseDM`(pc,`PETSC_TRUE`); 1281 Further information about the user-provided methods required by this setup type are described here `PCTelescopeSetUseCoarseDM()`. 1282 1283 Developer Notes: 1284 During `PCSetUp()`, the B operator is scattered onto c'. 1285 Within `PCApply()`, the RHS vector (x) is scattered into a redundant vector, xred (defined on c'). 1286 Then, `KSPSolve()` is executed on the c' communicator. 1287 1288 The communicator used within the telescoping preconditioner is defined by a `PetscSubcomm` using the INTERLACED 1289 creation routine by default (this can be changed with `-pc_telescope_subcomm_type`). We run the sub `KSP` on only 1290 the ranks within the communicator which have a color equal to zero. 1291 1292 The telescoping preconditioner is aware of nullspaces and near nullspaces which are attached to the B operator. 1293 In the case where B has a (near) nullspace attached, the (near) nullspace vectors are extracted from B and mapped into 1294 a new (near) nullspace, defined on the sub-communicator, which is attached to B' (the B operator which was scattered to c') 1295 1296 The telescoping preconditioner can re-partition an attached `DM` if it is a `DMDA` (2D or 3D - 1297 support for 1D `DMDA`s is not provided). If a `DMDA` is found, a topologically equivalent `DMDA` is created on c' 1298 and this new `DM` is attached the sub `KSP`. The design of telescope is such that it should be possible to extend support 1299 for re-partitioning other to `DM`'s (e.g. `DMPLEX`). The user can supply a flag to ignore attached DMs. 1300 Alternatively, user-provided re-partitioned `DM`s can be used via `-pc_telescope_use_coarse_dm`. 1301 1302 With the default setup mode, B' is defined by fusing rows (in order) associated with MPI processes common to c and c'. 1303 1304 When a `DMDA` is attached to the parent preconditioner, B' is defined by: (i) performing a symmetric permutation of B 1305 into the ordering defined by the `DMDA` on c', (ii) extracting the local chunks via `MatCreateSubMatrices()`, (iii) fusing the 1306 locally (sequential) matrices defined on the ranks common to c and c' into B' using `MatCreateMPIMatConcatenateSeqMat()` 1307 1308 Limitations/improvements include the following. 1309 `VecPlaceArray()` could be used within `PCApply()` to improve efficiency and reduce memory usage. 1310 A unified mechanism to query for user contexts as required by `KSPSetComputeOperators()` and `MatNullSpaceSetFunction()`. 1311 1312 The symmetric permutation used when a `DMDA` is encountered is performed via explicitly assembling a permutation matrix P, 1313 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 1314 `VecPermute()` does not support the use case required here. By computing P, one can permute both the operator and RHS in a 1315 consistent manner. 1316 1317 Mapping of vectors (default setup mode) is performed in the following way. 1318 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. 1319 Using the interlaced creation routine, the ranks in c with color = 0 will be rank 0 and 2. 1320 We perform the scatter to the sub-communicator in the following way. 1321 [1] Given a vector x defined on communicator c 1322 1323 .vb 1324 rank(c) local values of x 1325 ------- ---------------------------------------- 1326 0 [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ] 1327 1 [ 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 ] 1328 2 [ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0 ] 1329 3 [ 18.0, 19.0, 20.0, 21.0, 22.0, 23.0 ] 1330 .ve 1331 1332 scatter into xtmp defined also on comm c, so that we have the following values 1333 1334 .vb 1335 rank(c) local values of xtmp 1336 ------- ---------------------------------------------------------------------------- 1337 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 ] 1338 1 [ ] 1339 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 ] 1340 3 [ ] 1341 .ve 1342 1343 The entries on rank 1 and 3 (ranks which do not have a color = 0 in c') have no values 1344 1345 [2] Copy the values from ranks 0, 2 (indices with respect to comm c) into the vector xred which is defined on communicator c'. 1346 Ranks 0 and 2 are the only ranks in the subcomm which have a color = 0. 1347 1348 .vb 1349 rank(c') local values of xred 1350 -------- ---------------------------------------------------------------------------- 1351 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 ] 1352 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 ] 1353 .ve 1354 1355 Contributed by: 1356 Dave May 1357 1358 .seealso: [](ch_ksp), `PCTelescopeGetKSP()`, `PCTelescopeGetDM()`, `PCTelescopeGetReductionFactor()`, `PCTelescopeSetReductionFactor()`, `PCTelescopeGetIgnoreDM()`, `PCTelescopeSetIgnoreDM()`, `PCREDUNDANT` 1359 M*/ 1360 PETSC_EXTERN PetscErrorCode PCCreate_Telescope(PC pc) 1361 { 1362 struct _PC_Telescope *sred; 1363 1364 PetscFunctionBegin; 1365 PetscCall(PetscNew(&sred)); 1366 sred->psubcomm = NULL; 1367 sred->subcommtype = PETSC_SUBCOMM_INTERLACED; 1368 sred->subcomm = MPI_COMM_NULL; 1369 sred->redfactor = 1; 1370 sred->ignore_dm = PETSC_FALSE; 1371 sred->ignore_kspcomputeoperators = PETSC_FALSE; 1372 sred->use_coarse_dm = PETSC_FALSE; 1373 pc->data = (void *)sred; 1374 1375 pc->ops->apply = PCApply_Telescope; 1376 pc->ops->applytranspose = NULL; 1377 pc->ops->applyrichardson = PCApplyRichardson_Telescope; 1378 pc->ops->setup = PCSetUp_Telescope; 1379 pc->ops->destroy = PCDestroy_Telescope; 1380 pc->ops->reset = PCReset_Telescope; 1381 pc->ops->setfromoptions = PCSetFromOptions_Telescope; 1382 pc->ops->view = PCView_Telescope; 1383 1384 sred->pctelescope_setup_type = PCTelescopeSetUp_default; 1385 sred->pctelescope_matcreate_type = PCTelescopeMatCreate_default; 1386 sred->pctelescope_matnullspacecreate_type = PCTelescopeMatNullSpaceCreate_default; 1387 sred->pctelescope_reset_type = NULL; 1388 1389 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetKSP_C", PCTelescopeGetKSP_Telescope)); 1390 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetSubcommType_C", PCTelescopeGetSubcommType_Telescope)); 1391 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetSubcommType_C", PCTelescopeSetSubcommType_Telescope)); 1392 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetReductionFactor_C", PCTelescopeGetReductionFactor_Telescope)); 1393 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetReductionFactor_C", PCTelescopeSetReductionFactor_Telescope)); 1394 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreDM_C", PCTelescopeGetIgnoreDM_Telescope)); 1395 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreDM_C", PCTelescopeSetIgnoreDM_Telescope)); 1396 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetIgnoreKSPComputeOperators_C", PCTelescopeGetIgnoreKSPComputeOperators_Telescope)); 1397 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetIgnoreKSPComputeOperators_C", PCTelescopeSetIgnoreKSPComputeOperators_Telescope)); 1398 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetDM_C", PCTelescopeGetDM_Telescope)); 1399 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeGetUseCoarseDM_C", PCTelescopeGetUseCoarseDM_Telescope)); 1400 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCTelescopeSetUseCoarseDM_C", PCTelescopeSetUseCoarseDM_Telescope)); 1401 PetscFunctionReturn(PETSC_SUCCESS); 1402 } 1403