1 #include <petsc-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 || ((startf+want)/ratio < nextc - stencil_width) 547 || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width)) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range"); 548 } 549 lf[i] = want; 550 startc += lc[i]; 551 startf += lf[i]; 552 remaining -= lf[i]; 553 } 554 PetscFunctionReturn(0); 555 } 556 557 #undef __FUNCT__ 558 #define __FUNCT__ "DMDACoarsenOwnershipRanges" 559 /* 560 Creates "balanced" ownership ranges after coarsening, constrained by the need for the 561 fine grid boundaries to fall within one stencil width of the coarse partition. 562 563 Uses a greedy algorithm to handle non-ideal layouts, could probably do something better. 564 */ 565 static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[]) 566 { 567 PetscInt i,totalf,remaining,startc,startf; 568 PetscErrorCode ierr; 569 570 PetscFunctionBegin; 571 if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio); 572 if (ratio == 1) { 573 ierr = PetscMemcpy(lc,lf,m*sizeof(lf[0]));CHKERRQ(ierr); 574 PetscFunctionReturn(0); 575 } 576 for (i=0,totalf=0; i<m; i++) totalf += lf[i]; 577 remaining = (!periodic) + (totalf - (!periodic)) / ratio; 578 for (i=0,startc=0,startf=0; i<m; i++) { 579 PetscInt want = remaining/(m-i) + !!(remaining%(m-i)); 580 if (i == m-1) lc[i] = want; 581 else { 582 const PetscInt nextf = startf+lf[i]; 583 /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine 584 * node is within one stencil width. */ 585 while (nextf/ratio < startc+want-stencil_width) want--; 586 /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last 587 * fine node is within one stencil width. */ 588 while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++; 589 if (want < 0 || want > remaining 590 || (nextf/ratio < startc+want-stencil_width) || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width)) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range"); 591 } 592 lc[i] = want; 593 startc += lc[i]; 594 startf += lf[i]; 595 remaining -= lc[i]; 596 } 597 PetscFunctionReturn(0); 598 } 599 600 #undef __FUNCT__ 601 #define __FUNCT__ "DMRefine_DA" 602 PetscErrorCode DMRefine_DA(DM da,MPI_Comm comm,DM *daref) 603 { 604 PetscErrorCode ierr; 605 PetscInt M,N,P,i; 606 DM da2; 607 DM_DA *dd = (DM_DA*)da->data,*dd2; 608 609 PetscFunctionBegin; 610 PetscValidHeaderSpecific(da,DM_CLASSID,1); 611 PetscValidPointer(daref,3); 612 613 if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 614 M = dd->refine_x*dd->M; 615 } else { 616 M = 1 + dd->refine_x*(dd->M - 1); 617 } 618 if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 619 N = dd->refine_y*dd->N; 620 } else { 621 N = 1 + dd->refine_y*(dd->N - 1); 622 } 623 if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 624 P = dd->refine_z*dd->P; 625 } else { 626 P = 1 + dd->refine_z*(dd->P - 1); 627 } 628 ierr = DMDACreate(((PetscObject)da)->comm,&da2);CHKERRQ(ierr); 629 ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr); 630 ierr = DMDASetDim(da2,dd->dim);CHKERRQ(ierr); 631 ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr); 632 ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr); 633 ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr); 634 ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr); 635 ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr); 636 ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr); 637 if (dd->dim == 3) { 638 PetscInt *lx,*ly,*lz; 639 ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr); 640 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); 641 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); 642 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); 643 ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr); 644 ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr); 645 } else if (dd->dim == 2) { 646 PetscInt *lx,*ly; 647 ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr); 648 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); 649 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); 650 ierr = DMDASetOwnershipRanges(da2,lx,ly,PETSC_NULL);CHKERRQ(ierr); 651 ierr = PetscFree2(lx,ly);CHKERRQ(ierr); 652 } else if (dd->dim == 1) { 653 PetscInt *lx; 654 ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr); 655 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); 656 ierr = DMDASetOwnershipRanges(da2,lx,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 657 ierr = PetscFree(lx);CHKERRQ(ierr); 658 } 659 dd2 = (DM_DA*)da2->data; 660 661 /* allow overloaded (user replaced) operations to be inherited by refinement clones */ 662 da2->ops->creatematrix = da->ops->creatematrix; 663 /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */ 664 da2->ops->getcoloring = da->ops->getcoloring; 665 dd2->interptype = dd->interptype; 666 667 /* copy fill information if given */ 668 if (dd->dfill) { 669 ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr); 670 ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 671 } 672 if (dd->ofill) { 673 ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr); 674 ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 675 } 676 /* copy the refine information */ 677 dd2->coarsen_x = dd2->refine_x = dd->refine_x; 678 dd2->coarsen_y = dd2->refine_y = dd->refine_y; 679 dd2->coarsen_z = dd2->refine_z = dd->refine_z; 680 681 /* copy vector type information */ 682 ierr = PetscFree(da2->vectype);CHKERRQ(ierr); 683 ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr); 684 685 dd2->lf = dd->lf; 686 dd2->lj = dd->lj; 687 688 /* interpolate coordinates if they are set on the coarse grid */ 689 if (dd->coordinates) { 690 DM cdaf,cdac; 691 Vec coordsc,coordsf; 692 Mat II; 693 694 ierr = DMDAGetCoordinateDA(da,&cdac);CHKERRQ(ierr); 695 ierr = DMDAGetCoordinates(da,&coordsc);CHKERRQ(ierr); 696 ierr = DMDAGetCoordinateDA(da2,&cdaf);CHKERRQ(ierr); 697 /* force creation of the coordinate vector */ 698 ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr); 699 ierr = DMDAGetCoordinates(da2,&coordsf);CHKERRQ(ierr); 700 ierr = DMCreateInterpolation(cdac,cdaf,&II,PETSC_NULL);CHKERRQ(ierr); 701 ierr = MatInterpolate(II,coordsc,coordsf);CHKERRQ(ierr); 702 ierr = MatDestroy(&II);CHKERRQ(ierr); 703 } 704 705 /* Need to set up before we can do field names */ 706 da2->leveldown = da->leveldown; 707 da2->levelup = da->levelup + 1; 708 ierr = DMSetFromOptions(da2);CHKERRQ(ierr); 709 ierr = DMSetUp(da2);CHKERRQ(ierr); 710 ierr = DMView_DA_Private(da2);CHKERRQ(ierr); 711 712 for (i=0; i<da->bs; i++) { 713 const char *fieldname; 714 ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr); 715 ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr); 716 } 717 718 *daref = da2; 719 PetscFunctionReturn(0); 720 } 721 722 723 #undef __FUNCT__ 724 #define __FUNCT__ "DMCoarsen_DA" 725 PetscErrorCode DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref) 726 { 727 PetscErrorCode ierr; 728 PetscInt M,N,P,i; 729 DM da2; 730 DM_DA *dd = (DM_DA*)da->data,*dd2; 731 732 PetscFunctionBegin; 733 PetscValidHeaderSpecific(da,DM_CLASSID,1); 734 PetscValidPointer(daref,3); 735 736 if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 737 M = dd->M / dd->coarsen_x; 738 } else { 739 M = 1 + (dd->M - 1) / dd->coarsen_x; 740 } 741 if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 742 N = dd->N / dd->coarsen_y; 743 } else { 744 N = 1 + (dd->N - 1) / dd->coarsen_y; 745 } 746 if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){ 747 P = dd->P / dd->coarsen_z; 748 } else { 749 P = 1 + (dd->P - 1) / dd->coarsen_z; 750 } 751 ierr = DMDACreate(((PetscObject)da)->comm,&da2);CHKERRQ(ierr); 752 ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr); 753 ierr = DMDASetDim(da2,dd->dim);CHKERRQ(ierr); 754 ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr); 755 ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr); 756 ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr); 757 ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr); 758 ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr); 759 ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr); 760 if (dd->dim == 3) { 761 PetscInt *lx,*ly,*lz; 762 ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr); 763 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 764 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 765 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_z,dd->p,dd->lz,lz);CHKERRQ(ierr); 766 ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr); 767 ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr); 768 } else if (dd->dim == 2) { 769 PetscInt *lx,*ly; 770 ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr); 771 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 772 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr); 773 ierr = DMDASetOwnershipRanges(da2,lx,ly,PETSC_NULL);CHKERRQ(ierr); 774 ierr = PetscFree2(lx,ly);CHKERRQ(ierr); 775 } else if (dd->dim == 1) { 776 PetscInt *lx; 777 ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr); 778 ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr); 779 ierr = DMDASetOwnershipRanges(da2,lx,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 780 ierr = PetscFree(lx);CHKERRQ(ierr); 781 } 782 dd2 = (DM_DA*)da2->data; 783 784 /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */ 785 /* da2->ops->createinterpolation = da->ops->createinterpolation; copying this one causes trouble for DMSetVI */ 786 da2->ops->creatematrix = da->ops->creatematrix; 787 da2->ops->getcoloring = da->ops->getcoloring; 788 dd2->interptype = dd->interptype; 789 790 /* copy fill information if given */ 791 if (dd->dfill) { 792 ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr); 793 ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 794 } 795 if (dd->ofill) { 796 ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr); 797 ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr); 798 } 799 /* copy the refine information */ 800 dd2->coarsen_x = dd2->refine_x = dd->coarsen_x; 801 dd2->coarsen_y = dd2->refine_y = dd->coarsen_y; 802 dd2->coarsen_z = dd2->refine_z = dd->coarsen_z; 803 804 /* copy vector type information */ 805 ierr = PetscFree(da2->vectype);CHKERRQ(ierr); 806 ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr); 807 808 dd2->lf = dd->lf; 809 dd2->lj = dd->lj; 810 811 /* inject coordinates if they are set on the fine grid */ 812 if (dd->coordinates) { 813 DM cdaf,cdac; 814 Vec coordsc,coordsf; 815 VecScatter inject; 816 817 ierr = DMDAGetCoordinateDA(da,&cdaf);CHKERRQ(ierr); 818 ierr = DMDAGetCoordinates(da,&coordsf);CHKERRQ(ierr); 819 ierr = DMDAGetCoordinateDA(da2,&cdac);CHKERRQ(ierr); 820 /* force creation of the coordinate vector */ 821 ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr); 822 ierr = DMDAGetCoordinates(da2,&coordsc);CHKERRQ(ierr); 823 824 ierr = DMCreateInjection(cdac,cdaf,&inject);CHKERRQ(ierr); 825 ierr = VecScatterBegin(inject,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 826 ierr = VecScatterEnd(inject ,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 827 ierr = VecScatterDestroy(&inject);CHKERRQ(ierr); 828 } 829 830 /* Need to set up before we can do field names */ 831 da2->leveldown = da->leveldown + 1; 832 da2->levelup = da->levelup; 833 ierr = DMSetFromOptions(da2);CHKERRQ(ierr); 834 ierr = DMSetUp(da2);CHKERRQ(ierr); 835 ierr = DMView_DA_Private(da2);CHKERRQ(ierr); 836 837 for (i=0; i<da->bs; i++) { 838 const char *fieldname; 839 ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr); 840 ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr); 841 } 842 843 *daref = da2; 844 PetscFunctionReturn(0); 845 } 846 847 #undef __FUNCT__ 848 #define __FUNCT__ "DMRefineHierarchy_DA" 849 PetscErrorCode DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[]) 850 { 851 PetscErrorCode ierr; 852 PetscInt i,n,*refx,*refy,*refz; 853 854 PetscFunctionBegin; 855 PetscValidHeaderSpecific(da,DM_CLASSID,1); 856 if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative"); 857 if (nlevels == 0) PetscFunctionReturn(0); 858 PetscValidPointer(daf,3); 859 860 /* Get refinement factors, defaults taken from the coarse DMDA */ 861 ierr = PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);CHKERRQ(ierr); 862 for (i=0; i<nlevels; i++) { 863 ierr = DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr); 864 } 865 n = nlevels; 866 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);CHKERRQ(ierr); 867 n = nlevels; 868 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);CHKERRQ(ierr); 869 n = nlevels; 870 ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);CHKERRQ(ierr); 871 872 ierr = DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr); 873 ierr = DMRefine(da,((PetscObject)da)->comm,&daf[0]);CHKERRQ(ierr); 874 for (i=1; i<nlevels; i++) { 875 ierr = DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr); 876 ierr = DMRefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);CHKERRQ(ierr); 877 } 878 ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr); 879 PetscFunctionReturn(0); 880 } 881 882 #undef __FUNCT__ 883 #define __FUNCT__ "DMCoarsenHierarchy_DA" 884 PetscErrorCode DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[]) 885 { 886 PetscErrorCode ierr; 887 PetscInt i; 888 889 PetscFunctionBegin; 890 PetscValidHeaderSpecific(da,DM_CLASSID,1); 891 if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative"); 892 if (nlevels == 0) PetscFunctionReturn(0); 893 PetscValidPointer(dac,3); 894 ierr = DMCoarsen(da,((PetscObject)da)->comm,&dac[0]);CHKERRQ(ierr); 895 for (i=1; i<nlevels; i++) { 896 ierr = DMCoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);CHKERRQ(ierr); 897 } 898 PetscFunctionReturn(0); 899 } 900