1 2 #include <petsc/private/matimpl.h> 3 #include <petsc/private/pcimpl.h> 4 #include <petsc/private/dmimpl.h> 5 #include <petscksp.h> /*I "petscksp.h" I*/ 6 #include <petscdm.h> 7 #include <petscdmda.h> 8 9 #include "../src/ksp/pc/impls/telescope/telescope.h" 10 11 static PetscBool cited = PETSC_FALSE; 12 static const char citation[] = 13 "@inproceedings{MaySananRuppKnepleySmith2016,\n" 14 " title = {Extreme-Scale Multigrid Components within PETSc},\n" 15 " author = {Dave A. May and Patrick Sanan and Karl Rupp and Matthew G. Knepley and Barry F. Smith},\n" 16 " booktitle = {Proceedings of the Platform for Advanced Scientific Computing Conference},\n" 17 " series = {PASC '16},\n" 18 " isbn = {978-1-4503-4126-4},\n" 19 " location = {Lausanne, Switzerland},\n" 20 " pages = {5:1--5:12},\n" 21 " articleno = {5},\n" 22 " numpages = {12},\n" 23 " url = {https://doi.acm.org/10.1145/2929908.2929913},\n" 24 " doi = {10.1145/2929908.2929913},\n" 25 " acmid = {2929913},\n" 26 " publisher = {ACM},\n" 27 " address = {New York, NY, USA},\n" 28 " keywords = {GPU, HPC, agglomeration, coarse-level solver, multigrid, parallel computing, preconditioning},\n" 29 " year = {2016}\n" 30 "}\n"; 31 32 static PetscErrorCode _DMDADetermineRankFromGlobalIJK(PetscInt dim,PetscInt i,PetscInt j,PetscInt k, 33 PetscInt Mp,PetscInt Np,PetscInt Pp, 34 PetscInt start_i[],PetscInt start_j[],PetscInt start_k[], 35 PetscInt span_i[],PetscInt span_j[],PetscInt span_k[], 36 PetscMPIInt *_pi,PetscMPIInt *_pj,PetscMPIInt *_pk,PetscMPIInt *rank_re) 37 { 38 PetscInt pi,pj,pk,n; 39 40 PetscFunctionBegin; 41 *rank_re = -1; 42 if (_pi) *_pi = -1; 43 if (_pj) *_pj = -1; 44 if (_pk) *_pk = -1; 45 pi = pj = pk = -1; 46 if (_pi) { 47 for (n=0; n<Mp; n++) { 48 if ((i >= start_i[n]) && (i < start_i[n]+span_i[n])) { 49 pi = n; 50 break; 51 } 52 } 53 PetscCheckFalse(pi == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pi cannot be determined : range %D, val %D",Mp,i); 54 *_pi = pi; 55 } 56 57 if (_pj) { 58 for (n=0; n<Np; n++) { 59 if ((j >= start_j[n]) && (j < start_j[n]+span_j[n])) { 60 pj = n; 61 break; 62 } 63 } 64 PetscCheckFalse(pj == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pj cannot be determined : range %D, val %D",Np,j); 65 *_pj = pj; 66 } 67 68 if (_pk) { 69 for (n=0; n<Pp; n++) { 70 if ((k >= start_k[n]) && (k < start_k[n]+span_k[n])) { 71 pk = n; 72 break; 73 } 74 } 75 PetscCheckFalse(pk == -1,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmda-ijk] pk cannot be determined : range %D, val %D",Pp,k); 76 *_pk = pk; 77 } 78 79 switch (dim) { 80 case 1: 81 *rank_re = pi; 82 break; 83 case 2: 84 *rank_re = pi + pj * Mp; 85 break; 86 case 3: 87 *rank_re = pi + pj * Mp + pk * (Mp*Np); 88 break; 89 } 90 PetscFunctionReturn(0); 91 } 92 93 static PetscErrorCode _DMDADetermineGlobalS0(PetscInt dim,PetscMPIInt rank_re,PetscInt Mp_re,PetscInt Np_re,PetscInt Pp_re, 94 PetscInt range_i_re[],PetscInt range_j_re[],PetscInt range_k_re[],PetscInt *s0) 95 { 96 PetscInt i,j,k,start_IJK = 0; 97 PetscInt rank_ijk; 98 99 PetscFunctionBegin; 100 switch (dim) { 101 case 1: 102 for (i=0; i<Mp_re; i++) { 103 rank_ijk = i; 104 if (rank_ijk < rank_re) { 105 start_IJK += range_i_re[i]; 106 } 107 } 108 break; 109 case 2: 110 for (j=0; j<Np_re; j++) { 111 for (i=0; i<Mp_re; i++) { 112 rank_ijk = i + j*Mp_re; 113 if (rank_ijk < rank_re) { 114 start_IJK += range_i_re[i]*range_j_re[j]; 115 } 116 } 117 } 118 break; 119 case 3: 120 for (k=0; k<Pp_re; k++) { 121 for (j=0; j<Np_re; j++) { 122 for (i=0; i<Mp_re; i++) { 123 rank_ijk = i + j*Mp_re + k*Mp_re*Np_re; 124 if (rank_ijk < rank_re) { 125 start_IJK += range_i_re[i]*range_j_re[j]*range_k_re[k]; 126 } 127 } 128 } 129 } 130 break; 131 } 132 *s0 = start_IJK; 133 PetscFunctionReturn(0); 134 } 135 136 static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors2d(PC_Telescope sred,DM dm,DM subdm) 137 { 138 DM cdm; 139 Vec coor,coor_natural,perm_coors; 140 PetscInt i,j,si,sj,ni,nj,M,N,Ml,Nl,c,nidx; 141 PetscInt *fine_indices; 142 IS is_fine,is_local; 143 VecScatter sctx; 144 145 PetscFunctionBegin; 146 PetscCall(DMGetCoordinates(dm,&coor)); 147 if (!coor) return(0); 148 if (PCTelescope_isActiveRank(sred)) { 149 PetscCall(DMDASetUniformCoordinates(subdm,0.0,1.0,0.0,1.0,0.0,1.0)); 150 } 151 /* Get the coordinate vector from the distributed array */ 152 PetscCall(DMGetCoordinateDM(dm,&cdm)); 153 PetscCall(DMDACreateNaturalVector(cdm,&coor_natural)); 154 155 PetscCall(DMDAGlobalToNaturalBegin(cdm,coor,INSERT_VALUES,coor_natural)); 156 PetscCall(DMDAGlobalToNaturalEnd(cdm,coor,INSERT_VALUES,coor_natural)); 157 158 /* get indices of the guys I want to grab */ 159 PetscCall(DMDAGetInfo(dm,NULL,&M,&N,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 160 if (PCTelescope_isActiveRank(sred)) { 161 PetscCall(DMDAGetCorners(subdm,&si,&sj,NULL,&ni,&nj,NULL)); 162 Ml = ni; 163 Nl = nj; 164 } else { 165 si = sj = 0; 166 ni = nj = 0; 167 Ml = Nl = 0; 168 } 169 170 PetscCall(PetscMalloc1(Ml*Nl*2,&fine_indices)); 171 c = 0; 172 if (PCTelescope_isActiveRank(sred)) { 173 for (j=sj; j<sj+nj; j++) { 174 for (i=si; i<si+ni; i++) { 175 nidx = (i) + (j)*M; 176 fine_indices[c ] = 2 * nidx ; 177 fine_indices[c+1] = 2 * nidx + 1 ; 178 c = c + 2; 179 } 180 } 181 PetscCheckFalse(c != Ml*Nl*2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"c %D should equal 2 * Ml %D * Nl %D",c,Ml,Nl); 182 } 183 184 /* generate scatter */ 185 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm),Ml*Nl*2,fine_indices,PETSC_USE_POINTER,&is_fine)); 186 PetscCall(ISCreateStride(PETSC_COMM_SELF,Ml*Nl*2,0,1,&is_local)); 187 188 /* scatter */ 189 PetscCall(VecCreate(PETSC_COMM_SELF,&perm_coors)); 190 PetscCall(VecSetSizes(perm_coors,PETSC_DECIDE,Ml*Nl*2)); 191 PetscCall(VecSetType(perm_coors,VECSEQ)); 192 193 PetscCall(VecScatterCreate(coor_natural,is_fine,perm_coors,is_local,&sctx)); 194 PetscCall(VecScatterBegin(sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD)); 195 PetscCall(VecScatterEnd( sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD)); 196 /* access */ 197 if (PCTelescope_isActiveRank(sred)) { 198 Vec _coors; 199 const PetscScalar *LA_perm; 200 PetscScalar *LA_coors; 201 202 PetscCall(DMGetCoordinates(subdm,&_coors)); 203 PetscCall(VecGetArrayRead(perm_coors,&LA_perm)); 204 PetscCall(VecGetArray(_coors,&LA_coors)); 205 for (i=0; i<Ml*Nl*2; i++) { 206 LA_coors[i] = LA_perm[i]; 207 } 208 PetscCall(VecRestoreArray(_coors,&LA_coors)); 209 PetscCall(VecRestoreArrayRead(perm_coors,&LA_perm)); 210 } 211 212 /* update local coords */ 213 if (PCTelescope_isActiveRank(sred)) { 214 DM _dmc; 215 Vec _coors,_coors_local; 216 PetscCall(DMGetCoordinateDM(subdm,&_dmc)); 217 PetscCall(DMGetCoordinates(subdm,&_coors)); 218 PetscCall(DMGetCoordinatesLocal(subdm,&_coors_local)); 219 PetscCall(DMGlobalToLocalBegin(_dmc,_coors,INSERT_VALUES,_coors_local)); 220 PetscCall(DMGlobalToLocalEnd(_dmc,_coors,INSERT_VALUES,_coors_local)); 221 } 222 PetscCall(VecScatterDestroy(&sctx)); 223 PetscCall(ISDestroy(&is_fine)); 224 PetscCall(PetscFree(fine_indices)); 225 PetscCall(ISDestroy(&is_local)); 226 PetscCall(VecDestroy(&perm_coors)); 227 PetscCall(VecDestroy(&coor_natural)); 228 PetscFunctionReturn(0); 229 } 230 231 static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors3d(PC_Telescope sred,DM dm,DM subdm) 232 { 233 DM cdm; 234 Vec coor,coor_natural,perm_coors; 235 PetscInt i,j,k,si,sj,sk,ni,nj,nk,M,N,P,Ml,Nl,Pl,c,nidx; 236 PetscInt *fine_indices; 237 IS is_fine,is_local; 238 VecScatter sctx; 239 240 PetscFunctionBegin; 241 PetscCall(DMGetCoordinates(dm,&coor)); 242 if (!coor) PetscFunctionReturn(0); 243 244 if (PCTelescope_isActiveRank(sred)) { 245 PetscCall(DMDASetUniformCoordinates(subdm,0.0,1.0,0.0,1.0,0.0,1.0)); 246 } 247 248 /* Get the coordinate vector from the distributed array */ 249 PetscCall(DMGetCoordinateDM(dm,&cdm)); 250 PetscCall(DMDACreateNaturalVector(cdm,&coor_natural)); 251 PetscCall(DMDAGlobalToNaturalBegin(cdm,coor,INSERT_VALUES,coor_natural)); 252 PetscCall(DMDAGlobalToNaturalEnd(cdm,coor,INSERT_VALUES,coor_natural)); 253 254 /* get indices of the guys I want to grab */ 255 PetscCall(DMDAGetInfo(dm,NULL,&M,&N,&P,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 256 257 if (PCTelescope_isActiveRank(sred)) { 258 PetscCall(DMDAGetCorners(subdm,&si,&sj,&sk,&ni,&nj,&nk)); 259 Ml = ni; 260 Nl = nj; 261 Pl = nk; 262 } else { 263 si = sj = sk = 0; 264 ni = nj = nk = 0; 265 Ml = Nl = Pl = 0; 266 } 267 268 PetscCall(PetscMalloc1(Ml*Nl*Pl*3,&fine_indices)); 269 270 c = 0; 271 if (PCTelescope_isActiveRank(sred)) { 272 for (k=sk; k<sk+nk; k++) { 273 for (j=sj; j<sj+nj; j++) { 274 for (i=si; i<si+ni; i++) { 275 nidx = (i) + (j)*M + (k)*M*N; 276 fine_indices[c ] = 3 * nidx ; 277 fine_indices[c+1] = 3 * nidx + 1 ; 278 fine_indices[c+2] = 3 * nidx + 2 ; 279 c = c + 3; 280 } 281 } 282 } 283 } 284 285 /* generate scatter */ 286 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm),Ml*Nl*Pl*3,fine_indices,PETSC_USE_POINTER,&is_fine)); 287 PetscCall(ISCreateStride(PETSC_COMM_SELF,Ml*Nl*Pl*3,0,1,&is_local)); 288 289 /* scatter */ 290 PetscCall(VecCreate(PETSC_COMM_SELF,&perm_coors)); 291 PetscCall(VecSetSizes(perm_coors,PETSC_DECIDE,Ml*Nl*Pl*3)); 292 PetscCall(VecSetType(perm_coors,VECSEQ)); 293 PetscCall(VecScatterCreate(coor_natural,is_fine,perm_coors,is_local,&sctx)); 294 PetscCall(VecScatterBegin(sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD)); 295 PetscCall(VecScatterEnd( sctx,coor_natural,perm_coors,INSERT_VALUES,SCATTER_FORWARD)); 296 297 /* access */ 298 if (PCTelescope_isActiveRank(sred)) { 299 Vec _coors; 300 const PetscScalar *LA_perm; 301 PetscScalar *LA_coors; 302 303 PetscCall(DMGetCoordinates(subdm,&_coors)); 304 PetscCall(VecGetArrayRead(perm_coors,&LA_perm)); 305 PetscCall(VecGetArray(_coors,&LA_coors)); 306 for (i=0; i<Ml*Nl*Pl*3; i++) { 307 LA_coors[i] = LA_perm[i]; 308 } 309 PetscCall(VecRestoreArray(_coors,&LA_coors)); 310 PetscCall(VecRestoreArrayRead(perm_coors,&LA_perm)); 311 } 312 313 /* update local coords */ 314 if (PCTelescope_isActiveRank(sred)) { 315 DM _dmc; 316 Vec _coors,_coors_local; 317 318 PetscCall(DMGetCoordinateDM(subdm,&_dmc)); 319 PetscCall(DMGetCoordinates(subdm,&_coors)); 320 PetscCall(DMGetCoordinatesLocal(subdm,&_coors_local)); 321 PetscCall(DMGlobalToLocalBegin(_dmc,_coors,INSERT_VALUES,_coors_local)); 322 PetscCall(DMGlobalToLocalEnd(_dmc,_coors,INSERT_VALUES,_coors_local)); 323 } 324 325 PetscCall(VecScatterDestroy(&sctx)); 326 PetscCall(ISDestroy(&is_fine)); 327 PetscCall(PetscFree(fine_indices)); 328 PetscCall(ISDestroy(&is_local)); 329 PetscCall(VecDestroy(&perm_coors)); 330 PetscCall(VecDestroy(&coor_natural)); 331 PetscFunctionReturn(0); 332 } 333 334 static PetscErrorCode PCTelescopeSetUp_dmda_repart_coors(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx) 335 { 336 PetscInt dim; 337 DM dm,subdm; 338 PetscSubcomm psubcomm; 339 MPI_Comm comm; 340 Vec coor; 341 342 PetscFunctionBegin; 343 PetscCall(PCGetDM(pc,&dm)); 344 PetscCall(DMGetCoordinates(dm,&coor)); 345 if (!coor) PetscFunctionReturn(0); 346 psubcomm = sred->psubcomm; 347 comm = PetscSubcommParent(psubcomm); 348 subdm = ctx->dmrepart; 349 350 PetscCall(PetscInfo(pc,"PCTelescope: setting up the coordinates (DMDA)\n")); 351 PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 352 switch (dim) { 353 case 1: 354 SETERRQ(comm,PETSC_ERR_SUP,"Telescope: DMDA (1D) repartitioning not provided"); 355 case 2: PetscCall(PCTelescopeSetUp_dmda_repart_coors2d(sred,dm,subdm)); 356 break; 357 case 3: PetscCall(PCTelescopeSetUp_dmda_repart_coors3d(sred,dm,subdm)); 358 break; 359 } 360 PetscFunctionReturn(0); 361 } 362 363 /* setup repartitioned dm */ 364 PetscErrorCode PCTelescopeSetUp_dmda_repart(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx) 365 { 366 DM dm; 367 PetscInt dim,nx,ny,nz,ndof,nsw,sum,k; 368 DMBoundaryType bx,by,bz; 369 DMDAStencilType stencil; 370 const PetscInt *_range_i_re; 371 const PetscInt *_range_j_re; 372 const PetscInt *_range_k_re; 373 DMDAInterpolationType itype; 374 PetscInt refine_x,refine_y,refine_z; 375 MPI_Comm comm,subcomm; 376 const char *prefix; 377 378 PetscFunctionBegin; 379 comm = PetscSubcommParent(sred->psubcomm); 380 subcomm = PetscSubcommChild(sred->psubcomm); 381 PetscCall(PCGetDM(pc,&dm)); 382 383 PetscCall(DMDAGetInfo(dm,&dim,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,&nsw,&bx,&by,&bz,&stencil)); 384 PetscCall(DMDAGetInterpolationType(dm,&itype)); 385 PetscCall(DMDAGetRefinementFactor(dm,&refine_x,&refine_y,&refine_z)); 386 387 ctx->dmrepart = NULL; 388 _range_i_re = _range_j_re = _range_k_re = NULL; 389 /* Create DMDA on the child communicator */ 390 if (PCTelescope_isActiveRank(sred)) { 391 switch (dim) { 392 case 1: 393 PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (1D)\n")); 394 /* PetscCall(DMDACreate1d(subcomm,bx,nx,ndof,nsw,NULL,&ctx->dmrepart)); */ 395 ny = nz = 1; 396 by = bz = DM_BOUNDARY_NONE; 397 break; 398 case 2: 399 PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (2D)\n")); 400 /* PetscCall(DMDACreate2d(subcomm,bx,by,stencil,nx,ny, PETSC_DECIDE,PETSC_DECIDE, 401 ndof,nsw, NULL,NULL,&ctx->dmrepart)); */ 402 nz = 1; 403 bz = DM_BOUNDARY_NONE; 404 break; 405 case 3: 406 PetscCall(PetscInfo(pc,"PCTelescope: setting up the DMDA on comm subset (3D)\n")); 407 /* PetscCall(DMDACreate3d(subcomm,bx,by,bz,stencil,nx,ny,nz, 408 PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE, ndof,nsw, NULL,NULL,NULL,&ctx->dmrepart)); */ 409 break; 410 } 411 /* 412 The API DMDACreate1d(), DMDACreate2d(), DMDACreate3d() does not allow us to set/append 413 a unique option prefix for the DM, thus I prefer to expose the contents of these API's here. 414 This allows users to control the partitioning of the subDM. 415 */ 416 PetscCall(DMDACreate(subcomm,&ctx->dmrepart)); 417 /* Set unique option prefix name */ 418 PetscCall(KSPGetOptionsPrefix(sred->ksp,&prefix)); 419 PetscCall(DMSetOptionsPrefix(ctx->dmrepart,prefix)); 420 PetscCall(DMAppendOptionsPrefix(ctx->dmrepart,"repart_")); 421 /* standard setup from DMDACreate{1,2,3}d() */ 422 PetscCall(DMSetDimension(ctx->dmrepart,dim)); 423 PetscCall(DMDASetSizes(ctx->dmrepart,nx,ny,nz)); 424 PetscCall(DMDASetNumProcs(ctx->dmrepart,PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE)); 425 PetscCall(DMDASetBoundaryType(ctx->dmrepart,bx,by,bz)); 426 PetscCall(DMDASetDof(ctx->dmrepart,ndof)); 427 PetscCall(DMDASetStencilType(ctx->dmrepart,stencil)); 428 PetscCall(DMDASetStencilWidth(ctx->dmrepart,nsw)); 429 PetscCall(DMDASetOwnershipRanges(ctx->dmrepart,NULL,NULL,NULL)); 430 PetscCall(DMSetFromOptions(ctx->dmrepart)); 431 PetscCall(DMSetUp(ctx->dmrepart)); 432 /* Set refinement factors and interpolation type from the partent */ 433 PetscCall(DMDASetRefinementFactor(ctx->dmrepart,refine_x,refine_y,refine_z)); 434 PetscCall(DMDASetInterpolationType(ctx->dmrepart,itype)); 435 436 PetscCall(DMDAGetInfo(ctx->dmrepart,NULL,NULL,NULL,NULL,&ctx->Mp_re,&ctx->Np_re,&ctx->Pp_re,NULL,NULL,NULL,NULL,NULL,NULL)); 437 PetscCall(DMDAGetOwnershipRanges(ctx->dmrepart,&_range_i_re,&_range_j_re,&_range_k_re)); 438 439 ctx->dmrepart->ops->creatematrix = dm->ops->creatematrix; 440 ctx->dmrepart->ops->createdomaindecomposition = dm->ops->createdomaindecomposition; 441 } 442 443 /* generate ranges for repartitioned dm */ 444 /* note - assume rank 0 always participates */ 445 /* TODO: use a single MPI call */ 446 PetscCallMPI(MPI_Bcast(&ctx->Mp_re,1,MPIU_INT,0,comm)); 447 PetscCallMPI(MPI_Bcast(&ctx->Np_re,1,MPIU_INT,0,comm)); 448 PetscCallMPI(MPI_Bcast(&ctx->Pp_re,1,MPIU_INT,0,comm)); 449 450 PetscCall(PetscCalloc3(ctx->Mp_re,&ctx->range_i_re,ctx->Np_re,&ctx->range_j_re,ctx->Pp_re,&ctx->range_k_re)); 451 452 if (_range_i_re) PetscCall(PetscArraycpy(ctx->range_i_re,_range_i_re,ctx->Mp_re)); 453 if (_range_j_re) PetscCall(PetscArraycpy(ctx->range_j_re,_range_j_re,ctx->Np_re)); 454 if (_range_k_re) PetscCall(PetscArraycpy(ctx->range_k_re,_range_k_re,ctx->Pp_re)); 455 456 /* TODO: use a single MPI call */ 457 PetscCallMPI(MPI_Bcast(ctx->range_i_re,ctx->Mp_re,MPIU_INT,0,comm)); 458 PetscCallMPI(MPI_Bcast(ctx->range_j_re,ctx->Np_re,MPIU_INT,0,comm)); 459 PetscCallMPI(MPI_Bcast(ctx->range_k_re,ctx->Pp_re,MPIU_INT,0,comm)); 460 461 PetscCall(PetscMalloc3(ctx->Mp_re,&ctx->start_i_re,ctx->Np_re,&ctx->start_j_re,ctx->Pp_re,&ctx->start_k_re)); 462 463 sum = 0; 464 for (k=0; k<ctx->Mp_re; k++) { 465 ctx->start_i_re[k] = sum; 466 sum += ctx->range_i_re[k]; 467 } 468 469 sum = 0; 470 for (k=0; k<ctx->Np_re; k++) { 471 ctx->start_j_re[k] = sum; 472 sum += ctx->range_j_re[k]; 473 } 474 475 sum = 0; 476 for (k=0; k<ctx->Pp_re; k++) { 477 ctx->start_k_re[k] = sum; 478 sum += ctx->range_k_re[k]; 479 } 480 481 /* attach repartitioned dm to child ksp */ 482 { 483 PetscErrorCode (*dmksp_func)(KSP,Mat,Mat,void*); 484 void *dmksp_ctx; 485 486 PetscCall(DMKSPGetComputeOperators(dm,&dmksp_func,&dmksp_ctx)); 487 488 /* attach dm to ksp on sub communicator */ 489 if (PCTelescope_isActiveRank(sred)) { 490 PetscCall(KSPSetDM(sred->ksp,ctx->dmrepart)); 491 492 if (!dmksp_func || sred->ignore_kspcomputeoperators) { 493 PetscCall(KSPSetDMActive(sred->ksp,PETSC_FALSE)); 494 } else { 495 /* sub ksp inherits dmksp_func and context provided by user */ 496 PetscCall(KSPSetComputeOperators(sred->ksp,dmksp_func,dmksp_ctx)); 497 PetscCall(KSPSetDMActive(sred->ksp,PETSC_TRUE)); 498 } 499 } 500 } 501 PetscFunctionReturn(0); 502 } 503 504 PetscErrorCode PCTelescopeSetUp_dmda_permutation_3d(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx) 505 { 506 PetscErrorCode ierr; 507 DM dm; 508 MPI_Comm comm; 509 Mat Pscalar,P; 510 PetscInt ndof; 511 PetscInt i,j,k,location,startI[3],endI[3],lenI[3],nx,ny,nz; 512 PetscInt sr,er,Mr; 513 Vec V; 514 515 PetscFunctionBegin; 516 PetscCall(PetscInfo(pc,"PCTelescope: setting up the permutation matrix (DMDA-3D)\n")); 517 PetscCall(PetscObjectGetComm((PetscObject)pc,&comm)); 518 519 PetscCall(PCGetDM(pc,&dm)); 520 PetscCall(DMDAGetInfo(dm,NULL,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,NULL,NULL,NULL,NULL,NULL)); 521 522 PetscCall(DMGetGlobalVector(dm,&V)); 523 PetscCall(VecGetSize(V,&Mr)); 524 PetscCall(VecGetOwnershipRange(V,&sr,&er)); 525 PetscCall(DMRestoreGlobalVector(dm,&V)); 526 sr = sr / ndof; 527 er = er / ndof; 528 Mr = Mr / ndof; 529 530 PetscCall(MatCreate(comm,&Pscalar)); 531 PetscCall(MatSetSizes(Pscalar,(er-sr),(er-sr),Mr,Mr)); 532 PetscCall(MatSetType(Pscalar,MATAIJ)); 533 PetscCall(MatSeqAIJSetPreallocation(Pscalar,1,NULL)); 534 PetscCall(MatMPIAIJSetPreallocation(Pscalar,1,NULL,1,NULL)); 535 536 PetscCall(DMDAGetCorners(dm,NULL,NULL,NULL,&lenI[0],&lenI[1],&lenI[2])); 537 PetscCall(DMDAGetCorners(dm,&startI[0],&startI[1],&startI[2],&endI[0],&endI[1],&endI[2])); 538 endI[0] += startI[0]; 539 endI[1] += startI[1]; 540 endI[2] += startI[2]; 541 542 for (k=startI[2]; k<endI[2]; k++) { 543 for (j=startI[1]; j<endI[1]; j++) { 544 for (i=startI[0]; i<endI[0]; i++) { 545 PetscMPIInt rank_ijk_re,rank_reI[3]; 546 PetscInt s0_re; 547 PetscInt ii,jj,kk,local_ijk_re,mapped_ijk; 548 PetscInt lenI_re[3]; 549 550 location = (i - startI[0]) + (j - startI[1])*lenI[0] + (k - startI[2])*lenI[0]*lenI[1]; 551 ierr = _DMDADetermineRankFromGlobalIJK(3,i,j,k, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, 552 ctx->start_i_re,ctx->start_j_re,ctx->start_k_re, 553 ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, 554 &rank_reI[0],&rank_reI[1],&rank_reI[2],&rank_ijk_re);PetscCall(ierr); 555 PetscCall(_DMDADetermineGlobalS0(3,rank_ijk_re, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, &s0_re)); 556 ii = i - ctx->start_i_re[ rank_reI[0] ]; 557 PetscCheckFalse(ii < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error ii"); 558 jj = j - ctx->start_j_re[ rank_reI[1] ]; 559 PetscCheckFalse(jj < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error jj"); 560 kk = k - ctx->start_k_re[ rank_reI[2] ]; 561 PetscCheckFalse(kk < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm3d] index error kk"); 562 lenI_re[0] = ctx->range_i_re[ rank_reI[0] ]; 563 lenI_re[1] = ctx->range_j_re[ rank_reI[1] ]; 564 lenI_re[2] = ctx->range_k_re[ rank_reI[2] ]; 565 local_ijk_re = ii + jj * lenI_re[0] + kk * lenI_re[0] * lenI_re[1]; 566 mapped_ijk = s0_re + local_ijk_re; 567 PetscCall(MatSetValue(Pscalar,sr+location,mapped_ijk,1.0,INSERT_VALUES)); 568 } 569 } 570 } 571 PetscCall(MatAssemblyBegin(Pscalar,MAT_FINAL_ASSEMBLY)); 572 PetscCall(MatAssemblyEnd(Pscalar,MAT_FINAL_ASSEMBLY)); 573 PetscCall(MatCreateMAIJ(Pscalar,ndof,&P)); 574 PetscCall(MatDestroy(&Pscalar)); 575 ctx->permutation = P; 576 PetscFunctionReturn(0); 577 } 578 579 PetscErrorCode PCTelescopeSetUp_dmda_permutation_2d(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx) 580 { 581 PetscErrorCode ierr; 582 DM dm; 583 MPI_Comm comm; 584 Mat Pscalar,P; 585 PetscInt ndof; 586 PetscInt i,j,location,startI[2],endI[2],lenI[2],nx,ny,nz; 587 PetscInt sr,er,Mr; 588 Vec V; 589 590 PetscFunctionBegin; 591 PetscCall(PetscInfo(pc,"PCTelescope: setting up the permutation matrix (DMDA-2D)\n")); 592 PetscCall(PetscObjectGetComm((PetscObject)pc,&comm)); 593 PetscCall(PCGetDM(pc,&dm)); 594 PetscCall(DMDAGetInfo(dm,NULL,&nx,&ny,&nz,NULL,NULL,NULL,&ndof,NULL,NULL,NULL,NULL,NULL)); 595 PetscCall(DMGetGlobalVector(dm,&V)); 596 PetscCall(VecGetSize(V,&Mr)); 597 PetscCall(VecGetOwnershipRange(V,&sr,&er)); 598 PetscCall(DMRestoreGlobalVector(dm,&V)); 599 sr = sr / ndof; 600 er = er / ndof; 601 Mr = Mr / ndof; 602 603 PetscCall(MatCreate(comm,&Pscalar)); 604 PetscCall(MatSetSizes(Pscalar,(er-sr),(er-sr),Mr,Mr)); 605 PetscCall(MatSetType(Pscalar,MATAIJ)); 606 PetscCall(MatSeqAIJSetPreallocation(Pscalar,1,NULL)); 607 PetscCall(MatMPIAIJSetPreallocation(Pscalar,1,NULL,1,NULL)); 608 609 PetscCall(DMDAGetCorners(dm,NULL,NULL,NULL,&lenI[0],&lenI[1],NULL)); 610 PetscCall(DMDAGetCorners(dm,&startI[0],&startI[1],NULL,&endI[0],&endI[1],NULL)); 611 endI[0] += startI[0]; 612 endI[1] += startI[1]; 613 614 for (j=startI[1]; j<endI[1]; j++) { 615 for (i=startI[0]; i<endI[0]; i++) { 616 PetscMPIInt rank_ijk_re,rank_reI[3]; 617 PetscInt s0_re; 618 PetscInt ii,jj,local_ijk_re,mapped_ijk; 619 PetscInt lenI_re[3]; 620 621 location = (i - startI[0]) + (j - startI[1])*lenI[0]; 622 ierr = _DMDADetermineRankFromGlobalIJK(2,i,j,0, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, 623 ctx->start_i_re,ctx->start_j_re,ctx->start_k_re, 624 ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, 625 &rank_reI[0],&rank_reI[1],NULL,&rank_ijk_re);PetscCall(ierr); 626 627 PetscCall(_DMDADetermineGlobalS0(2,rank_ijk_re, ctx->Mp_re,ctx->Np_re,ctx->Pp_re, ctx->range_i_re,ctx->range_j_re,ctx->range_k_re, &s0_re)); 628 629 ii = i - ctx->start_i_re[ rank_reI[0] ]; 630 PetscCheckFalse(ii < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm2d] index error ii"); 631 jj = j - ctx->start_j_re[ rank_reI[1] ]; 632 PetscCheckFalse(jj < 0,PETSC_COMM_SELF,PETSC_ERR_USER,"[dmdarepart-perm2d] index error jj"); 633 634 lenI_re[0] = ctx->range_i_re[ rank_reI[0] ]; 635 lenI_re[1] = ctx->range_j_re[ rank_reI[1] ]; 636 local_ijk_re = ii + jj * lenI_re[0]; 637 mapped_ijk = s0_re + local_ijk_re; 638 PetscCall(MatSetValue(Pscalar,sr+location,mapped_ijk,1.0,INSERT_VALUES)); 639 } 640 } 641 PetscCall(MatAssemblyBegin(Pscalar,MAT_FINAL_ASSEMBLY)); 642 PetscCall(MatAssemblyEnd(Pscalar,MAT_FINAL_ASSEMBLY)); 643 PetscCall(MatCreateMAIJ(Pscalar,ndof,&P)); 644 PetscCall(MatDestroy(&Pscalar)); 645 ctx->permutation = P; 646 PetscFunctionReturn(0); 647 } 648 649 PetscErrorCode PCTelescopeSetUp_dmda_scatters(PC pc,PC_Telescope sred,PC_Telescope_DMDACtx *ctx) 650 { 651 Vec xred,yred,xtmp,x,xp; 652 VecScatter scatter; 653 IS isin; 654 Mat B; 655 PetscInt m,bs,st,ed; 656 MPI_Comm comm; 657 658 PetscFunctionBegin; 659 PetscCall(PetscObjectGetComm((PetscObject)pc,&comm)); 660 PetscCall(PCGetOperators(pc,NULL,&B)); 661 PetscCall(MatCreateVecs(B,&x,NULL)); 662 PetscCall(MatGetBlockSize(B,&bs)); 663 PetscCall(VecDuplicate(x,&xp)); 664 m = 0; 665 xred = NULL; 666 yred = NULL; 667 if (PCTelescope_isActiveRank(sred)) { 668 PetscCall(DMCreateGlobalVector(ctx->dmrepart,&xred)); 669 PetscCall(VecDuplicate(xred,&yred)); 670 PetscCall(VecGetOwnershipRange(xred,&st,&ed)); 671 PetscCall(ISCreateStride(comm,ed-st,st,1,&isin)); 672 PetscCall(VecGetLocalSize(xred,&m)); 673 } else { 674 PetscCall(VecGetOwnershipRange(x,&st,&ed)); 675 PetscCall(ISCreateStride(comm,0,st,1,&isin)); 676 } 677 PetscCall(ISSetBlockSize(isin,bs)); 678 PetscCall(VecCreate(comm,&xtmp)); 679 PetscCall(VecSetSizes(xtmp,m,PETSC_DECIDE)); 680 PetscCall(VecSetBlockSize(xtmp,bs)); 681 PetscCall(VecSetType(xtmp,((PetscObject)x)->type_name)); 682 PetscCall(VecScatterCreate(x,isin,xtmp,NULL,&scatter)); 683 sred->xred = xred; 684 sred->yred = yred; 685 sred->isin = isin; 686 sred->scatter = scatter; 687 sred->xtmp = xtmp; 688 689 ctx->xp = xp; 690 PetscCall(VecDestroy(&x)); 691 PetscFunctionReturn(0); 692 } 693 694 PetscErrorCode PCTelescopeSetUp_dmda(PC pc,PC_Telescope sred) 695 { 696 PC_Telescope_DMDACtx *ctx; 697 PetscInt dim; 698 DM dm; 699 MPI_Comm comm; 700 701 PetscFunctionBegin; 702 PetscCall(PetscInfo(pc,"PCTelescope: setup (DMDA)\n")); 703 PetscCall(PetscNew(&ctx)); 704 sred->dm_ctx = (void*)ctx; 705 706 PetscCall(PetscObjectGetComm((PetscObject)pc,&comm)); 707 PetscCall(PCGetDM(pc,&dm)); 708 PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 709 710 PCTelescopeSetUp_dmda_repart(pc,sred,ctx); 711 PCTelescopeSetUp_dmda_repart_coors(pc,sred,ctx); 712 switch (dim) { 713 case 1: 714 SETERRQ(comm,PETSC_ERR_SUP,"Telescope: DMDA (1D) repartitioning not provided"); 715 case 2: PetscCall(PCTelescopeSetUp_dmda_permutation_2d(pc,sred,ctx)); 716 break; 717 case 3: PetscCall(PCTelescopeSetUp_dmda_permutation_3d(pc,sred,ctx)); 718 break; 719 } 720 PetscCall(PCTelescopeSetUp_dmda_scatters(pc,sred,ctx)); 721 PetscFunctionReturn(0); 722 } 723 724 PetscErrorCode PCTelescopeMatCreate_dmda_dmactivefalse(PC pc,PC_Telescope sred,MatReuse reuse,Mat *A) 725 { 726 PC_Telescope_DMDACtx *ctx; 727 MPI_Comm comm,subcomm; 728 Mat Bperm,Bred,B,P; 729 PetscInt nr,nc; 730 IS isrow,iscol; 731 Mat Blocal,*_Blocal; 732 733 PetscFunctionBegin; 734 PetscCall(PetscInfo(pc,"PCTelescope: updating the redundant preconditioned operator (DMDA)\n")); 735 PetscCall(PetscObjectGetComm((PetscObject)pc,&comm)); 736 subcomm = PetscSubcommChild(sred->psubcomm); 737 ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx; 738 739 PetscCall(PCGetOperators(pc,NULL,&B)); 740 PetscCall(MatGetSize(B,&nr,&nc)); 741 742 P = ctx->permutation; 743 PetscCall(MatPtAP(B,P,MAT_INITIAL_MATRIX,1.1,&Bperm)); 744 745 /* Get submatrices */ 746 isrow = sred->isin; 747 PetscCall(ISCreateStride(comm,nc,0,1,&iscol)); 748 749 PetscCall(MatCreateSubMatrices(Bperm,1,&isrow,&iscol,MAT_INITIAL_MATRIX,&_Blocal)); 750 Blocal = *_Blocal; 751 Bred = NULL; 752 if (PCTelescope_isActiveRank(sred)) { 753 PetscInt mm; 754 755 if (reuse != MAT_INITIAL_MATRIX) {Bred = *A;} 756 PetscCall(MatGetSize(Blocal,&mm,NULL)); 757 /* PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,PETSC_DECIDE,reuse,&Bred)); */ 758 PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm,Blocal,mm,reuse,&Bred)); 759 } 760 *A = Bred; 761 762 PetscCall(ISDestroy(&iscol)); 763 PetscCall(MatDestroy(&Bperm)); 764 PetscCall(MatDestroyMatrices(1,&_Blocal)); 765 PetscFunctionReturn(0); 766 } 767 768 PetscErrorCode PCTelescopeMatCreate_dmda(PC pc,PC_Telescope sred,MatReuse reuse,Mat *A) 769 { 770 DM dm; 771 PetscErrorCode (*dmksp_func)(KSP,Mat,Mat,void*); 772 void *dmksp_ctx; 773 774 PetscFunctionBegin; 775 PetscCall(PCGetDM(pc,&dm)); 776 PetscCall(DMKSPGetComputeOperators(dm,&dmksp_func,&dmksp_ctx)); 777 /* We assume that dmksp_func = NULL, is equivalent to dmActive = PETSC_FALSE */ 778 if (dmksp_func && !sred->ignore_kspcomputeoperators) { 779 DM dmrepart; 780 Mat Ak; 781 782 *A = NULL; 783 if (PCTelescope_isActiveRank(sred)) { 784 PetscCall(KSPGetDM(sred->ksp,&dmrepart)); 785 if (reuse == MAT_INITIAL_MATRIX) { 786 PetscCall(DMCreateMatrix(dmrepart,&Ak)); 787 *A = Ak; 788 } else if (reuse == MAT_REUSE_MATRIX) { 789 Ak = *A; 790 } 791 /* 792 There is no need to explicitly assemble the operator now, 793 the sub-KSP will call the method provided to KSPSetComputeOperators() during KSPSetUp() 794 */ 795 } 796 } else { 797 PetscCall(PCTelescopeMatCreate_dmda_dmactivefalse(pc,sred,reuse,A)); 798 } 799 PetscFunctionReturn(0); 800 } 801 802 PetscErrorCode PCTelescopeSubNullSpaceCreate_dmda_Telescope(PC pc,PC_Telescope sred,MatNullSpace nullspace,MatNullSpace *sub_nullspace) 803 { 804 PetscBool has_const; 805 PetscInt i,k,n = 0; 806 const Vec *vecs; 807 Vec *sub_vecs = NULL; 808 MPI_Comm subcomm; 809 PC_Telescope_DMDACtx *ctx; 810 811 PetscFunctionBegin; 812 ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx; 813 subcomm = PetscSubcommChild(sred->psubcomm); 814 PetscCall(MatNullSpaceGetVecs(nullspace,&has_const,&n,&vecs)); 815 816 if (PCTelescope_isActiveRank(sred)) { 817 /* create new vectors */ 818 if (n) { 819 PetscCall(VecDuplicateVecs(sred->xred,n,&sub_vecs)); 820 } 821 } 822 823 /* copy entries */ 824 for (k=0; k<n; k++) { 825 const PetscScalar *x_array; 826 PetscScalar *LA_sub_vec; 827 PetscInt st,ed; 828 829 /* permute vector into ordering associated with re-partitioned dmda */ 830 PetscCall(MatMultTranspose(ctx->permutation,vecs[k],ctx->xp)); 831 832 /* pull in vector x->xtmp */ 833 PetscCall(VecScatterBegin(sred->scatter,ctx->xp,sred->xtmp,INSERT_VALUES,SCATTER_FORWARD)); 834 PetscCall(VecScatterEnd(sred->scatter,ctx->xp,sred->xtmp,INSERT_VALUES,SCATTER_FORWARD)); 835 836 /* copy vector entries into xred */ 837 PetscCall(VecGetArrayRead(sred->xtmp,&x_array)); 838 if (sub_vecs) { 839 if (sub_vecs[k]) { 840 PetscCall(VecGetOwnershipRange(sub_vecs[k],&st,&ed)); 841 PetscCall(VecGetArray(sub_vecs[k],&LA_sub_vec)); 842 for (i=0; i<ed-st; i++) { 843 LA_sub_vec[i] = x_array[i]; 844 } 845 PetscCall(VecRestoreArray(sub_vecs[k],&LA_sub_vec)); 846 } 847 } 848 PetscCall(VecRestoreArrayRead(sred->xtmp,&x_array)); 849 } 850 851 if (PCTelescope_isActiveRank(sred)) { 852 /* create new (near) nullspace for redundant object */ 853 PetscCall(MatNullSpaceCreate(subcomm,has_const,n,sub_vecs,sub_nullspace)); 854 PetscCall(VecDestroyVecs(n,&sub_vecs)); 855 PetscCheck(!nullspace->remove,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Propagation of custom remove callbacks not supported when propagating (near) nullspaces with PCTelescope"); 856 PetscCheck(!nullspace->rmctx,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Propagation of custom remove callback context not supported when propagating (near) nullspaces with PCTelescope"); 857 } 858 PetscFunctionReturn(0); 859 } 860 861 PetscErrorCode PCTelescopeMatNullSpaceCreate_dmda(PC pc,PC_Telescope sred,Mat sub_mat) 862 { 863 Mat B; 864 865 PetscFunctionBegin; 866 PetscCall(PCGetOperators(pc,NULL,&B)); 867 { 868 MatNullSpace nullspace,sub_nullspace; 869 PetscCall(MatGetNullSpace(B,&nullspace)); 870 if (nullspace) { 871 PetscCall(PetscInfo(pc,"PCTelescope: generating nullspace (DMDA)\n")); 872 PetscCall(PCTelescopeSubNullSpaceCreate_dmda_Telescope(pc,sred,nullspace,&sub_nullspace)); 873 if (PCTelescope_isActiveRank(sred)) { 874 PetscCall(MatSetNullSpace(sub_mat,sub_nullspace)); 875 PetscCall(MatNullSpaceDestroy(&sub_nullspace)); 876 } 877 } 878 } 879 { 880 MatNullSpace nearnullspace,sub_nearnullspace; 881 PetscCall(MatGetNearNullSpace(B,&nearnullspace)); 882 if (nearnullspace) { 883 PetscCall(PetscInfo(pc,"PCTelescope: generating near nullspace (DMDA)\n")); 884 PetscCall(PCTelescopeSubNullSpaceCreate_dmda_Telescope(pc,sred,nearnullspace,&sub_nearnullspace)); 885 if (PCTelescope_isActiveRank(sred)) { 886 PetscCall(MatSetNearNullSpace(sub_mat,sub_nearnullspace)); 887 PetscCall(MatNullSpaceDestroy(&sub_nearnullspace)); 888 } 889 } 890 } 891 PetscFunctionReturn(0); 892 } 893 894 PetscErrorCode PCApply_Telescope_dmda(PC pc,Vec x,Vec y) 895 { 896 PC_Telescope sred = (PC_Telescope)pc->data; 897 Mat perm; 898 Vec xtmp,xp,xred,yred; 899 PetscInt i,st,ed; 900 VecScatter scatter; 901 PetscScalar *array; 902 const PetscScalar *x_array; 903 PC_Telescope_DMDACtx *ctx; 904 905 ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx; 906 xtmp = sred->xtmp; 907 scatter = sred->scatter; 908 xred = sred->xred; 909 yred = sred->yred; 910 perm = ctx->permutation; 911 xp = ctx->xp; 912 913 PetscFunctionBegin; 914 PetscCall(PetscCitationsRegister(citation,&cited)); 915 916 /* permute vector into ordering associated with re-partitioned dmda */ 917 PetscCall(MatMultTranspose(perm,x,xp)); 918 919 /* pull in vector x->xtmp */ 920 PetscCall(VecScatterBegin(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD)); 921 PetscCall(VecScatterEnd(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD)); 922 923 /* copy vector entries into xred */ 924 PetscCall(VecGetArrayRead(xtmp,&x_array)); 925 if (xred) { 926 PetscScalar *LA_xred; 927 PetscCall(VecGetOwnershipRange(xred,&st,&ed)); 928 929 PetscCall(VecGetArray(xred,&LA_xred)); 930 for (i=0; i<ed-st; i++) { 931 LA_xred[i] = x_array[i]; 932 } 933 PetscCall(VecRestoreArray(xred,&LA_xred)); 934 } 935 PetscCall(VecRestoreArrayRead(xtmp,&x_array)); 936 937 /* solve */ 938 if (PCTelescope_isActiveRank(sred)) { 939 PetscCall(KSPSolve(sred->ksp,xred,yred)); 940 PetscCall(KSPCheckSolve(sred->ksp,pc,yred)); 941 } 942 943 /* return vector */ 944 PetscCall(VecGetArray(xtmp,&array)); 945 if (yred) { 946 const PetscScalar *LA_yred; 947 PetscCall(VecGetOwnershipRange(yred,&st,&ed)); 948 PetscCall(VecGetArrayRead(yred,&LA_yred)); 949 for (i=0; i<ed-st; i++) { 950 array[i] = LA_yred[i]; 951 } 952 PetscCall(VecRestoreArrayRead(yred,&LA_yred)); 953 } 954 PetscCall(VecRestoreArray(xtmp,&array)); 955 PetscCall(VecScatterBegin(scatter,xtmp,xp,INSERT_VALUES,SCATTER_REVERSE)); 956 PetscCall(VecScatterEnd(scatter,xtmp,xp,INSERT_VALUES,SCATTER_REVERSE)); 957 PetscCall(MatMult(perm,xp,y)); 958 PetscFunctionReturn(0); 959 } 960 961 PetscErrorCode PCApplyRichardson_Telescope_dmda(PC pc,Vec x,Vec y,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason) 962 { 963 PC_Telescope sred = (PC_Telescope)pc->data; 964 Mat perm; 965 Vec xtmp,xp,yred; 966 PetscInt i,st,ed; 967 VecScatter scatter; 968 const PetscScalar *x_array; 969 PetscBool default_init_guess_value = PETSC_FALSE; 970 PC_Telescope_DMDACtx *ctx; 971 972 PetscFunctionBegin; 973 ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx; 974 xtmp = sred->xtmp; 975 scatter = sred->scatter; 976 yred = sred->yred; 977 perm = ctx->permutation; 978 xp = ctx->xp; 979 980 PetscCheckFalse(its > 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"PCApplyRichardson_Telescope_dmda only supports max_it = 1"); 981 *reason = (PCRichardsonConvergedReason)0; 982 983 if (!zeroguess) { 984 PetscCall(PetscInfo(pc,"PCTelescopeDMDA: Scattering y for non-zero-initial guess\n")); 985 /* permute vector into ordering associated with re-partitioned dmda */ 986 PetscCall(MatMultTranspose(perm,y,xp)); 987 988 /* pull in vector x->xtmp */ 989 PetscCall(VecScatterBegin(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD)); 990 PetscCall(VecScatterEnd(scatter,xp,xtmp,INSERT_VALUES,SCATTER_FORWARD)); 991 992 /* copy vector entries into xred */ 993 PetscCall(VecGetArrayRead(xtmp,&x_array)); 994 if (yred) { 995 PetscScalar *LA_yred; 996 PetscCall(VecGetOwnershipRange(yred,&st,&ed)); 997 PetscCall(VecGetArray(yred,&LA_yred)); 998 for (i=0; i<ed-st; i++) { 999 LA_yred[i] = x_array[i]; 1000 } 1001 PetscCall(VecRestoreArray(yred,&LA_yred)); 1002 } 1003 PetscCall(VecRestoreArrayRead(xtmp,&x_array)); 1004 } 1005 1006 if (PCTelescope_isActiveRank(sred)) { 1007 PetscCall(KSPGetInitialGuessNonzero(sred->ksp,&default_init_guess_value)); 1008 if (!zeroguess) PetscCall(KSPSetInitialGuessNonzero(sred->ksp,PETSC_TRUE)); 1009 } 1010 1011 PetscCall(PCApply_Telescope_dmda(pc,x,y)); 1012 1013 if (PCTelescope_isActiveRank(sred)) { 1014 PetscCall(KSPSetInitialGuessNonzero(sred->ksp,default_init_guess_value)); 1015 } 1016 1017 if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS; 1018 *outits = 1; 1019 PetscFunctionReturn(0); 1020 } 1021 1022 PetscErrorCode PCReset_Telescope_dmda(PC pc) 1023 { 1024 PC_Telescope sred = (PC_Telescope)pc->data; 1025 PC_Telescope_DMDACtx *ctx; 1026 1027 PetscFunctionBegin; 1028 ctx = (PC_Telescope_DMDACtx*)sred->dm_ctx; 1029 PetscCall(VecDestroy(&ctx->xp)); 1030 PetscCall(MatDestroy(&ctx->permutation)); 1031 PetscCall(DMDestroy(&ctx->dmrepart)); 1032 PetscCall(PetscFree3(ctx->range_i_re,ctx->range_j_re,ctx->range_k_re)); 1033 PetscCall(PetscFree3(ctx->start_i_re,ctx->start_j_re,ctx->start_k_re)); 1034 PetscFunctionReturn(0); 1035 } 1036 1037 PetscErrorCode DMView_DA_Short_3d(DM dm,PetscViewer v) 1038 { 1039 PetscInt M,N,P,m,n,p,ndof,nsw; 1040 MPI_Comm comm; 1041 PetscMPIInt size; 1042 const char* prefix; 1043 1044 PetscFunctionBegin; 1045 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1046 PetscCallMPI(MPI_Comm_size(comm,&size)); 1047 PetscCall(DMGetOptionsPrefix(dm,&prefix)); 1048 PetscCall(DMDAGetInfo(dm,NULL,&M,&N,&P,&m,&n,&p,&ndof,&nsw,NULL,NULL,NULL,NULL)); 1049 if (prefix) PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object: (%s) %d MPI processes\n",prefix,size)); 1050 else PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object: %d MPI processes\n",size)); 1051 PetscCall(PetscViewerASCIIPrintf(v," M %D N %D P %D m %D n %D p %D dof %D overlap %D\n",M,N,P,m,n,p,ndof,nsw)); 1052 PetscFunctionReturn(0); 1053 } 1054 1055 PetscErrorCode DMView_DA_Short_2d(DM dm,PetscViewer v) 1056 { 1057 PetscInt M,N,m,n,ndof,nsw; 1058 MPI_Comm comm; 1059 PetscMPIInt size; 1060 const char* prefix; 1061 1062 PetscFunctionBegin; 1063 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1064 PetscCallMPI(MPI_Comm_size(comm,&size)); 1065 PetscCall(DMGetOptionsPrefix(dm,&prefix)); 1066 PetscCall(DMDAGetInfo(dm,NULL,&M,&N,NULL,&m,&n,NULL,&ndof,&nsw,NULL,NULL,NULL,NULL)); 1067 if (prefix) PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object: (%s) %d MPI processes\n",prefix,size)); 1068 else PetscCall(PetscViewerASCIIPrintf(v,"DMDA Object: %d MPI processes\n",size)); 1069 PetscCall(PetscViewerASCIIPrintf(v," M %D N %D m %D n %D dof %D overlap %D\n",M,N,m,n,ndof,nsw)); 1070 PetscFunctionReturn(0); 1071 } 1072 1073 PetscErrorCode DMView_DA_Short(DM dm,PetscViewer v) 1074 { 1075 PetscInt dim; 1076 1077 PetscFunctionBegin; 1078 PetscCall(DMDAGetInfo(dm,&dim,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 1079 switch (dim) { 1080 case 2: PetscCall(DMView_DA_Short_2d(dm,v)); 1081 break; 1082 case 3: PetscCall(DMView_DA_Short_3d(dm,v)); 1083 break; 1084 } 1085 PetscFunctionReturn(0); 1086 } 1087