Actual source code: da.c

  1: #include <private/daimpl.h>    /*I   "petscdmda.h"   I*/


  6: /*@
  7:   DMDASetDim - Sets the dimension

  9:   Collective on DMDA

 11:   Input Parameters:
 12: + da - the DMDA
 13: - dim - the dimension (or PETSC_DECIDE)

 15:   Level: intermediate

 17: .seealso: DaGetDim(), DMDASetSizes()
 18: @*/
 19: PetscErrorCode  DMDASetDim(DM da, PetscInt dim)
 20: {
 21:   DM_DA *dd = (DM_DA*)da->data;

 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:   return(0);
 28: }

 32: /*@
 33:   DMDASetSizes - Sets the global sizes

 35:   Logically Collective on DMDA

 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)

 43:   Level: intermediate

 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;


 57:   dd->M = M;
 58:   dd->N = N;
 59:   dd->P = P;
 60:   return(0);
 61: }

 65: /*@
 66:   DMDASetNumProcs - Sets the number of processes in each dimension

 68:   Logically Collective on DMDA

 70:   Input Parameters:
 71: + da - the DMDA
 72: . m - the number of X procs (or PETSC_DECIDE)
 73: . n - the number of Y procs (or PETSC_DECIDE)
 74: - p - the number of Z procs (or PETSC_DECIDE)

 76:   Level: intermediate

 78: .seealso: DMDASetSizes(), DMDAGetSize(), PetscSplitOwnership()
 79: @*/
 80: PetscErrorCode  DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p)
 81: {
 82:   DM_DA *dd = (DM_DA*)da->data;

 89:   dd->m = m;
 90:   dd->n = n;
 91:   dd->p = p;
 92:   return(0);
 93: }

 97: /*@
 98:   DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries.

100:   Not collective

102:   Input Parameter:
103: + da    - The DMDA
104: - bx,by,bz - One of DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_GHOSTED, DMDA_BOUNDARY_PERIODIC

106:   Level: intermediate

108: .keywords:  distributed array, periodicity
109: .seealso: DMDACreate(), DMDestroy(), DMDA, DMDABoundaryType
110: @*/
111: PetscErrorCode  DMDASetBoundaryType(DM da,DMDABoundaryType bx,DMDABoundaryType by,DMDABoundaryType bz)
112: {
113:   DM_DA *dd = (DM_DA*)da->data;

120:   dd->bx = bx;
121:   dd->by = by;
122:   dd->bz = bz;
123:   return(0);
124: }

128: /*@
129:   DMDASetDof - Sets the number of degrees of freedom per vertex

131:   Not collective

133:   Input Parameter:
134: + da  - The DMDA
135: - dof - Number of degrees of freedom

137:   Level: intermediate

139: .keywords:  distributed array, degrees of freedom
140: .seealso: DMDACreate(), DMDestroy(), DMDA
141: @*/
142: PetscErrorCode  DMDASetDof(DM da, PetscInt dof)
143: {
144:   DM_DA *dd = (DM_DA*)da->data;

149:   dd->w = dof;
150:   da->bs = dof;
151:   return(0);
152: }

156: /*@
157:   DMDASetStencilType - Sets the type of the communication stencil

159:   Logically Collective on DMDA

161:   Input Parameter:
162: + da    - The DMDA
163: - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.

165:   Level: intermediate

167: .keywords:  distributed array, stencil
168: .seealso: DMDACreate(), DMDestroy(), DMDA
169: @*/
170: PetscErrorCode  DMDASetStencilType(DM da, DMDAStencilType stype)
171: {
172:   DM_DA *dd = (DM_DA*)da->data;

177:   dd->stencil_type = stype;
178:   return(0);
179: }

183: /*@
184:   DMDASetStencilWidth - Sets the width of the communication stencil

186:   Logically Collective on DMDA

188:   Input Parameter:
189: + da    - The DMDA
190: - width - The stencil width

192:   Level: intermediate

194: .keywords:  distributed array, stencil
195: .seealso: DMDACreate(), DMDestroy(), DMDA
196: @*/
197: PetscErrorCode  DMDASetStencilWidth(DM da, PetscInt width)
198: {
199:   DM_DA *dd = (DM_DA*)da->data;

204:   dd->s = width;
205:   return(0);
206: }

210: static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
211: {
212:   PetscInt i,sum;

215:   if (M < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
216:   for (i=sum=0; i<m; i++) sum += lx[i];
217:   if (sum != M) SETERRQ2(((PetscObject)da)->comm,PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M);
218:   return(0);
219: }

223: /*@
224:   DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process

226:   Logically Collective on DMDA

228:   Input Parameter:
229: + da - The DMDA
230: . 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
231: . 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
232: - 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.

234:   Level: intermediate

236: .keywords:  distributed array
237: .seealso: DMDACreate(), DMDestroy(), DMDA
238: @*/
239: PetscErrorCode  DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
240: {
242:   DM_DA          *dd = (DM_DA*)da->data;
243: 
246:   if (lx) {
247:     if (dd->m < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
248:     DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);
249:     if (!dd->lx) {
250:       PetscMalloc(dd->m*sizeof(PetscInt), &dd->lx);
251:     }
252:     PetscMemcpy(dd->lx, lx, dd->m*sizeof(PetscInt));
253:   }
254:   if (ly) {
255:     if (dd->n < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
256:     DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);
257:     if (!dd->ly) {
258:       PetscMalloc(dd->n*sizeof(PetscInt), &dd->ly);
259:     }
260:     PetscMemcpy(dd->ly, ly, dd->n*sizeof(PetscInt));
261:   }
262:   if (lz) {
263:     if (dd->p < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
264:     DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);
265:     if (!dd->lz) {
266:       PetscMalloc(dd->p*sizeof(PetscInt), &dd->lz);
267:     }
268:     PetscMemcpy(dd->lz, lz, dd->p*sizeof(PetscInt));
269:   }
270:   return(0);
271: }

275: /*@
276:        DMDASetInterpolationType - Sets the type of interpolation that will be 
277:           returned by DMGetInterpolation()

279:    Logically Collective on DMDA

281:    Input Parameter:
282: +  da - initial distributed array
283: .  ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms

285:    Level: intermediate

287:    Notes: you should call this on the coarser of the two DMDAs you pass to DMGetInterpolation()

289: .keywords:  distributed array, interpolation

291: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType
292: @*/
293: PetscErrorCode  DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
294: {
295:   DM_DA *dd = (DM_DA*)da->data;

300:   dd->interptype = ctype;
301:   return(0);
302: }

306: /*@
307:        DMDAGetInterpolationType - Gets the type of interpolation that will be
308:           used by DMGetInterpolation()

310:    Not Collective

312:    Input Parameter:
313: .  da - distributed array

315:    Output Parameter:
316: .  ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms)

318:    Level: intermediate

320: .keywords:  distributed array, interpolation

322: .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMGetInterpolation()
323: @*/
324: PetscErrorCode  DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
325: {
326:   DM_DA *dd = (DM_DA*)da->data;

331:   *ctype = dd->interptype;
332:   return(0);
333: }

337: /*@C
338:       DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
339:         processes neighbors.

341:     Not Collective

343:    Input Parameter:
344: .     da - the DMDA object

346:    Output Parameters:
347: .     ranks - the neighbors ranks, stored with the x index increasing most rapidly.
348:               this process itself is in the list

350:    Notes: In 2d the array is of length 9, in 3d of length 27
351:           Not supported in 1d
352:           Do not free the array, it is freed when the DMDA is destroyed.

354:    Fortran Notes: In fortran you must pass in an array of the appropriate length.

356:    Level: intermediate

358: @*/
359: PetscErrorCode  DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
360: {
361:   DM_DA *dd = (DM_DA*)da->data;
364:   *ranks = dd->neighbors;
365:   return(0);
366: }

370: /*@C
371:       DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process

373:     Not Collective

375:    Input Parameter:
376: .     da - the DMDA object

378:    Output Parameter:
379: +     lx - ownership along x direction (optional)
380: .     ly - ownership along y direction (optional)
381: -     lz - ownership along z direction (optional)

383:    Level: intermediate

385:     Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d()

387:     In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and
388:     eighth arguments from DMDAGetInfo()

390:      In C you should not free these arrays, nor change the values in them. They will only have valid values while the
391:     DMDA they came from still exists (has not been destroyed).

393: .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges()
394: @*/
395: PetscErrorCode  DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
396: {
397:   DM_DA *dd = (DM_DA*)da->data;

401:   if (lx) *lx = dd->lx;
402:   if (ly) *ly = dd->ly;
403:   if (lz) *lz = dd->lz;
404:   return(0);
405: }

409: /*@
410:      DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined

412:     Logically Collective on DMDA

414:   Input Parameters:
415: +    da - the DMDA object
416: .    refine_x - ratio of fine grid to coarse in x direction (2 by default)
417: .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
418: -    refine_z - ratio of fine grid to coarse in z direction (2 by default)

420:   Options Database:
421: +  -da_refine_x - refinement ratio in x direction
422: .  -da_refine_y - refinement ratio in y direction
423: -  -da_refine_z - refinement ratio in z direction

425:   Level: intermediate

427:     Notes: Pass PETSC_IGNORE to leave a value unchanged

429: .seealso: DMRefine(), DMDAGetRefinementFactor()
430: @*/
431: PetscErrorCode  DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
432: {
433:   DM_DA *dd = (DM_DA*)da->data;


441:   if (refine_x > 0) dd->refine_x = refine_x;
442:   if (refine_y > 0) dd->refine_y = refine_y;
443:   if (refine_z > 0) dd->refine_z = refine_z;
444:   return(0);
445: }

449: /*@C
450:      DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined

452:     Not Collective

454:   Input Parameter:
455: .    da - the DMDA object

457:   Output Parameters:
458: +    refine_x - ratio of fine grid to coarse in x direction (2 by default)
459: .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
460: -    refine_z - ratio of fine grid to coarse in z direction (2 by default)

462:   Level: intermediate

464:     Notes: Pass PETSC_NULL for values you do not need

466: .seealso: DMRefine(), DMDASetRefinementFactor()
467: @*/
468: PetscErrorCode  DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
469: {
470:   DM_DA *dd = (DM_DA*)da->data;

474:   if (refine_x) *refine_x = dd->refine_x;
475:   if (refine_y) *refine_y = dd->refine_y;
476:   if (refine_z) *refine_z = dd->refine_z;
477:   return(0);
478: }

482: /*@C
483:      DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix.

485:     Logically Collective on DMDA

487:   Input Parameters:
488: +    da - the DMDA object
489: -    f - the function that allocates the matrix for that specific DMDA

491:   Level: developer

493:    Notes: See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for 
494:        the diagonal and off-diagonal blocks of the matrix

496: .seealso: DMGetMatrix(), DMDASetBlockFills()
497: @*/
498: PetscErrorCode  DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, const MatType,Mat*))
499: {
502:   da->ops->getmatrix = f;
503:   return(0);
504: }

508: /*
509:   Creates "balanced" ownership ranges after refinement, constrained by the need for the
510:   fine grid boundaries to fall within one stencil width of the coarse partition.

512:   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
513: */
514: static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[])
515: {
516:   PetscInt       i,totalc = 0,remaining,startc = 0,startf = 0;

520:   if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
521:   if (ratio == 1) {
522:     PetscMemcpy(lf,lc,m*sizeof(lc[0]));
523:     return(0);
524:   }
525:   for (i=0; i<m; i++) totalc += lc[i];
526:   remaining = (!periodic) + ratio * (totalc - (!periodic));
527:   for (i=0; i<m; i++) {
528:     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
529:     if (i == m-1) lf[i] = want;
530:     else {
531:       const PetscInt nextc = startc + lc[i];
532:       /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
533:        * coarse stencil width of the first coarse node in the next subdomain. */
534:       while ((startf+want)/ratio < nextc - stencil_width) want++;
535:       /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
536:        * coarse stencil width of the last coarse node in the current subdomain. */
537:       while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
538:       /* Make sure all constraints are satisfied */
539:       if (want < 0 || want > remaining
540:           || ((startf+want)/ratio < nextc - stencil_width)
541:           || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width))
542:         SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range");
543:     }
544:     lf[i] = want;
545:     startc += lc[i];
546:     startf += lf[i];
547:     remaining -= lf[i];
548:   }
549:   return(0);
550: }

554: /*
555:   Creates "balanced" ownership ranges after coarsening, constrained by the need for the
556:   fine grid boundaries to fall within one stencil width of the coarse partition.

558:   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
559: */
560: static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[])
561: {
562:   PetscInt       i,totalf,remaining,startc,startf;

566:   if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
567:   if (ratio == 1) {
568:     PetscMemcpy(lc,lf,m*sizeof(lf[0]));
569:     return(0);
570:   }
571:   for (i=0,totalf=0; i<m; i++) totalf += lf[i];
572:   remaining = (!periodic) + (totalf - (!periodic)) / ratio;
573:   for (i=0,startc=0,startf=0; i<m; i++) {
574:     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
575:     if (i == m-1) lc[i] = want;
576:     else {
577:       const PetscInt nextf = startf+lf[i];
578:       /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
579:        * node is within one stencil width. */
580:       while (nextf/ratio < startc+want-stencil_width) want--;
581:       /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
582:        * fine node is within one stencil width. */
583:       while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
584:       if (want < 0 || want > remaining
585:           || (nextf/ratio < startc+want-stencil_width)
586:           || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width))
587:         SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range");
588:     }
589:     lc[i] = want;
590:     startc += lc[i];
591:     startf += lf[i];
592:     remaining -= lc[i];
593:   }
594:   return(0);
595: }

599: PetscErrorCode  DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
600: {
602:   PetscInt       M,N,P;
603:   DM             da2;
604:   DM_DA          *dd = (DM_DA*)da->data,*dd2;


610:   if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
611:     M = dd->refine_x*dd->M;
612:   } else {
613:     M = 1 + dd->refine_x*(dd->M - 1);
614:   }
615:   if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
616:     N = dd->refine_y*dd->N;
617:   } else {
618:     N = 1 + dd->refine_y*(dd->N - 1);
619:   }
620:   if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
621:     P = dd->refine_z*dd->P;
622:   } else {
623:     P = 1 + dd->refine_z*(dd->P - 1);
624:   }
625:   if (dd->dim == 3) {
626:     PetscInt *lx,*ly,*lz;
627:     PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);
628:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
629:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
630:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);
631:     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);
632:     PetscFree3(lx,ly,lz);
633:   } else if (dd->dim == 2) {
634:     PetscInt *lx,*ly;
635:     PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);
636:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
637:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
638:     DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);
639:     PetscFree2(lx,ly);
640:   } else if (dd->dim == 1) {
641:     PetscInt *lx;
642:     PetscMalloc(dd->m*sizeof(PetscInt),&lx);
643:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
644:     DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);
645:     PetscFree(lx);
646:   }
647:   dd2 = (DM_DA*)da2->data;

649:   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
650:   da2->ops->getmatrix        = da->ops->getmatrix;
651:   /* da2->ops->getinterpolation = da->ops->getinterpolation; this causes problem with SNESVI */
652:   da2->ops->getcoloring      = da->ops->getcoloring;
653:   dd2->interptype            = dd->interptype;
654: 
655:   /* copy fill information if given */
656:   if (dd->dfill) {
657:     PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);
658:     PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));
659:   }
660:   if (dd->ofill) {
661:     PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);
662:     PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));
663:   }
664:   /* copy the refine information */
665:   dd2->refine_x = dd->refine_x;
666:   dd2->refine_y = dd->refine_y;
667:   dd2->refine_z = dd->refine_z;

669:   /* copy vector type information */
670:   PetscFree(da2->vectype);
671:   PetscStrallocpy(da->vectype,&da2->vectype);

673:   dd2->lf = dd->lf;
674:   dd2->lj = dd->lj;

676:   /* interpolate coordinates if they are set on the coarse grid */
677:   if (dd->coordinates) {
678:     DM  cdaf,cdac;
679:     Vec coordsc,coordsf;
680:     Mat II;
681: 
682:     DMDAGetCoordinateDA(da,&cdac);
683:     DMDAGetCoordinates(da,&coordsc);
684:     DMDAGetCoordinateDA(da2,&cdaf);
685:     /* force creation of the coordinate vector */
686:     DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);
687:     DMDAGetCoordinates(da2,&coordsf);
688:     DMGetInterpolation(cdac,cdaf,&II,PETSC_NULL);
689:     MatInterpolate(II,coordsc,coordsf);
690:     MatDestroy(&II);
691:   }
692:   *daref = da2;
693:   return(0);
694: }

698: PetscErrorCode  DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref)
699: {
701:   PetscInt       M,N,P;
702:   DM             da2;
703:   DM_DA          *dd = (DM_DA*)da->data,*dd2;


709:   if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
710:     M = dd->M / dd->refine_x;
711:   } else {
712:     M = 1 + (dd->M - 1) / dd->refine_x;
713:   }
714:   if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
715:     N = dd->N / dd->refine_y;
716:   } else {
717:     N = 1 + (dd->N - 1) / dd->refine_y;
718:   }
719:   if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
720:     P = dd->P / dd->refine_z;
721:   } else {
722:     P = 1 + (dd->P - 1) / dd->refine_z;
723:   }
724:   if (dd->dim == 3) {
725:     PetscInt *lx,*ly,*lz;
726:     PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);
727:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
728:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
729:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);
730:     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);
731:     PetscFree3(lx,ly,lz);
732:   } else if (dd->dim == 2) {
733:     PetscInt *lx,*ly;
734:     PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);
735:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
736:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
737:     DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);
738:     PetscFree2(lx,ly);
739:   } else if (dd->dim == 1) {
740:     PetscInt *lx;
741:     PetscMalloc(dd->m*sizeof(PetscInt),&lx);
742:     DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
743:     DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);
744:     PetscFree(lx);
745:   }
746:   dd2 = (DM_DA*)da2->data;

748:   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
749:   /* da2->ops->getinterpolation = da->ops->getinterpolation; copying this one causes trouble for DMSetVI */
750:   da2->ops->getmatrix        = da->ops->getmatrix;
751:   da2->ops->getcoloring      = da->ops->getcoloring;
752:   dd2->interptype            = dd->interptype;
753: 
754:   /* copy fill information if given */
755:   if (dd->dfill) {
756:     PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);
757:     PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));
758:   }
759:   if (dd->ofill) {
760:     PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);
761:     PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));
762:   }
763:   /* copy the refine information */
764:   dd2->refine_x = dd->refine_x;
765:   dd2->refine_y = dd->refine_y;
766:   dd2->refine_z = dd->refine_z;

768:   /* copy vector type information */
769:   PetscFree(da2->vectype);
770:   PetscStrallocpy(da->vectype,&da2->vectype);

772:   dd2->lf = dd->lf;
773:   dd2->lj = dd->lj;

775:   /* inject coordinates if they are set on the fine grid */
776:   if (dd->coordinates) {
777:     DM         cdaf,cdac;
778:     Vec        coordsc,coordsf;
779:     VecScatter inject;
780: 
781:     DMDAGetCoordinateDA(da,&cdaf);
782:     DMDAGetCoordinates(da,&coordsf);
783:     DMDAGetCoordinateDA(da2,&cdac);
784:     /* force creation of the coordinate vector */
785:     DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);
786:     DMDAGetCoordinates(da2,&coordsc);
787: 
788:     DMGetInjection(cdac,cdaf,&inject);
789:     VecScatterBegin(inject,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
790:     VecScatterEnd(inject  ,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
791:     VecScatterDestroy(&inject);
792:   }
793:   *daref = da2;
794:   return(0);
795: }

799: PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
800: {
802:   PetscInt       i,n,*refx,*refy,*refz;

806:   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
807:   if (nlevels == 0) return(0);

810:   /* Get refinement factors, defaults taken from the coarse DMDA */
811:   PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);
812:   for (i=0; i<nlevels; i++) {
813:     DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);
814:   }
815:   n = nlevels;
816:   PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);
817:   n = nlevels;
818:   PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);
819:   n = nlevels;
820:   PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);

822:   DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);
823:   DMRefine(da,((PetscObject)da)->comm,&daf[0]);
824:   for (i=1; i<nlevels; i++) {
825:     DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);
826:     DMRefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);
827:   }
828:   PetscFree3(refx,refy,refz);
829:   return(0);
830: }

834: PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
835: {
837:   PetscInt       i;

841:   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
842:   if (nlevels == 0) return(0);
844:   DMCoarsen(da,((PetscObject)da)->comm,&dac[0]);
845:   for (i=1; i<nlevels; i++) {
846:     DMCoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);
847:   }
848:   return(0);
849: }