Actual source code: da.c

  1: #include <petsc/private/dmdaimpl.h>

  3: /*@
  4:   DMDASetSizes - Sets the number of grid points in the three dimensional directions

  6:   Logically Collective on da

  8:   Input Parameters:
  9: + da - the DMDA
 10: . M - the global X size
 11: . N - the global Y size
 12: - P - the global Z size

 14:   Level: intermediate

 16:   Developer Notes:
 17:   Since the dimension may not yet have been set the code cannot error check for non-positive Y and Z number of grid points

 19: .seealso: PetscSplitOwnership()
 20: @*/
 21: PetscErrorCode  DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P)
 22: {
 23:   DM_DA *dd = (DM_DA*)da->data;

 30:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
 31:   if (M < 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in X direction must be positive");
 32:   if (N < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in Y direction must be positive");
 33:   if (P < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in Z direction must be positive");

 35:   dd->M = M;
 36:   dd->N = N;
 37:   dd->P = P;
 38:   return(0);
 39: }

 41: /*@
 42:   DMDASetNumProcs - Sets the number of processes in each dimension

 44:   Logically Collective on da

 46:   Input Parameters:
 47: + da - the DMDA
 48: . m - the number of X procs (or PETSC_DECIDE)
 49: . n - the number of Y procs (or PETSC_DECIDE)
 50: - p - the number of Z procs (or PETSC_DECIDE)

 52:   Level: intermediate

 54: .seealso: DMDASetSizes(), PetscSplitOwnership()
 55: @*/
 56: PetscErrorCode  DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p)
 57: {
 58:   DM_DA          *dd = (DM_DA*)da->data;

 66:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
 67:   dd->m = m;
 68:   dd->n = n;
 69:   dd->p = p;
 70:   if (da->dim == 2) {
 71:     PetscMPIInt size;
 72:     MPI_Comm_size(PetscObjectComm((PetscObject)da),&size);
 73:     if ((dd->m > 0) && (dd->n < 0)) {
 74:       dd->n = size/dd->m;
 75:       if (dd->n*dd->m != size) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%D processes in X direction not divisible into comm size %d",m,size);
 76:     }
 77:     if ((dd->n > 0) && (dd->m < 0)) {
 78:       dd->m = size/dd->n;
 79:       if (dd->n*dd->m != size) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%D processes in Y direction not divisible into comm size %d",n,size);
 80:     }
 81:   }
 82:   return(0);
 83: }

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

 88:   Not collective

 90:   Input Parameters:
 91: + da    - The DMDA
 92: - bx,by,bz - One of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC

 94:   Level: intermediate

 96: .seealso: DMDACreate(), DMDestroy(), DMDA, DMBoundaryType
 97: @*/
 98: PetscErrorCode  DMDASetBoundaryType(DM da,DMBoundaryType bx,DMBoundaryType by,DMBoundaryType bz)
 99: {
100:   DM_DA *dd = (DM_DA*)da->data;

107:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
108:   dd->bx = bx;
109:   dd->by = by;
110:   dd->bz = bz;
111:   return(0);
112: }

114: /*@
115:   DMDASetDof - Sets the number of degrees of freedom per vertex

117:   Not collective

119:   Input Parameters:
120: + da  - The DMDA
121: - dof - Number of degrees of freedom

123:   Level: intermediate

125: .seealso: DMDAGetDof(), DMDACreate(), DMDestroy(), DMDA
126: @*/
127: PetscErrorCode  DMDASetDof(DM da, PetscInt dof)
128: {
129:   DM_DA *dd = (DM_DA*)da->data;

134:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
135:   dd->w  = dof;
136:   da->bs = dof;
137:   return(0);
138: }

140: /*@
141:   DMDAGetDof - Gets the number of degrees of freedom per vertex

143:   Not collective

145:   Input Parameter:
146: . da  - The DMDA

148:   Output Parameter:
149: . dof - Number of degrees of freedom

151:   Level: intermediate

153: .seealso: DMDASetDof(), DMDACreate(), DMDestroy(), DMDA
154: @*/
155: PetscErrorCode DMDAGetDof(DM da, PetscInt *dof)
156: {
157:   DM_DA *dd = (DM_DA *) da->data;

162:   *dof = dd->w;
163:   return(0);
164: }

166: /*@
167:   DMDAGetOverlap - Gets the size of the per-processor overlap.

169:   Not collective

171:   Input Parameter:
172: . da  - The DMDA

174:   Output Parameters:
175: + x   - Overlap in the x direction
176: . y   - Overlap in the y direction
177: - z   - Overlap in the z direction

179:   Level: intermediate

181: .seealso: DMDACreateDomainDecomposition(), DMDASetOverlap(), DMDA
182: @*/
183: PetscErrorCode  DMDAGetOverlap(DM da,PetscInt *x,PetscInt *y,PetscInt *z)
184: {
185:   DM_DA *dd = (DM_DA*)da->data;

189:   if (x) *x = dd->xol;
190:   if (y) *y = dd->yol;
191:   if (z) *z = dd->zol;
192:   return(0);
193: }

195: /*@
196:   DMDASetOverlap - Sets the size of the per-processor overlap.

198:   Not collective

200:   Input Parameters:
201: + da  - The DMDA
202: . x   - Overlap in the x direction
203: . y   - Overlap in the y direction
204: - z   - Overlap in the z direction

206:   Level: intermediate

208: .seealso: DMDACreateDomainDecomposition(), DMDAGetOverlap(), DMDA
209: @*/
210: PetscErrorCode  DMDASetOverlap(DM da,PetscInt x,PetscInt y,PetscInt z)
211: {
212:   DM_DA *dd = (DM_DA*)da->data;

219:   dd->xol = x;
220:   dd->yol = y;
221:   dd->zol = z;
222:   return(0);
223: }

225: /*@
226:   DMDAGetNumLocalSubDomains - Gets the number of local subdomains created upon decomposition.

228:   Not collective

230:   Input Parameters:
231: . da  - The DMDA

233:   Output Parameters:
234: . Nsub   - Number of local subdomains created upon decomposition

236:   Level: intermediate

238: .seealso: DMDACreateDomainDecomposition(), DMDASetNumLocalSubDomains(), DMDA
239: @*/
240: PetscErrorCode  DMDAGetNumLocalSubDomains(DM da,PetscInt *Nsub)
241: {
242:   DM_DA *dd = (DM_DA*)da->data;

246:   if (Nsub) *Nsub = dd->Nsub;
247:   return(0);
248: }

250: /*@
251:   DMDASetNumLocalSubDomains - Sets the number of local subdomains created upon decomposition.

253:   Not collective

255:   Input Parameters:
256: + da  - The DMDA
257: - Nsub - The number of local subdomains requested

259:   Level: intermediate

261: .seealso: DMDACreateDomainDecomposition(), DMDAGetNumLocalSubDomains(), DMDA
262: @*/
263: PetscErrorCode  DMDASetNumLocalSubDomains(DM da,PetscInt Nsub)
264: {
265:   DM_DA *dd = (DM_DA*)da->data;

270:   dd->Nsub = Nsub;
271:   return(0);
272: }

274: /*@
275:   DMDASetOffset - Sets the index offset of the DA.

277:   Collective on DA

279:   Input Parameters:
280: + da  - The DMDA
281: . xo  - The offset in the x direction
282: . yo  - The offset in the y direction
283: - zo  - The offset in the z direction

285:   Level: intermediate

287:   Notes:
288:     This is used primarily to overlap a computation on a local DA with that on a global DA without
289:   changing boundary conditions or subdomain features that depend upon the global offsets.

291: .seealso: DMDAGetOffset(), DMDAVecGetArray()
292: @*/
293: PetscErrorCode  DMDASetOffset(DM da, PetscInt xo, PetscInt yo, PetscInt zo, PetscInt Mo, PetscInt No, PetscInt Po)
294: {
296:   DM_DA          *dd = (DM_DA*)da->data;

306:   dd->xo = xo;
307:   dd->yo = yo;
308:   dd->zo = zo;
309:   dd->Mo = Mo;
310:   dd->No = No;
311:   dd->Po = Po;

313:   if (da->coordinateDM) {
314:     DMDASetOffset(da->coordinateDM,xo,yo,zo,Mo,No,Po);
315:   }
316:   return(0);
317: }

319: /*@
320:   DMDAGetOffset - Gets the index offset of the DA.

322:   Not collective

324:   Input Parameter:
325: . da  - The DMDA

327:   Output Parameters:
328: + xo  - The offset in the x direction
329: . yo  - The offset in the y direction
330: . zo  - The offset in the z direction
331: . Mo  - The global size in the x direction
332: . No  - The global size in the y direction
333: - Po  - The global size in the z direction

335:   Level: intermediate

337: .seealso: DMDASetOffset(), DMDAVecGetArray()
338: @*/
339: PetscErrorCode  DMDAGetOffset(DM da,PetscInt *xo,PetscInt *yo,PetscInt *zo,PetscInt *Mo,PetscInt *No,PetscInt *Po)
340: {
341:   DM_DA *dd = (DM_DA*)da->data;

345:   if (xo) *xo = dd->xo;
346:   if (yo) *yo = dd->yo;
347:   if (zo) *zo = dd->zo;
348:   if (Mo) *Mo = dd->Mo;
349:   if (No) *No = dd->No;
350:   if (Po) *Po = dd->Po;
351:   return(0);
352: }

354: /*@
355:   DMDAGetNonOverlappingRegion - Gets the indices of the nonoverlapping region of a subdomain DM.

357:   Not collective

359:   Input Parameter:
360: . da  - The DMDA

362:   Output Parameters:
363: + xs  - The start of the region in x
364: . ys  - The start of the region in y
365: . zs  - The start of the region in z
366: . xs  - The size of the region in x
367: . ys  - The size of the region in y
368: - zs  - The size of the region in z

370:   Level: intermediate

372: .seealso: DMDAGetOffset(), DMDAVecGetArray()
373: @*/
374: PetscErrorCode  DMDAGetNonOverlappingRegion(DM da, PetscInt *xs, PetscInt *ys, PetscInt *zs, PetscInt *xm, PetscInt *ym, PetscInt *zm)
375: {
376:   DM_DA          *dd = (DM_DA*)da->data;

380:   if (xs) *xs = dd->nonxs;
381:   if (ys) *ys = dd->nonys;
382:   if (zs) *zs = dd->nonzs;
383:   if (xm) *xm = dd->nonxm;
384:   if (ym) *ym = dd->nonym;
385:   if (zm) *zm = dd->nonzm;
386:   return(0);
387: }

389: /*@
390:   DMDASetNonOverlappingRegion - Sets the indices of the nonoverlapping region of a subdomain DM.

392:   Collective on DA

394:   Input Parameters:
395: + da  - The DMDA
396: . xs  - The start of the region in x
397: . ys  - The start of the region in y
398: . zs  - The start of the region in z
399: . xs  - The size of the region in x
400: . ys  - The size of the region in y
401: - zs  - The size of the region in z

403:   Level: intermediate

405: .seealso: DMDAGetOffset(), DMDAVecGetArray()
406: @*/
407: PetscErrorCode  DMDASetNonOverlappingRegion(DM da, PetscInt xs, PetscInt ys, PetscInt zs, PetscInt xm, PetscInt ym, PetscInt zm)
408: {
409:   DM_DA          *dd = (DM_DA*)da->data;

419:   dd->nonxs = xs;
420:   dd->nonys = ys;
421:   dd->nonzs = zs;
422:   dd->nonxm = xm;
423:   dd->nonym = ym;
424:   dd->nonzm = zm;

426:   return(0);
427: }

429: /*@
430:   DMDASetStencilType - Sets the type of the communication stencil

432:   Logically Collective on da

434:   Input Parameters:
435: + da    - The DMDA
436: - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.

438:   Level: intermediate

440: .seealso: DMDACreate(), DMDestroy(), DMDA
441: @*/
442: PetscErrorCode  DMDASetStencilType(DM da, DMDAStencilType stype)
443: {
444:   DM_DA *dd = (DM_DA*)da->data;

449:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
450:   dd->stencil_type = stype;
451:   return(0);
452: }

454: /*@
455:   DMDAGetStencilType - Gets the type of the communication stencil

457:   Not collective

459:   Input Parameter:
460: . da    - The DMDA

462:   Output Parameter:
463: . stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.

465:   Level: intermediate

467: .seealso: DMDACreate(), DMDestroy(), DMDA
468: @*/
469: PetscErrorCode DMDAGetStencilType(DM da, DMDAStencilType *stype)
470: {
471:   DM_DA *dd = (DM_DA*)da->data;

476:   *stype = dd->stencil_type;
477:   return(0);
478: }

480: /*@
481:   DMDASetStencilWidth - Sets the width of the communication stencil

483:   Logically Collective on da

485:   Input Parameters:
486: + da    - The DMDA
487: - width - The stencil width

489:   Level: intermediate

491: .seealso: DMDACreate(), DMDestroy(), DMDA
492: @*/
493: PetscErrorCode  DMDASetStencilWidth(DM da, PetscInt width)
494: {
495:   DM_DA *dd = (DM_DA*)da->data;

500:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
501:   dd->s = width;
502:   return(0);
503: }

505: /*@
506:   DMDAGetStencilWidth - Gets the width of the communication stencil

508:   Not collective

510:   Input Parameter:
511: . da    - The DMDA

513:   Output Parameter:
514: . width - The stencil width

516:   Level: intermediate

518: .seealso: DMDACreate(), DMDestroy(), DMDA
519: @*/
520: PetscErrorCode DMDAGetStencilWidth(DM da, PetscInt *width)
521: {
522:   DM_DA *dd = (DM_DA *) da->data;

527:   *width = dd->s;
528:   return(0);
529: }

531: static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
532: {
533:   PetscInt i,sum;

536:   if (M < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
537:   for (i=sum=0; i<m; i++) sum += lx[i];
538:   if (sum != M) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M);
539:   return(0);
540: }

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

545:   Logically Collective on da

547:   Input Parameters:
548: + da - The DMDA
549: . lx - array containing number of nodes in the X direction on each process, or NULL. If non-null, must be of length da->m
550: . ly - array containing number of nodes in the Y direction on each process, or NULL. If non-null, must be of length da->n
551: - lz - array containing number of nodes in the Z direction on each process, or NULL. If non-null, must be of length da->p.

553:   Level: intermediate

555:   Note: these numbers are NOT multiplied by the number of dof per node.

557: .seealso: DMDACreate(), DMDestroy(), DMDA
558: @*/
559: PetscErrorCode  DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
560: {
562:   DM_DA          *dd = (DM_DA*)da->data;

566:   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
567:   if (lx) {
568:     if (dd->m < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
569:     DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);
570:     if (!dd->lx) {
571:       PetscMalloc1(dd->m, &dd->lx);
572:     }
573:     PetscArraycpy(dd->lx, lx, dd->m);
574:   }
575:   if (ly) {
576:     if (dd->n < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
577:     DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);
578:     if (!dd->ly) {
579:       PetscMalloc1(dd->n, &dd->ly);
580:     }
581:     PetscArraycpy(dd->ly, ly, dd->n);
582:   }
583:   if (lz) {
584:     if (dd->p < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
585:     DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);
586:     if (!dd->lz) {
587:       PetscMalloc1(dd->p, &dd->lz);
588:     }
589:     PetscArraycpy(dd->lz, lz, dd->p);
590:   }
591:   return(0);
592: }

594: /*@
595:        DMDASetInterpolationType - Sets the type of interpolation that will be
596:           returned by DMCreateInterpolation()

598:    Logically Collective on da

600:    Input Parameters:
601: +  da - initial distributed array
602: -  ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms

604:    Level: intermediate

606:    Notes:
607:     you should call this on the coarser of the two DMDAs you pass to DMCreateInterpolation()

609: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType
610: @*/
611: PetscErrorCode  DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
612: {
613:   DM_DA *dd = (DM_DA*)da->data;

618:   dd->interptype = ctype;
619:   return(0);
620: }

622: /*@
623:        DMDAGetInterpolationType - Gets the type of interpolation that will be
624:           used by DMCreateInterpolation()

626:    Not Collective

628:    Input Parameter:
629: .  da - distributed array

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

634:    Level: intermediate

636: .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMCreateInterpolation()
637: @*/
638: PetscErrorCode  DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
639: {
640:   DM_DA *dd = (DM_DA*)da->data;

645:   *ctype = dd->interptype;
646:   return(0);
647: }

649: /*@C
650:       DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
651:         processes neighbors.

653:     Not Collective

655:    Input Parameter:
656: .     da - the DMDA object

658:    Output Parameters:
659: .     ranks - the neighbors ranks, stored with the x index increasing most rapidly.
660:               this process itself is in the list

662:    Notes:
663:     In 2d the array is of length 9, in 3d of length 27
664:           Not supported in 1d
665:           Do not free the array, it is freed when the DMDA is destroyed.

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

670:    Level: intermediate

672: @*/
673: PetscErrorCode  DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
674: {
675:   DM_DA *dd = (DM_DA*)da->data;

679:   *ranks = dd->neighbors;
680:   return(0);
681: }

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

686:     Not Collective

688:    Input Parameter:
689: .     da - the DMDA object

691:    Output Parameters:
692: +     lx - ownership along x direction (optional)
693: .     ly - ownership along y direction (optional)
694: -     lz - ownership along z direction (optional)

696:    Level: intermediate

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

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

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

706:     These numbers are NOT multiplied by the number of dof per node.

708: .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges()
709: @*/
710: PetscErrorCode  DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
711: {
712:   DM_DA *dd = (DM_DA*)da->data;

716:   if (lx) *lx = dd->lx;
717:   if (ly) *ly = dd->ly;
718:   if (lz) *lz = dd->lz;
719:   return(0);
720: }

722: /*@
723:      DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined

725:     Logically Collective on da

727:   Input Parameters:
728: +    da - the DMDA object
729: .    refine_x - ratio of fine grid to coarse in x direction (2 by default)
730: .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
731: -    refine_z - ratio of fine grid to coarse in z direction (2 by default)

733:   Options Database:
734: +  -da_refine_x refine_x - refinement ratio in x direction
735: .  -da_refine_y rafine_y - refinement ratio in y direction
736: .  -da_refine_z refine_z - refinement ratio in z direction
737: -  -da_refine <n> - refine the DMDA object n times when it is created.

739:   Level: intermediate

741:     Notes:
742:     Pass PETSC_IGNORE to leave a value unchanged

744: .seealso: DMRefine(), DMDAGetRefinementFactor()
745: @*/
746: PetscErrorCode  DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
747: {
748:   DM_DA *dd = (DM_DA*)da->data;


756:   if (refine_x > 0) dd->refine_x = refine_x;
757:   if (refine_y > 0) dd->refine_y = refine_y;
758:   if (refine_z > 0) dd->refine_z = refine_z;
759:   return(0);
760: }

762: /*@C
763:      DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined

765:     Not Collective

767:   Input Parameter:
768: .    da - the DMDA object

770:   Output Parameters:
771: +    refine_x - ratio of fine grid to coarse in x direction (2 by default)
772: .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
773: -    refine_z - ratio of fine grid to coarse in z direction (2 by default)

775:   Level: intermediate

777:     Notes:
778:     Pass NULL for values you do not need

780: .seealso: DMRefine(), DMDASetRefinementFactor()
781: @*/
782: PetscErrorCode  DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
783: {
784:   DM_DA *dd = (DM_DA*)da->data;

788:   if (refine_x) *refine_x = dd->refine_x;
789:   if (refine_y) *refine_y = dd->refine_y;
790:   if (refine_z) *refine_z = dd->refine_z;
791:   return(0);
792: }

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

797:     Logically Collective on da

799:   Input Parameters:
800: +    da - the DMDA object
801: -    f - the function that allocates the matrix for that specific DMDA

803:   Level: developer

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

809:    Not supported from Fortran

811: .seealso: DMCreateMatrix(), DMDASetBlockFills()
812: @*/
813: PetscErrorCode  DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, Mat*))
814: {
817:   da->ops->creatematrix = f;
818:   return(0);
819: }

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

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

833:   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
834:   if (ratio == 1) {
835:     PetscArraycpy(lf,lc,m);
836:     return(0);
837:   }
838:   for (i=0; i<m; i++) totalc += lc[i];
839:   remaining = (!periodic) + ratio * (totalc - (!periodic));
840:   for (i=0; i<m; i++) {
841:     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
842:     if (i == m-1) lf[i] = want;
843:     else {
844:       const PetscInt nextc = startc + lc[i];
845:       /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
846:        * coarse stencil width of the first coarse node in the next subdomain. */
847:       while ((startf+want)/ratio < nextc - stencil_width) want++;
848:       /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
849:        * coarse stencil width of the last coarse node in the current subdomain. */
850:       while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
851:       /* Make sure all constraints are satisfied */
852:       if (want < 0 || want > remaining || ((startf+want)/ratio < nextc - stencil_width)
853:           || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range");
854:     }
855:     lf[i]      = want;
856:     startc    += lc[i];
857:     startf    += lf[i];
858:     remaining -= lf[i];
859:   }
860:   return(0);
861: }

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

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

875:   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
876:   if (ratio == 1) {
877:     PetscArraycpy(lc,lf,m);
878:     return(0);
879:   }
880:   for (i=0,totalf=0; i<m; i++) totalf += lf[i];
881:   remaining = (!periodic) + (totalf - (!periodic)) / ratio;
882:   for (i=0,startc=0,startf=0; i<m; i++) {
883:     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
884:     if (i == m-1) lc[i] = want;
885:     else {
886:       const PetscInt nextf = startf+lf[i];
887:       /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
888:        * node is within one stencil width. */
889:       while (nextf/ratio < startc+want-stencil_width) want--;
890:       /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
891:        * fine node is within one stencil width. */
892:       while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
893:       if (want < 0 || want > remaining
894:           || (nextf/ratio < startc+want-stencil_width) || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range");
895:     }
896:     lc[i]      = want;
897:     startc    += lc[i];
898:     startf    += lf[i];
899:     remaining -= lc[i];
900:   }
901:   return(0);
902: }

904: PetscErrorCode  DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
905: {
907:   PetscInt       M,N,P,i,dim;
908:   DM             da2;
909:   DM_DA          *dd = (DM_DA*)da->data,*dd2;


915:   DMGetDimension(da, &dim);
916:   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
917:     M = dd->refine_x*dd->M;
918:   } else {
919:     M = 1 + dd->refine_x*(dd->M - 1);
920:   }
921:   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
922:     if (dim > 1) {
923:       N = dd->refine_y*dd->N;
924:     } else {
925:       N = 1;
926:     }
927:   } else {
928:     N = 1 + dd->refine_y*(dd->N - 1);
929:   }
930:   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
931:     if (dim > 2) {
932:       P = dd->refine_z*dd->P;
933:     } else {
934:       P = 1;
935:     }
936:   } else {
937:     P = 1 + dd->refine_z*(dd->P - 1);
938:   }
939:   DMDACreate(PetscObjectComm((PetscObject)da),&da2);
940:   DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);
941:   DMSetDimension(da2,dim);
942:   DMDASetSizes(da2,M,N,P);
943:   DMDASetNumProcs(da2,dd->m,dd->n,dd->p);
944:   DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);
945:   DMDASetDof(da2,dd->w);
946:   DMDASetStencilType(da2,dd->stencil_type);
947:   DMDASetStencilWidth(da2,dd->s);
948:   if (dim == 3) {
949:     PetscInt *lx,*ly,*lz;
950:     PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);
951:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
952:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
953:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);
954:     DMDASetOwnershipRanges(da2,lx,ly,lz);
955:     PetscFree3(lx,ly,lz);
956:   } else if (dim == 2) {
957:     PetscInt *lx,*ly;
958:     PetscMalloc2(dd->m,&lx,dd->n,&ly);
959:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
960:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
961:     DMDASetOwnershipRanges(da2,lx,ly,NULL);
962:     PetscFree2(lx,ly);
963:   } else if (dim == 1) {
964:     PetscInt *lx;
965:     PetscMalloc1(dd->m,&lx);
966:     DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
967:     DMDASetOwnershipRanges(da2,lx,NULL,NULL);
968:     PetscFree(lx);
969:   }
970:   dd2 = (DM_DA*)da2->data;

972:   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
973:   da2->ops->creatematrix = da->ops->creatematrix;
974:   /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */
975:   da2->ops->getcoloring = da->ops->getcoloring;
976:   dd2->interptype       = dd->interptype;

978:   /* copy fill information if given */
979:   if (dd->dfill) {
980:     PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);
981:     PetscArraycpy(dd2->dfill,dd->dfill,dd->dfill[dd->w]+dd->w+1);
982:   }
983:   if (dd->ofill) {
984:     PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);
985:     PetscArraycpy(dd2->ofill,dd->ofill,dd->ofill[dd->w]+dd->w+1);
986:   }
987:   /* copy the refine information */
988:   dd2->coarsen_x = dd2->refine_x = dd->refine_x;
989:   dd2->coarsen_y = dd2->refine_y = dd->refine_y;
990:   dd2->coarsen_z = dd2->refine_z = dd->refine_z;

992:   if (dd->refine_z_hier) {
993:     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_z_hier_n) {
994:       dd2->refine_z = dd->refine_z_hier[da->levelup - da->leveldown + 1];
995:     }
996:     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_z_hier_n) {
997:       dd2->coarsen_z = dd->refine_z_hier[da->levelup - da->leveldown];
998:     }
999:     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1000:     PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier);
1001:     PetscArraycpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n);
1002:   }
1003:   if (dd->refine_y_hier) {
1004:     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_y_hier_n) {
1005:       dd2->refine_y = dd->refine_y_hier[da->levelup - da->leveldown + 1];
1006:     }
1007:     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_y_hier_n) {
1008:       dd2->coarsen_y = dd->refine_y_hier[da->levelup - da->leveldown];
1009:     }
1010:     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1011:     PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier);
1012:     PetscArraycpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n);
1013:   }
1014:   if (dd->refine_x_hier) {
1015:     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_x_hier_n) {
1016:       dd2->refine_x = dd->refine_x_hier[da->levelup - da->leveldown + 1];
1017:     }
1018:     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_x_hier_n) {
1019:       dd2->coarsen_x = dd->refine_x_hier[da->levelup - da->leveldown];
1020:     }
1021:     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1022:     PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier);
1023:     PetscArraycpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n);
1024:   }

1026:   /* copy vector type information */
1027:   DMSetVecType(da2,da->vectype);

1029:   dd2->lf = dd->lf;
1030:   dd2->lj = dd->lj;

1032:   da2->leveldown = da->leveldown;
1033:   da2->levelup   = da->levelup + 1;

1035:   DMSetUp(da2);

1037:   /* interpolate coordinates if they are set on the coarse grid */
1038:   if (da->coordinates) {
1039:     DM  cdaf,cdac;
1040:     Vec coordsc,coordsf;
1041:     Mat II;

1043:     DMGetCoordinateDM(da,&cdac);
1044:     DMGetCoordinates(da,&coordsc);
1045:     DMGetCoordinateDM(da2,&cdaf);
1046:     /* force creation of the coordinate vector */
1047:     DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);
1048:     DMGetCoordinates(da2,&coordsf);
1049:     DMCreateInterpolation(cdac,cdaf,&II,NULL);
1050:     MatInterpolate(II,coordsc,coordsf);
1051:     MatDestroy(&II);
1052:   }

1054:   for (i=0; i<da->bs; i++) {
1055:     const char *fieldname;
1056:     DMDAGetFieldName(da,i,&fieldname);
1057:     DMDASetFieldName(da2,i,fieldname);
1058:   }

1060:   *daref = da2;
1061:   return(0);
1062: }

1064: PetscErrorCode  DMCoarsen_DA(DM dmf, MPI_Comm comm,DM *dmc)
1065: {
1067:   PetscInt       M,N,P,i,dim;
1068:   DM             dmc2;
1069:   DM_DA          *dd = (DM_DA*)dmf->data,*dd2;


1075:   DMGetDimension(dmf, &dim);
1076:   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1077:     M = dd->M / dd->coarsen_x;
1078:   } else {
1079:     M = 1 + (dd->M - 1) / dd->coarsen_x;
1080:   }
1081:   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1082:     if (dim > 1) {
1083:       N = dd->N / dd->coarsen_y;
1084:     } else {
1085:       N = 1;
1086:     }
1087:   } else {
1088:     N = 1 + (dd->N - 1) / dd->coarsen_y;
1089:   }
1090:   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1091:     if (dim > 2) {
1092:       P = dd->P / dd->coarsen_z;
1093:     } else {
1094:       P = 1;
1095:     }
1096:   } else {
1097:     P = 1 + (dd->P - 1) / dd->coarsen_z;
1098:   }
1099:   DMDACreate(PetscObjectComm((PetscObject)dmf),&dmc2);
1100:   DMSetOptionsPrefix(dmc2,((PetscObject)dmf)->prefix);
1101:   DMSetDimension(dmc2,dim);
1102:   DMDASetSizes(dmc2,M,N,P);
1103:   DMDASetNumProcs(dmc2,dd->m,dd->n,dd->p);
1104:   DMDASetBoundaryType(dmc2,dd->bx,dd->by,dd->bz);
1105:   DMDASetDof(dmc2,dd->w);
1106:   DMDASetStencilType(dmc2,dd->stencil_type);
1107:   DMDASetStencilWidth(dmc2,dd->s);
1108:   if (dim == 3) {
1109:     PetscInt *lx,*ly,*lz;
1110:     PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);
1111:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);
1112:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);
1113:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_z,dd->p,dd->lz,lz);
1114:     DMDASetOwnershipRanges(dmc2,lx,ly,lz);
1115:     PetscFree3(lx,ly,lz);
1116:   } else if (dim == 2) {
1117:     PetscInt *lx,*ly;
1118:     PetscMalloc2(dd->m,&lx,dd->n,&ly);
1119:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);
1120:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);
1121:     DMDASetOwnershipRanges(dmc2,lx,ly,NULL);
1122:     PetscFree2(lx,ly);
1123:   } else if (dim == 1) {
1124:     PetscInt *lx;
1125:     PetscMalloc1(dd->m,&lx);
1126:     DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);
1127:     DMDASetOwnershipRanges(dmc2,lx,NULL,NULL);
1128:     PetscFree(lx);
1129:   }
1130:   dd2 = (DM_DA*)dmc2->data;

1132:   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
1133:   /* dmc2->ops->createinterpolation = dmf->ops->createinterpolation; copying this one causes trouble for DMSetVI */
1134:   dmc2->ops->creatematrix = dmf->ops->creatematrix;
1135:   dmc2->ops->getcoloring  = dmf->ops->getcoloring;
1136:   dd2->interptype         = dd->interptype;

1138:   /* copy fill information if given */
1139:   if (dd->dfill) {
1140:     PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);
1141:     PetscArraycpy(dd2->dfill,dd->dfill,dd->dfill[dd->w]+dd->w+1);
1142:   }
1143:   if (dd->ofill) {
1144:     PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);
1145:     PetscArraycpy(dd2->ofill,dd->ofill,dd->ofill[dd->w]+dd->w+1);
1146:   }
1147:   /* copy the refine information */
1148:   dd2->coarsen_x = dd2->refine_x = dd->coarsen_x;
1149:   dd2->coarsen_y = dd2->refine_y = dd->coarsen_y;
1150:   dd2->coarsen_z = dd2->refine_z = dd->coarsen_z;

1152:   if (dd->refine_z_hier) {
1153:     if (dmf->levelup - dmf->leveldown -1 > -1 && dmf->levelup - dmf->leveldown - 1< dd->refine_z_hier_n) {
1154:       dd2->refine_z = dd->refine_z_hier[dmf->levelup - dmf->leveldown - 1];
1155:     }
1156:     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_z_hier_n) {
1157:       dd2->coarsen_z = dd->refine_z_hier[dmf->levelup - dmf->leveldown - 2];
1158:     }
1159:     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1160:     PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier);
1161:     PetscArraycpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n);
1162:   }
1163:   if (dd->refine_y_hier) {
1164:     if (dmf->levelup - dmf->leveldown - 1 > -1 && dmf->levelup - dmf->leveldown - 1< dd->refine_y_hier_n) {
1165:       dd2->refine_y = dd->refine_y_hier[dmf->levelup - dmf->leveldown - 1];
1166:     }
1167:     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_y_hier_n) {
1168:       dd2->coarsen_y = dd->refine_y_hier[dmf->levelup - dmf->leveldown - 2];
1169:     }
1170:     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1171:     PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier);
1172:     PetscArraycpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n);
1173:   }
1174:   if (dd->refine_x_hier) {
1175:     if (dmf->levelup - dmf->leveldown - 1 > -1 && dmf->levelup - dmf->leveldown - 1 < dd->refine_x_hier_n) {
1176:       dd2->refine_x = dd->refine_x_hier[dmf->levelup - dmf->leveldown - 1];
1177:     }
1178:     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_x_hier_n) {
1179:       dd2->coarsen_x = dd->refine_x_hier[dmf->levelup - dmf->leveldown - 2];
1180:     }
1181:     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1182:     PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier);
1183:     PetscArraycpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n);
1184:   }

1186:   /* copy vector type information */
1187:   DMSetVecType(dmc2,dmf->vectype);

1189:   dd2->lf = dd->lf;
1190:   dd2->lj = dd->lj;

1192:   dmc2->leveldown = dmf->leveldown + 1;
1193:   dmc2->levelup   = dmf->levelup;

1195:   DMSetUp(dmc2);

1197:   /* inject coordinates if they are set on the fine grid */
1198:   if (dmf->coordinates) {
1199:     DM         cdaf,cdac;
1200:     Vec        coordsc,coordsf;
1201:     Mat        inject;
1202:     VecScatter vscat;

1204:     DMGetCoordinateDM(dmf,&cdaf);
1205:     DMGetCoordinates(dmf,&coordsf);
1206:     DMGetCoordinateDM(dmc2,&cdac);
1207:     /* force creation of the coordinate vector */
1208:     DMDASetUniformCoordinates(dmc2,0.0,1.0,0.0,1.0,0.0,1.0);
1209:     DMGetCoordinates(dmc2,&coordsc);

1211:     DMCreateInjection(cdac,cdaf,&inject);
1212:     MatScatterGetVecScatter(inject,&vscat);
1213:     VecScatterBegin(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
1214:     VecScatterEnd(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
1215:     MatDestroy(&inject);
1216:   }

1218:   for (i=0; i<dmf->bs; i++) {
1219:     const char *fieldname;
1220:     DMDAGetFieldName(dmf,i,&fieldname);
1221:     DMDASetFieldName(dmc2,i,fieldname);
1222:   }

1224:   *dmc = dmc2;
1225:   return(0);
1226: }

1228: PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
1229: {
1231:   PetscInt       i,n,*refx,*refy,*refz;

1235:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1236:   if (nlevels == 0) return(0);

1239:   /* Get refinement factors, defaults taken from the coarse DMDA */
1240:   PetscMalloc3(nlevels,&refx,nlevels,&refy,nlevels,&refz);
1241:   for (i=0; i<nlevels; i++) {
1242:     DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);
1243:   }
1244:   n    = nlevels;
1245:   PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,NULL);
1246:   n    = nlevels;
1247:   PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,NULL);
1248:   n    = nlevels;
1249:   PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,NULL);

1251:   DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);
1252:   DMRefine(da,PetscObjectComm((PetscObject)da),&daf[0]);
1253:   for (i=1; i<nlevels; i++) {
1254:     DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);
1255:     DMRefine(daf[i-1],PetscObjectComm((PetscObject)da),&daf[i]);
1256:   }
1257:   PetscFree3(refx,refy,refz);
1258:   return(0);
1259: }

1261: PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
1262: {
1264:   PetscInt       i;

1268:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1269:   if (nlevels == 0) return(0);
1271:   DMCoarsen(da,PetscObjectComm((PetscObject)da),&dac[0]);
1272:   for (i=1; i<nlevels; i++) {
1273:     DMCoarsen(dac[i-1],PetscObjectComm((PetscObject)da),&dac[i]);
1274:   }
1275:   return(0);
1276: }

1278: PetscErrorCode DMDASetGLLCoordinates_1d(DM dm,PetscInt n,PetscReal *nodes)
1279: {
1281:   PetscInt       i,j,xs,xn,q;
1282:   PetscScalar    *xx;
1283:   PetscReal      h;
1284:   Vec            x;
1285:   DM_DA          *da = (DM_DA*)dm->data;

1288:   if (da->bx != DM_BOUNDARY_PERIODIC) {
1289:     DMDAGetInfo(dm,NULL,&q,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
1290:     q    = (q-1)/(n-1);  /* number of spectral elements */
1291:     h    = 2.0/q;
1292:     DMDAGetCorners(dm,&xs,NULL,NULL,&xn,NULL,NULL);
1293:     xs   = xs/(n-1);
1294:     xn   = xn/(n-1);
1295:     DMDASetUniformCoordinates(dm,-1.,1.,0.,0.,0.,0.);
1296:     DMGetCoordinates(dm,&x);
1297:     DMDAVecGetArray(dm,x,&xx);

1299:     /* loop over local spectral elements */
1300:     for (j=xs; j<xs+xn; j++) {
1301:       /*
1302:        Except for the first process, each process starts on the second GLL point of the first element on that process
1303:        */
1304:       for (i= (j == xs && xs > 0)? 1 : 0; i<n; i++) {
1305:         xx[j*(n-1) + i] = -1.0 + h*j + h*(nodes[i]+1.0)/2.;
1306:       }
1307:     }
1308:     DMDAVecRestoreArray(dm,x,&xx);
1309:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for periodic");
1310:   return(0);
1311: }

1313: /*@

1315:      DMDASetGLLCoordinates - Sets the global coordinates from -1 to 1 to the GLL points of as many GLL elements that fit the number of grid points

1317:    Collective on da

1319:    Input Parameters:
1320: +   da - the DMDA object
1321: -   n - the number of GLL nodes
1322: -   nodes - the GLL nodes

1324:    Notes:
1325:     the parallel decomposition of grid points must correspond to the degree of the GLL. That is, the number of grid points
1326:           on each process much be divisible by the number of GLL elements needed per process. This depends on whether the DM is
1327:           periodic or not.

1329:    Level: advanced

1331: .seealso:   DMDACreate(), PetscDTGaussLobattoLegendreQuadrature(), DMGetCoordinates()
1332: @*/
1333: PetscErrorCode DMDASetGLLCoordinates(DM da,PetscInt n,PetscReal *nodes)
1334: {

1338:   if (da->dim == 1) {
1339:     DMDASetGLLCoordinates_1d(da,n,nodes);
1340:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for 2 or 3d");
1341:   return(0);
1342: }

1344: PETSC_INTERN PetscErrorCode DMGetCompatibility_DA(DM da1,DM dm2,PetscBool *compatible,PetscBool *set)
1345: {
1347:   DM_DA          *dd1 = (DM_DA*)da1->data,*dd2;
1348:   DM             da2;
1349:   DMType         dmtype2;
1350:   PetscBool      isda,compatibleLocal;
1351:   PetscInt       i;

1354:   if (!da1->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da1),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on first DM before DMGetCompatibility()");
1355:   DMGetType(dm2,&dmtype2);
1356:   PetscStrcmp(dmtype2,DMDA,&isda);
1357:   if (isda) {
1358:     da2 = dm2;
1359:     dd2 = (DM_DA*)da2->data;
1360:     if (!da2->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da2),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on second DM before DMGetCompatibility()");
1361:     compatibleLocal = (PetscBool)(da1->dim == da2->dim);
1362:     if (compatibleLocal) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->s == dd2->s)); /* Stencil width */
1363:     /*                                                                           Global size              ranks               Boundary type */
1364:     if (compatibleLocal)                 compatibleLocal = (PetscBool)(compatibleLocal && (dd1->M == dd2->M) && (dd1->m == dd2->m) && (dd1->bx == dd2->bx));
1365:     if (compatibleLocal && da1->dim > 1) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->N == dd2->N) && (dd1->n == dd2->n) && (dd1->by == dd2->by));
1366:     if (compatibleLocal && da1->dim > 2) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->P == dd2->P) && (dd1->p == dd2->p) && (dd1->bz == dd2->bz));
1367:     if (compatibleLocal) {
1368:       for (i=0; i<dd1->m; ++i) {
1369:         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lx[i] == dd2->lx[i]));           /* Local size     */
1370:       }
1371:     }
1372:     if (compatibleLocal && da1->dim > 1) {
1373:       for (i=0; i<dd1->n; ++i) {
1374:         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->ly[i] == dd2->ly[i]));
1375:       }
1376:     }
1377:     if (compatibleLocal && da1->dim > 2) {
1378:       for (i=0; i<dd1->p; ++i) {
1379:         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lz[i] == dd2->lz[i]));
1380:       }
1381:     }
1382:     *compatible = compatibleLocal;
1383:     *set = PETSC_TRUE;
1384:   } else {
1385:     /* Decline to determine compatibility with other DM types */
1386:     *set = PETSC_FALSE;
1387:   }
1388:   return(0);
1389: }