1 #include <private/daimpl.h> /*I "petscdmda.h" I*/ 2 3 4 #undef __FUNCT__ 5 #define __FUNCT__ "DMDASetDim" 6 /*@ 7 DMDASetDim - Sets the dimension 8 9 Collective on DMDA 10 11 Input Parameters: 12 + da - the DMDA 13 - dim - the dimension (or PETSC_DECIDE) 14 15 Level: intermediate 16 17 .seealso: DaGetDim(), DMDASetSizes() 18 @*/ 19 PetscErrorCode DMDASetDim(DM da, PetscInt dim) 20 { 21 DM_DA *dd = (DM_DA*)da->data; 22 23 PetscFunctionBegin; 24 PetscValidHeaderSpecific(da, DM_CLASSID, 1); 25 if (dd->dim > 0 && dim != dd->dim) SETERRQ2(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot change DMDA dim from %D after it was set to %D",dd->dim,dim); 26 dd->dim = dim; 27 PetscFunctionReturn(0); 28 } 29 30 #undef __FUNCT__ 31 #define __FUNCT__ "DMDASetSizes" 32 /*@ 33 DMDASetSizes - Sets the global sizes 34 35 Logically Collective on DMDA 36 37 Input Parameters: 38 + da - the DMDA 39 . M - the global X size (or PETSC_DECIDE) 40 . N - the global Y size (or PETSC_DECIDE) 41 - P - the global Z size (or PETSC_DECIDE) 42 43 Level: intermediate 44 45 .seealso: DMDAGetSize(), PetscSplitOwnership() 46 @*/ 47 PetscErrorCode DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P) 48 { 49 DM_DA *dd = (DM_DA*)da->data; 50 51 PetscFunctionBegin; 52 PetscValidHeaderSpecific(da, DM_CLASSID, 1); 53 PetscValidLogicalCollectiveInt(da,M,2); 54 PetscValidLogicalCollectiveInt(da,N,3); 55 PetscValidLogicalCollectiveInt(da,P,4); 56 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 57 58 dd->M = M; 59 dd->N = N; 60 dd->P = P; 61 PetscFunctionReturn(0); 62 } 63 64 #undef __FUNCT__ 65 #define __FUNCT__ "DMDASetNumProcs" 66 /*@ 67 DMDASetNumProcs - Sets the number of processes in each dimension 68 69 Logically Collective on DMDA 70 71 Input Parameters: 72 + da - the DMDA 73 . m - the number of X procs (or PETSC_DECIDE) 74 . n - the number of Y procs (or PETSC_DECIDE) 75 - p - the number of Z procs (or PETSC_DECIDE) 76 77 Level: intermediate 78 79 .seealso: DMDASetSizes(), DMDAGetSize(), PetscSplitOwnership() 80 @*/ 81 PetscErrorCode DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p) 82 { 83 DM_DA *dd = (DM_DA*)da->data; 84 85 PetscFunctionBegin; 86 PetscValidHeaderSpecific(da, DM_CLASSID, 1); 87 PetscValidLogicalCollectiveInt(da,m,2); 88 PetscValidLogicalCollectiveInt(da,n,3); 89 PetscValidLogicalCollectiveInt(da,p,4); 90 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 91 dd->m = m; 92 dd->n = n; 93 dd->p = p; 94 PetscFunctionReturn(0); 95 } 96 97 #undef __FUNCT__ 98 #define __FUNCT__ "DMDASetBoundaryType" 99 /*@ 100 DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries. 101 102 Not collective 103 104 Input Parameter: 105 + da - The DMDA 106 - bx,by,bz - One of DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_GHOSTED, DMDA_BOUNDARY_PERIODIC 107 108 Level: intermediate 109 110 .keywords: distributed array, periodicity 111 .seealso: DMDACreate(), DMDestroy(), DMDA, DMDABoundaryType 112 @*/ 113 PetscErrorCode DMDASetBoundaryType(DM da,DMDABoundaryType bx,DMDABoundaryType by,DMDABoundaryType bz) 114 { 115 DM_DA *dd = (DM_DA*)da->data; 116 117 PetscFunctionBegin; 118 PetscValidHeaderSpecific(da,DM_CLASSID,1); 119 PetscValidLogicalCollectiveEnum(da,bx,2); 120 PetscValidLogicalCollectiveEnum(da,by,3); 121 PetscValidLogicalCollectiveEnum(da,bz,4); 122 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 123 dd->bx = bx; 124 dd->by = by; 125 dd->bz = bz; 126 PetscFunctionReturn(0); 127 } 128 129 #undef __FUNCT__ 130 #define __FUNCT__ "DMDASetDof" 131 /*@ 132 DMDASetDof - Sets the number of degrees of freedom per vertex 133 134 Not collective 135 136 Input Parameter: 137 + da - The DMDA 138 - dof - Number of degrees of freedom 139 140 Level: intermediate 141 142 .keywords: distributed array, degrees of freedom 143 .seealso: DMDACreate(), DMDestroy(), DMDA 144 @*/ 145 PetscErrorCode DMDASetDof(DM da, PetscInt dof) 146 { 147 DM_DA *dd = (DM_DA*)da->data; 148 149 PetscFunctionBegin; 150 PetscValidHeaderSpecific(da,DM_CLASSID,1); 151 PetscValidLogicalCollectiveInt(da,dof,2); 152 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 153 dd->w = dof; 154 da->bs = dof; 155 PetscFunctionReturn(0); 156 } 157 158 #undef __FUNCT__ 159 #define __FUNCT__ "DMDASetStencilType" 160 /*@ 161 DMDASetStencilType - Sets the type of the communication stencil 162 163 Logically Collective on DMDA 164 165 Input Parameter: 166 + da - The DMDA 167 - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR. 168 169 Level: intermediate 170 171 .keywords: distributed array, stencil 172 .seealso: DMDACreate(), DMDestroy(), DMDA 173 @*/ 174 PetscErrorCode DMDASetStencilType(DM da, DMDAStencilType stype) 175 { 176 DM_DA *dd = (DM_DA*)da->data; 177 178 PetscFunctionBegin; 179 PetscValidHeaderSpecific(da,DM_CLASSID,1); 180 PetscValidLogicalCollectiveEnum(da,stype,2); 181 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 182 dd->stencil_type = stype; 183 PetscFunctionReturn(0); 184 } 185 186 #undef __FUNCT__ 187 #define __FUNCT__ "DMDASetStencilWidth" 188 /*@ 189 DMDASetStencilWidth - Sets the width of the communication stencil 190 191 Logically Collective on DMDA 192 193 Input Parameter: 194 + da - The DMDA 195 - width - The stencil width 196 197 Level: intermediate 198 199 .keywords: distributed array, stencil 200 .seealso: DMDACreate(), DMDestroy(), DMDA 201 @*/ 202 PetscErrorCode DMDASetStencilWidth(DM da, PetscInt width) 203 { 204 DM_DA *dd = (DM_DA*)da->data; 205 206 PetscFunctionBegin; 207 PetscValidHeaderSpecific(da,DM_CLASSID,1); 208 PetscValidLogicalCollectiveInt(da,width,2); 209 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 210 dd->s = width; 211 PetscFunctionReturn(0); 212 } 213 214 #undef __FUNCT__ 215 #define __FUNCT__ "DMDACheckOwnershipRanges_Private" 216 static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[]) 217 { 218 PetscInt i,sum; 219 220 PetscFunctionBegin; 221 if (M < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set"); 222 for (i=sum=0; i<m; i++) sum += lx[i]; 223 if (sum != M) SETERRQ2(((PetscObject)da)->comm,PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M); 224 PetscFunctionReturn(0); 225 } 226 227 #undef __FUNCT__ 228 #define __FUNCT__ "DMDASetOwnershipRanges" 229 /*@ 230 DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process 231 232 Logically Collective on DMDA 233 234 Input Parameter: 235 + da - The DMDA 236 . lx - array containing number of nodes in the X direction on each process, or PETSC_NULL. If non-null, must be of length da->m 237 . ly - array containing number of nodes in the Y direction on each process, or PETSC_NULL. If non-null, must be of length da->n 238 - lz - array containing number of nodes in the Z direction on each process, or PETSC_NULL. If non-null, must be of length da->p. 239 240 Level: intermediate 241 242 .keywords: distributed array 243 .seealso: DMDACreate(), DMDestroy(), DMDA 244 @*/ 245 PetscErrorCode DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[]) 246 { 247 PetscErrorCode ierr; 248 DM_DA *dd = (DM_DA*)da->data; 249 250 PetscFunctionBegin; 251 PetscValidHeaderSpecific(da,DM_CLASSID,1); 252 if (da->setupcalled) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()"); 253 if (lx) { 254 if (dd->m < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs"); 255 ierr = DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);CHKERRQ(ierr); 256 if (!dd->lx) { 257 ierr = PetscMalloc(dd->m*sizeof(PetscInt), &dd->lx);CHKERRQ(ierr); 258 } 259 ierr = PetscMemcpy(dd->lx, lx, dd->m*sizeof(PetscInt));CHKERRQ(ierr); 260 } 261 if (ly) { 262 if (dd->n < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs"); 263 ierr = DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);CHKERRQ(ierr); 264 if (!dd->ly) { 265 ierr = PetscMalloc(dd->n*sizeof(PetscInt), &dd->ly);CHKERRQ(ierr); 266 } 267 ierr = PetscMemcpy(dd->ly, ly, dd->n*sizeof(PetscInt));CHKERRQ(ierr); 268 } 269 if (lz) { 270 if (dd->p < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs"); 271 ierr = DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);CHKERRQ(ierr); 272 if (!dd->lz) { 273 ierr = PetscMalloc(dd->p*sizeof(PetscInt), &dd->lz);CHKERRQ(ierr); 274 } 275 ierr = PetscMemcpy(dd->lz, lz, dd->p*sizeof(PetscInt));CHKERRQ(ierr); 276 } 277 PetscFunctionReturn(0); 278 } 279 280 #undef __FUNCT__ 281 #define __FUNCT__ "DMDASetInterpolationType" 282 /*@ 283 DMDASetInterpolationType - Sets the type of interpolation that will be 284 returned by DMCreateInterpolation() 285 286 Logically Collective on DMDA 287 288 Input Parameter: 289 + da - initial distributed array 290 . ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms 291 292 Level: intermediate 293 294 Notes: you should call this on the coarser of the two DMDAs you pass to DMCreateInterpolation() 295 296 .keywords: distributed array, interpolation 297 298 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType 299 @*/ 300 PetscErrorCode DMDASetInterpolationType(DM da,DMDAInterpolationType ctype) 301 { 302 DM_DA *dd = (DM_DA*)da->data; 303 304 PetscFunctionBegin; 305 PetscValidHeaderSpecific(da,DM_CLASSID,1); 306 PetscValidLogicalCollectiveEnum(da,ctype,2); 307 dd->interptype = ctype; 308 PetscFunctionReturn(0); 309 } 310 311 #undef __FUNCT__ 312 #define __FUNCT__ "DMDAGetInterpolationType" 313 /*@ 314 DMDAGetInterpolationType - Gets the type of interpolation that will be 315 used by DMCreateInterpolation() 316 317 Not Collective 318 319 Input Parameter: 320 . da - distributed array 321 322 Output Parameter: 323 . ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms) 324 325 Level: intermediate 326 327 .keywords: distributed array, interpolation 328 329 .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMCreateInterpolation() 330 @*/ 331 PetscErrorCode DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype) 332 { 333 DM_DA *dd = (DM_DA*)da->data; 334 335 PetscFunctionBegin; 336 PetscValidHeaderSpecific(da,DM_CLASSID,1); 337 PetscValidPointer(ctype,2); 338 *ctype = dd->interptype; 339 PetscFunctionReturn(0); 340 } 341 342 #undef __FUNCT__ 343 #define __FUNCT__ "DMDAGetNeighbors" 344 /*@C 345 DMDAGetNeighbors - Gets an array containing the MPI rank of all the current 346 processes neighbors. 347 348 Not Collective 349 350 Input Parameter: 351 . da - the DMDA object 352 353 Output Parameters: 354 . ranks - the neighbors ranks, stored with the x index increasing most rapidly. 355 this process itself is in the list 356 357 Notes: In 2d the array is of length 9, in 3d of length 27 358 Not supported in 1d 359 Do not free the array, it is freed when the DMDA is destroyed. 360 361 Fortran Notes: In fortran you must pass in an array of the appropriate length. 362 363 Level: intermediate 364 365 @*/ 366 PetscErrorCode DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[]) 367 { 368 DM_DA *dd = (DM_DA*)da->data; 369 PetscFunctionBegin; 370 PetscValidHeaderSpecific(da,DM_CLASSID,1); 371 *ranks = dd->neighbors; 372 PetscFunctionReturn(0); 373 } 374 375 #undef __FUNCT__ 376 #define __FUNCT__ "DMDAGetOwnershipRanges" 377 /*@C 378 DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process 379 380 Not Collective 381 382 Input Parameter: 383 . da - the DMDA object 384 385 Output Parameter: 386 + lx - ownership along x direction (optional) 387 . ly - ownership along y direction (optional) 388 - lz - ownership along z direction (optional) 389 390 Level: intermediate 391 392 Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d() 393 394 In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and 395 eighth arguments from DMDAGetInfo() 396 397 In C you should not free these arrays, nor change the values in them. They will only have valid values while the 398 DMDA they came from still exists (has not been destroyed). 399 400 .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges() 401 @*/ 402 PetscErrorCode DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[]) 403 { 404 DM_DA *dd = (DM_DA*)da->data; 405 406 PetscFunctionBegin; 407 PetscValidHeaderSpecific(da,DM_CLASSID,1); 408 if (lx) *lx = dd->lx; 409 if (ly) *ly = dd->ly; 410 if (lz) *lz = dd->lz; 411 PetscFunctionReturn(0); 412 } 413 414 #undef __FUNCT__ 415 #define __FUNCT__ "DMDASetRefinementFactor" 416 /*@ 417 DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined 418 419 Logically Collective on DMDA 420 421 Input Parameters: 422 + da - the DMDA object 423 . refine_x - ratio of fine grid to coarse in x direction (2 by default) 424 . refine_y - ratio of fine grid to coarse in y direction (2 by default) 425 - refine_z - ratio of fine grid to coarse in z direction (2 by default) 426 427 Options Database: 428 + -da_refine_x - refinement ratio in x direction 429 . -da_refine_y - refinement ratio in y direction 430 - -da_refine_z - refinement ratio in z direction 431 432 Level: intermediate 433 434 Notes: Pass PETSC_IGNORE to leave a value unchanged 435 436 .seealso: DMRefine(), DMDAGetRefinementFactor() 437 @*/ 438 PetscErrorCode DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z) 439 { 440 DM_DA *dd = (DM_DA*)da->data; 441 442 PetscFunctionBegin; 443 PetscValidHeaderSpecific(da,DM_CLASSID,1); 444 PetscValidLogicalCollectiveInt(da,refine_x,2); 445 PetscValidLogicalCollectiveInt(da,refine_y,3); 446 PetscValidLogicalCollectiveInt(da,refine_z,4); 447 448 if (refine_x > 0) dd->refine_x = refine_x; 449 if (refine_y > 0) dd->refine_y = refine_y; 450 if (refine_z > 0) dd->refine_z = refine_z; 451 PetscFunctionReturn(0); 452 } 453 454 #undef __FUNCT__ 455 #define __FUNCT__ "DMDAGetRefinementFactor" 456 /*@C 457 DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined 458 459 Not Collective 460 461 Input Parameter: 462 . da - the DMDA object 463 464 Output Parameters: 465 + refine_x - ratio of fine grid to coarse in x direction (2 by default) 466 . refine_y - ratio of fine grid to coarse in y direction (2 by default) 467 - refine_z - ratio of fine grid to coarse in z direction (2 by default) 468 469 Level: intermediate 470 471 Notes: Pass PETSC_NULL for values you do not need 472 473 .seealso: DMRefine(), DMDASetRefinementFactor() 474 @*/ 475 PetscErrorCode DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z) 476 { 477 DM_DA *dd = (DM_DA*)da->data; 478 479 PetscFunctionBegin; 480 PetscValidHeaderSpecific(da,DM_CLASSID,1); 481 if (refine_x) *refine_x = dd->refine_x; 482 if (refine_y) *refine_y = dd->refine_y; 483 if (refine_z) *refine_z = dd->refine_z; 484 PetscFunctionReturn(0); 485 } 486 487 #undef __FUNCT__ 488 #define __FUNCT__ "DMDASetGetMatrix" 489 /*@C 490 DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix. 491 492 Logically Collective on DMDA 493 494 Input Parameters: 495 + da - the DMDA object 496 - f - the function that allocates the matrix for that specific DMDA 497 498 Level: developer 499 500 Notes: See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for 501 the diagonal and off-diagonal blocks of the matrix 502 503 .seealso: DMCreateMatrix(), DMDASetBlockFills() 504 @*/ 505 PetscErrorCode DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, const MatType,Mat*)) 506 { 507 PetscFunctionBegin; 508 PetscValidHeaderSpecific(da,DM_CLASSID,1); 509 da->ops->creatematrix = f; 510 PetscFunctionReturn(0); 511 } 512 513 #undef __FUNCT__ 514 #define __FUNCT__ "DMDARefineOwnershipRanges" 515 /* 516 Creates "balanced" ownership ranges after refinement, constrained by the need for the 517 fine grid boundaries to fall within one stencil width of the coarse partition. 518 519 Uses a greedy algorithm to handle non-ideal layouts, could probably do something better. 520 */ 521 static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[]) 522 { 523 PetscInt i,totalc = 0,remaining,startc = 0,startf = 0; 524 PetscErrorCode ierr; 525 526 PetscFunctionBegin; 527 if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio); 528 if (ratio == 1) { 529 ierr = PetscMemcpy(lf,lc,m*sizeof(lc[0]));CHKERRQ(ierr); 530 PetscFunctionReturn(0); 531 } 532 for (i=0; i<m; i++) totalc += lc[i]; 533 remaining = (!periodic) + ratio * (totalc - (!periodic)); 534 for (i=0; i<m; i++) { 535 PetscInt want = remaining/(m-i) + !!(remaining%(m-i)); 536 if (i == m-1) lf[i] = want; 537 else { 538 const PetscInt nextc = startc + lc[i]; 539 /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one 540 * coarse stencil width of the first coarse node in the next subdomain. */ 541 while ((startf+want)/ratio < nextc - stencil_width) want++; 542 /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one 543 * coarse stencil width of the last coarse node in the current subdomain. */ 544 while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--; 545 /* Make sure all constraints are satisfied */ 546 if (want < 0 || want > remaining 547 || ((startf+want)/ratio < nextc - stencil_width) 548 || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width)) 549 SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range"); 550 } 551 lf[i] = want; 552 startc += lc[i]; 553 startf += lf[i]; 554 remaining -= lf[i]; 555 } 556 PetscFunctionReturn(0); 557 } 558 559 #undef __FUNCT__ 560 #define __FUNCT__ "DMDACoarsenOwnershipRanges" 561 /* 562 Creates "balanced" ownership ranges after coarsening, constrained by the need for the 563 fine grid boundaries to fall within one stencil width of the coarse partition. 564 565 Uses a greedy algorithm to handle non-ideal layouts, could probably do something better. 566 */ 567 static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[]) 568 { 569 PetscInt i,totalf,remaining,startc,startf; 570 PetscErrorCode ierr; 571 572 PetscFunctionBegin; 573 if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio); 574 if (ratio == 1) { 575 ierr = PetscMemcpy(lc,lf,m*sizeof(lf[0]));CHKERRQ(ierr); 576 PetscFunctionReturn(0); 577 } 578 for (i=0,totalf=0; i<m; i++) totalf += lf[i]; 579 remaining = (!periodic) + (totalf - (!periodic)) / ratio; 580 for (i=0,startc=0,startf=0; i<m; i++) { 581 PetscInt want = remaining/(m-i) + !!(remaining%(m-i)); 582 if (i == m-1) lc[i] = want; 583 else { 584 const PetscInt nextf = startf+lf[i]; 585 /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine 586 * node is within one stencil width. */ 587 while (nextf/ratio < startc+want-stencil_width) want--; 588 /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last 589 * fine node is within one stencil width. */ 590 while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++; 591 if (want < 0 || want > remaining 592 || (nextf/ratio < startc+want-stencil_width) 593 || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width)) 594 SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range"); 595 } 596 lc[i] = want; 597 startc += lc[i]; 598 startf += lf[i]; 599 remaining -= lc[i]; 600 } 601 PetscFunctionReturn(0); 602 } 603 604 #undef __FUNCT__ 605 #define __FUNCT__ "DMRefine_DA" 606 PetscErrorCode DMRefine_DA(DM da,MPI_Comm comm,DM *daref) 607 { 608 PetscErrorCode ierr; 609 PetscInt M,N,P,i; 610 DM da2; 611 DM_DA *dd = (DM_DA*)da->data,*dd2; 612 613 PetscFunctionBegin; 614 PetscValidHeaderSpecific(da,DM_CLASSID,1); 615 PetscValidPointer(daref,3); 616 617 if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 618 M = dd->refine_x*dd->M; 619 } else { 620 M = 1 + dd->refine_x*(dd->M - 1); 621 } 622 if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 623 N = dd->refine_y*dd->N; 624 } else { 625 N = 1 + dd->refine_y*(dd->N - 1); 626 } 627 if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 628 P = dd->refine_z*dd->P; 629 } else { 630 P = 1 + dd->refine_z*(dd->P - 1); 631 } 632 if (dd->dim == 3) { 633 PetscInt *lx,*ly,*lz; 634 ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr); 635 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 636 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 637 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr); 638 ierr = DMDACreate3d(((PetscObject)da)->comm,dd->bx,dd->by,dd->bz,dd->stencil_type,M,N,P,dd->m,dd->n,dd->p,dd->w,dd->s,lx,ly,lz,&da2);CHKERRQ(ierr); 639 ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr); 640 } else if (dd->dim == 2) { 641 PetscInt *lx,*ly; 642 ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr); 643 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 644 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 645 ierr = DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);CHKERRQ(ierr); 646 ierr = PetscFree2(lx,ly);CHKERRQ(ierr); 647 } else if (dd->dim == 1) { 648 PetscInt *lx; 649 ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr); 650 ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 651 ierr = DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);CHKERRQ(ierr); 652 ierr = PetscFree(lx);CHKERRQ(ierr); 653 } 654 dd2 = (DM_DA*)da2->data; 655 656 /* allow overloaded (user replaced) operations to be inherited by refinement clones */ 657 da2->ops->creatematrix = da->ops->creatematrix; 658 /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */ 659 da2->ops->getcoloring = da->ops->getcoloring; 660 dd2->interptype = dd->interptype; 661 662 /* copy fill information if given */ 663 if (dd->dfill) { 664 ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr); 665 ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 666 } 667 if (dd->ofill) { 668 ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr); 669 ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 670 } 671 /* copy the refine information */ 672 dd2->refine_x = dd->refine_x; 673 dd2->refine_y = dd->refine_y; 674 dd2->refine_z = dd->refine_z; 675 676 /* copy vector type information */ 677 ierr = PetscFree(da2->vectype);CHKERRQ(ierr); 678 ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr); 679 680 dd2->lf = dd->lf; 681 dd2->lj = dd->lj; 682 683 /* interpolate coordinates if they are set on the coarse grid */ 684 if (dd->coordinates) { 685 DM cdaf,cdac; 686 Vec coordsc,coordsf; 687 Mat II; 688 689 ierr = DMDAGetCoordinateDA(da,&cdac);CHKERRQ(ierr); 690 ierr = DMDAGetCoordinates(da,&coordsc);CHKERRQ(ierr); 691 ierr = DMDAGetCoordinateDA(da2,&cdaf);CHKERRQ(ierr); 692 /* force creation of the coordinate vector */ 693 ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr); 694 ierr = DMDAGetCoordinates(da2,&coordsf);CHKERRQ(ierr); 695 ierr = DMCreateInterpolation(cdac,cdaf,&II,PETSC_NULL);CHKERRQ(ierr); 696 ierr = MatInterpolate(II,coordsc,coordsf);CHKERRQ(ierr); 697 ierr = MatDestroy(&II);CHKERRQ(ierr); 698 } 699 for (i=0; i<da->bs; i++) { 700 const char *fieldname; 701 ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr); 702 ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr); 703 } 704 *daref = da2; 705 PetscFunctionReturn(0); 706 } 707 708 #undef __FUNCT__ 709 #define __FUNCT__ "DMCoarsen_DA" 710 PetscErrorCode DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref) 711 { 712 PetscErrorCode ierr; 713 PetscInt M,N,P; 714 DM da2; 715 DM_DA *dd = (DM_DA*)da->data,*dd2; 716 717 PetscFunctionBegin; 718 PetscValidHeaderSpecific(da,DM_CLASSID,1); 719 PetscValidPointer(daref,3); 720 721 if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 722 M = dd->M / dd->refine_x; 723 } else { 724 M = 1 + (dd->M - 1) / dd->refine_x; 725 } 726 if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 727 N = dd->N / dd->refine_y; 728 } else { 729 N = 1 + (dd->N - 1) / dd->refine_y; 730 } 731 if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 732 P = dd->P / dd->refine_z; 733 } else { 734 P = 1 + (dd->P - 1) / dd->refine_z; 735 } 736 if (dd->dim == 3) { 737 PetscInt *lx,*ly,*lz; 738 ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr); 739 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 740 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 741 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr); 742 ierr = DMDACreate3d(((PetscObject)da)->comm,dd->bx,dd->by,dd->bz,dd->stencil_type,M,N,P,dd->m,dd->n,dd->p,dd->w,dd->s,lx,ly,lz,&da2);CHKERRQ(ierr); 743 ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr); 744 } else if (dd->dim == 2) { 745 PetscInt *lx,*ly; 746 ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr); 747 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 748 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 749 ierr = DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);CHKERRQ(ierr); 750 ierr = PetscFree2(lx,ly);CHKERRQ(ierr); 751 } else if (dd->dim == 1) { 752 PetscInt *lx; 753 ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr); 754 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 755 ierr = DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);CHKERRQ(ierr); 756 ierr = PetscFree(lx);CHKERRQ(ierr); 757 } 758 dd2 = (DM_DA*)da2->data; 759 760 /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */ 761 /* da2->ops->createinterpolation = da->ops->createinterpolation; copying this one causes trouble for DMSetVI */ 762 da2->ops->creatematrix = da->ops->creatematrix; 763 da2->ops->getcoloring = da->ops->getcoloring; 764 dd2->interptype = dd->interptype; 765 766 /* copy fill information if given */ 767 if (dd->dfill) { 768 ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr); 769 ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 770 } 771 if (dd->ofill) { 772 ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr); 773 ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 774 } 775 /* copy the refine information */ 776 dd2->refine_x = dd->refine_x; 777 dd2->refine_y = dd->refine_y; 778 dd2->refine_z = dd->refine_z; 779 780 /* copy vector type information */ 781 ierr = PetscFree(da2->vectype);CHKERRQ(ierr); 782 ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr); 783 784 dd2->lf = dd->lf; 785 dd2->lj = dd->lj; 786 787 /* inject coordinates if they are set on the fine grid */ 788 if (dd->coordinates) { 789 DM cdaf,cdac; 790 Vec coordsc,coordsf; 791 VecScatter inject; 792 793 ierr = DMDAGetCoordinateDA(da,&cdaf);CHKERRQ(ierr); 794 ierr = DMDAGetCoordinates(da,&coordsf);CHKERRQ(ierr); 795 ierr = DMDAGetCoordinateDA(da2,&cdac);CHKERRQ(ierr); 796 /* force creation of the coordinate vector */ 797 ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr); 798 ierr = DMDAGetCoordinates(da2,&coordsc);CHKERRQ(ierr); 799 800 ierr = DMCreateInjection(cdac,cdaf,&inject);CHKERRQ(ierr); 801 ierr = VecScatterBegin(inject,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 802 ierr = VecScatterEnd(inject ,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 803 ierr = VecScatterDestroy(&inject);CHKERRQ(ierr); 804 } 805 *daref = da2; 806 PetscFunctionReturn(0); 807 } 808 809 #undef __FUNCT__ 810 #define __FUNCT__ "DMRefineHierarchy_DA" 811 PetscErrorCode DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[]) 812 { 813 PetscErrorCode ierr; 814 PetscInt i,n,*refx,*refy,*refz; 815 816 PetscFunctionBegin; 817 PetscValidHeaderSpecific(da,DM_CLASSID,1); 818 if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative"); 819 if (nlevels == 0) PetscFunctionReturn(0); 820 PetscValidPointer(daf,3); 821 822 /* Get refinement factors, defaults taken from the coarse DMDA */ 823 ierr = PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);CHKERRQ(ierr); 824 for (i=0; i<nlevels; i++) { 825 ierr = DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr); 826 } 827 n = nlevels; 828 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);CHKERRQ(ierr); 829 n = nlevels; 830 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);CHKERRQ(ierr); 831 n = nlevels; 832 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);CHKERRQ(ierr); 833 834 ierr = DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr); 835 ierr = DMRefine(da,((PetscObject)da)->comm,&daf[0]);CHKERRQ(ierr); 836 for (i=1; i<nlevels; i++) { 837 ierr = DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr); 838 ierr = DMRefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);CHKERRQ(ierr); 839 } 840 ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr); 841 PetscFunctionReturn(0); 842 } 843 844 #undef __FUNCT__ 845 #define __FUNCT__ "DMCoarsenHierarchy_DA" 846 PetscErrorCode DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[]) 847 { 848 PetscErrorCode ierr; 849 PetscInt i; 850 851 PetscFunctionBegin; 852 PetscValidHeaderSpecific(da,DM_CLASSID,1); 853 if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative"); 854 if (nlevels == 0) PetscFunctionReturn(0); 855 PetscValidPointer(dac,3); 856 ierr = DMCoarsen(da,((PetscObject)da)->comm,&dac[0]);CHKERRQ(ierr); 857 for (i=1; i<nlevels; i++) { 858 ierr = DMCoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);CHKERRQ(ierr); 859 } 860 PetscFunctionReturn(0); 861 } 862