xref: /petsc/src/dm/impls/da/da.c (revision 07acc2aeea7a273014b10cda4fb272aa3ba8a1b1)
1 #include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/
2 
3 /*@
4   DMDASetSizes - Sets the number of grid points in the three dimensional directions
5 
6   Logically Collective on DMDA
7 
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
13 
14   Level: intermediate
15 
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
18 
19 .seealso: PetscSplitOwnership()
20 @*/
21 PetscErrorCode  DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P)
22 {
23   DM_DA *dd = (DM_DA*)da->data;
24 
25   PetscFunctionBegin;
26   PetscValidHeaderSpecificType(da, DM_CLASSID, 1,DMDA);
27   PetscValidLogicalCollectiveInt(da,M,2);
28   PetscValidLogicalCollectiveInt(da,N,3);
29   PetscValidLogicalCollectiveInt(da,P,4);
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");
34 
35   dd->M = M;
36   dd->N = N;
37   dd->P = P;
38   PetscFunctionReturn(0);
39 }
40 
41 /*@
42   DMDASetNumProcs - Sets the number of processes in each dimension
43 
44   Logically Collective on DMDA
45 
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)
51 
52   Level: intermediate
53 
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;
59   PetscErrorCode ierr;
60 
61   PetscFunctionBegin;
62   PetscValidHeaderSpecificType(da, DM_CLASSID, 1,DMDA);
63   PetscValidLogicalCollectiveInt(da,m,2);
64   PetscValidLogicalCollectiveInt(da,n,3);
65   PetscValidLogicalCollectiveInt(da,p,4);
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     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)da),&size);CHKERRQ(ierr);
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   PetscFunctionReturn(0);
83 }
84 
85 /*@
86   DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries.
87 
88   Not collective
89 
90   Input Parameter:
91 + da    - The DMDA
92 - bx,by,bz - One of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC
93 
94   Level: intermediate
95 
96 .keywords:  distributed array, periodicity
97 .seealso: DMDACreate(), DMDestroy(), DMDA, DMBoundaryType
98 @*/
99 PetscErrorCode  DMDASetBoundaryType(DM da,DMBoundaryType bx,DMBoundaryType by,DMBoundaryType bz)
100 {
101   DM_DA *dd = (DM_DA*)da->data;
102 
103   PetscFunctionBegin;
104   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
105   PetscValidLogicalCollectiveEnum(da,bx,2);
106   PetscValidLogicalCollectiveEnum(da,by,3);
107   PetscValidLogicalCollectiveEnum(da,bz,4);
108   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
109   dd->bx = bx;
110   dd->by = by;
111   dd->bz = bz;
112   PetscFunctionReturn(0);
113 }
114 
115 /*@
116   DMDASetDof - Sets the number of degrees of freedom per vertex
117 
118   Not collective
119 
120   Input Parameters:
121 + da  - The DMDA
122 - dof - Number of degrees of freedom
123 
124   Level: intermediate
125 
126 .keywords:  distributed array, degrees of freedom
127 .seealso: DMDAGetDof(), DMDACreate(), DMDestroy(), DMDA
128 @*/
129 PetscErrorCode  DMDASetDof(DM da, PetscInt dof)
130 {
131   DM_DA *dd = (DM_DA*)da->data;
132 
133   PetscFunctionBegin;
134   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
135   PetscValidLogicalCollectiveInt(da,dof,2);
136   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
137   dd->w  = dof;
138   da->bs = dof;
139   PetscFunctionReturn(0);
140 }
141 
142 /*@
143   DMDAGetDof - Gets the number of degrees of freedom per vertex
144 
145   Not collective
146 
147   Input Parameter:
148 . da  - The DMDA
149 
150   Output Parameter:
151 . dof - Number of degrees of freedom
152 
153   Level: intermediate
154 
155 .keywords:  distributed array, degrees of freedom
156 .seealso: DMDASetDof(), DMDACreate(), DMDestroy(), DMDA
157 @*/
158 PetscErrorCode DMDAGetDof(DM da, PetscInt *dof)
159 {
160   DM_DA *dd = (DM_DA *) da->data;
161 
162   PetscFunctionBegin;
163   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
164   PetscValidPointer(dof,2);
165   *dof = dd->w;
166   PetscFunctionReturn(0);
167 }
168 
169 /*@
170   DMDAGetOverlap - Gets the size of the per-processor overlap.
171 
172   Not collective
173 
174   Input Parameters:
175 . da  - The DMDA
176 
177   Output Parameters:
178 + x   - Overlap in the x direction
179 . y   - Overlap in the y direction
180 - z   - Overlap in the z direction
181 
182   Level: intermediate
183 
184 .keywords:  distributed array, overlap, domain decomposition
185 .seealso: DMDACreateDomainDecomposition(), DMDASetOverlap(), DMDA
186 @*/
187 PetscErrorCode  DMDAGetOverlap(DM da,PetscInt *x,PetscInt *y,PetscInt *z)
188 {
189   DM_DA *dd = (DM_DA*)da->data;
190 
191   PetscFunctionBegin;
192   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
193   if (x) *x = dd->xol;
194   if (y) *y = dd->yol;
195   if (z) *z = dd->zol;
196   PetscFunctionReturn(0);
197 }
198 
199 /*@
200   DMDASetOverlap - Sets the size of the per-processor overlap.
201 
202   Not collective
203 
204   Input Parameters:
205 + da  - The DMDA
206 . x   - Overlap in the x direction
207 . y   - Overlap in the y direction
208 - z   - Overlap in the z direction
209 
210   Level: intermediate
211 
212 .keywords:  distributed array, overlap, domain decomposition
213 .seealso: DMDACreateDomainDecomposition(), DMDAGetOverlap(), DMDA
214 @*/
215 PetscErrorCode  DMDASetOverlap(DM da,PetscInt x,PetscInt y,PetscInt z)
216 {
217   DM_DA *dd = (DM_DA*)da->data;
218 
219   PetscFunctionBegin;
220   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
221   PetscValidLogicalCollectiveInt(da,x,2);
222   PetscValidLogicalCollectiveInt(da,y,3);
223   PetscValidLogicalCollectiveInt(da,z,4);
224   dd->xol = x;
225   dd->yol = y;
226   dd->zol = z;
227   PetscFunctionReturn(0);
228 }
229 
230 
231 /*@
232   DMDAGetNumLocalSubDomains - Gets the number of local subdomains created upon decomposition.
233 
234   Not collective
235 
236   Input Parameters:
237 . da  - The DMDA
238 
239   Output Parameters:
240 + Nsub   - Number of local subdomains created upon decomposition
241 
242   Level: intermediate
243 
244 .keywords:  distributed array, domain decomposition
245 .seealso: DMDACreateDomainDecomposition(), DMDASetNumLocalSubDomains(), DMDA
246 @*/
247 PetscErrorCode  DMDAGetNumLocalSubDomains(DM da,PetscInt *Nsub)
248 {
249   DM_DA *dd = (DM_DA*)da->data;
250 
251   PetscFunctionBegin;
252   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
253   if (Nsub) *Nsub = dd->Nsub;
254   PetscFunctionReturn(0);
255 }
256 
257 /*@
258   DMDASetNumLocalSubDomains - Sets the number of local subdomains created upon decomposition.
259 
260   Not collective
261 
262   Input Parameters:
263 + da  - The DMDA
264 - Nsub - The number of local subdomains requested
265 
266   Level: intermediate
267 
268 .keywords:  distributed array, domain decomposition
269 .seealso: DMDACreateDomainDecomposition(), DMDAGetNumLocalSubDomains(), DMDA
270 @*/
271 PetscErrorCode  DMDASetNumLocalSubDomains(DM da,PetscInt Nsub)
272 {
273   DM_DA *dd = (DM_DA*)da->data;
274 
275   PetscFunctionBegin;
276   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
277   PetscValidLogicalCollectiveInt(da,Nsub,2);
278   dd->Nsub = Nsub;
279   PetscFunctionReturn(0);
280 }
281 
282 /*@
283   DMDASetOffset - Sets the index offset of the DA.
284 
285   Collective on DA
286 
287   Input Parameter:
288 + da  - The DMDA
289 . xo  - The offset in the x direction
290 . yo  - The offset in the y direction
291 - zo  - The offset in the z direction
292 
293   Level: intermediate
294 
295   Notes:
296     This is used primarily to overlap a computation on a local DA with that on a global DA without
297   changing boundary conditions or subdomain features that depend upon the global offsets.
298 
299 .keywords:  distributed array, degrees of freedom
300 .seealso: DMDAGetOffset(), DMDAVecGetArray()
301 @*/
302 PetscErrorCode  DMDASetOffset(DM da, PetscInt xo, PetscInt yo, PetscInt zo, PetscInt Mo, PetscInt No, PetscInt Po)
303 {
304   PetscErrorCode ierr;
305   DM_DA          *dd = (DM_DA*)da->data;
306 
307   PetscFunctionBegin;
308   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
309   PetscValidLogicalCollectiveInt(da,xo,2);
310   PetscValidLogicalCollectiveInt(da,yo,3);
311   PetscValidLogicalCollectiveInt(da,zo,4);
312   PetscValidLogicalCollectiveInt(da,Mo,5);
313   PetscValidLogicalCollectiveInt(da,No,6);
314   PetscValidLogicalCollectiveInt(da,Po,7);
315   dd->xo = xo;
316   dd->yo = yo;
317   dd->zo = zo;
318   dd->Mo = Mo;
319   dd->No = No;
320   dd->Po = Po;
321 
322   if (da->coordinateDM) {
323     ierr = DMDASetOffset(da->coordinateDM,xo,yo,zo,Mo,No,Po);CHKERRQ(ierr);
324   }
325   PetscFunctionReturn(0);
326 }
327 
328 /*@
329   DMDAGetOffset - Gets the index offset of the DA.
330 
331   Not collective
332 
333   Input Parameter:
334 . da  - The DMDA
335 
336   Output Parameters:
337 + xo  - The offset in the x direction
338 . yo  - The offset in the y direction
339 . zo  - The offset in the z direction
340 . Mo  - The global size in the x direction
341 . No  - The global size in the y direction
342 - Po  - The global size in the z direction
343 
344   Level: intermediate
345 
346 .keywords:  distributed array, degrees of freedom
347 .seealso: DMDASetOffset(), DMDAVecGetArray()
348 @*/
349 PetscErrorCode  DMDAGetOffset(DM da,PetscInt *xo,PetscInt *yo,PetscInt *zo,PetscInt *Mo,PetscInt *No,PetscInt *Po)
350 {
351   DM_DA *dd = (DM_DA*)da->data;
352 
353   PetscFunctionBegin;
354   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
355   if (xo) *xo = dd->xo;
356   if (yo) *yo = dd->yo;
357   if (zo) *zo = dd->zo;
358   if (Mo) *Mo = dd->Mo;
359   if (No) *No = dd->No;
360   if (Po) *Po = dd->Po;
361   PetscFunctionReturn(0);
362 }
363 
364 /*@
365   DMDAGetNonOverlappingRegion - Gets the indices of the nonoverlapping region of a subdomain DM.
366 
367   Not collective
368 
369   Input Parameter:
370 . da  - The DMDA
371 
372   Output Parameters:
373 + xs  - The start of the region in x
374 . ys  - The start of the region in y
375 . zs  - The start of the region in z
376 . xs  - The size of the region in x
377 . ys  - The size of the region in y
378 . zs  - The size of the region in z
379 
380   Level: intermediate
381 
382 .keywords:  distributed array, degrees of freedom
383 .seealso: DMDAGetOffset(), DMDAVecGetArray()
384 @*/
385 PetscErrorCode  DMDAGetNonOverlappingRegion(DM da, PetscInt *xs, PetscInt *ys, PetscInt *zs, PetscInt *xm, PetscInt *ym, PetscInt *zm)
386 {
387   DM_DA          *dd = (DM_DA*)da->data;
388 
389   PetscFunctionBegin;
390   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
391   if (xs) *xs = dd->nonxs;
392   if (ys) *ys = dd->nonys;
393   if (zs) *zs = dd->nonzs;
394   if (xm) *xm = dd->nonxm;
395   if (ym) *ym = dd->nonym;
396   if (zm) *zm = dd->nonzm;
397   PetscFunctionReturn(0);
398 }
399 
400 
401 /*@
402   DMDASetNonOverlappingRegion - Sets the indices of the nonoverlapping region of a subdomain DM.
403 
404   Collective on DA
405 
406   Input Parameter:
407 + da  - The DMDA
408 . xs  - The start of the region in x
409 . ys  - The start of the region in y
410 . zs  - The start of the region in z
411 . xs  - The size of the region in x
412 . ys  - The size of the region in y
413 . zs  - The size of the region in z
414 
415   Level: intermediate
416 
417 .keywords:  distributed array, degrees of freedom
418 .seealso: DMDAGetOffset(), DMDAVecGetArray()
419 @*/
420 PetscErrorCode  DMDASetNonOverlappingRegion(DM da, PetscInt xs, PetscInt ys, PetscInt zs, PetscInt xm, PetscInt ym, PetscInt zm)
421 {
422   DM_DA          *dd = (DM_DA*)da->data;
423 
424   PetscFunctionBegin;
425   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
426   PetscValidLogicalCollectiveInt(da,xs,2);
427   PetscValidLogicalCollectiveInt(da,ys,3);
428   PetscValidLogicalCollectiveInt(da,zs,4);
429   PetscValidLogicalCollectiveInt(da,xm,5);
430   PetscValidLogicalCollectiveInt(da,ym,6);
431   PetscValidLogicalCollectiveInt(da,zm,7);
432   dd->nonxs = xs;
433   dd->nonys = ys;
434   dd->nonzs = zs;
435   dd->nonxm = xm;
436   dd->nonym = ym;
437   dd->nonzm = zm;
438 
439   PetscFunctionReturn(0);
440 }
441 
442 /*@
443   DMDASetStencilType - Sets the type of the communication stencil
444 
445   Logically Collective on DMDA
446 
447   Input Parameter:
448 + da    - The DMDA
449 - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
450 
451   Level: intermediate
452 
453 .keywords:  distributed array, stencil
454 .seealso: DMDACreate(), DMDestroy(), DMDA
455 @*/
456 PetscErrorCode  DMDASetStencilType(DM da, DMDAStencilType stype)
457 {
458   DM_DA *dd = (DM_DA*)da->data;
459 
460   PetscFunctionBegin;
461   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
462   PetscValidLogicalCollectiveEnum(da,stype,2);
463   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
464   dd->stencil_type = stype;
465   PetscFunctionReturn(0);
466 }
467 
468 /*@
469   DMDAGetStencilType - Gets the type of the communication stencil
470 
471   Not collective
472 
473   Input Parameter:
474 . da    - The DMDA
475 
476   Output Parameter:
477 . stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
478 
479   Level: intermediate
480 
481 .keywords:  distributed array, stencil
482 .seealso: DMDACreate(), DMDestroy(), DMDA
483 @*/
484 PetscErrorCode DMDAGetStencilType(DM da, DMDAStencilType *stype)
485 {
486   DM_DA *dd = (DM_DA*)da->data;
487 
488   PetscFunctionBegin;
489   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
490   PetscValidPointer(stype,2);
491   *stype = dd->stencil_type;
492   PetscFunctionReturn(0);
493 }
494 
495 /*@
496   DMDASetStencilWidth - Sets the width of the communication stencil
497 
498   Logically Collective on DMDA
499 
500   Input Parameter:
501 + da    - The DMDA
502 - width - The stencil width
503 
504   Level: intermediate
505 
506 .keywords:  distributed array, stencil
507 .seealso: DMDACreate(), DMDestroy(), DMDA
508 @*/
509 PetscErrorCode  DMDASetStencilWidth(DM da, PetscInt width)
510 {
511   DM_DA *dd = (DM_DA*)da->data;
512 
513   PetscFunctionBegin;
514   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
515   PetscValidLogicalCollectiveInt(da,width,2);
516   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
517   dd->s = width;
518   PetscFunctionReturn(0);
519 }
520 
521 /*@
522   DMDAGetStencilWidth - Gets the width of the communication stencil
523 
524   Not collective
525 
526   Input Parameter:
527 . da    - The DMDA
528 
529   Output Parameter:
530 . width - The stencil width
531 
532   Level: intermediate
533 
534 .keywords:  distributed array, stencil
535 .seealso: DMDACreate(), DMDestroy(), DMDA
536 @*/
537 PetscErrorCode DMDAGetStencilWidth(DM da, PetscInt *width)
538 {
539   DM_DA *dd = (DM_DA *) da->data;
540 
541   PetscFunctionBegin;
542   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
543   PetscValidPointer(width,2);
544   *width = dd->s;
545   PetscFunctionReturn(0);
546 }
547 
548 static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
549 {
550   PetscInt i,sum;
551 
552   PetscFunctionBegin;
553   if (M < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
554   for (i=sum=0; i<m; i++) sum += lx[i];
555   if (sum != M) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M);
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560   DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process
561 
562   Logically Collective on DMDA
563 
564   Input Parameter:
565 + da - The DMDA
566 . lx - array containing number of nodes in the X direction on each process, or NULL. If non-null, must be of length da->m
567 . ly - array containing number of nodes in the Y direction on each process, or NULL. If non-null, must be of length da->n
568 - lz - array containing number of nodes in the Z direction on each process, or NULL. If non-null, must be of length da->p.
569 
570   Level: intermediate
571 
572   Note: these numbers are NOT multiplied by the number of dof per node.
573 
574 .keywords:  distributed array
575 .seealso: DMDACreate(), DMDestroy(), DMDA
576 @*/
577 PetscErrorCode  DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
578 {
579   PetscErrorCode ierr;
580   DM_DA          *dd = (DM_DA*)da->data;
581 
582   PetscFunctionBegin;
583   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
584   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
585   if (lx) {
586     if (dd->m < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
587     ierr = DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);CHKERRQ(ierr);
588     if (!dd->lx) {
589       ierr = PetscMalloc1(dd->m, &dd->lx);CHKERRQ(ierr);
590     }
591     ierr = PetscMemcpy(dd->lx, lx, dd->m*sizeof(PetscInt));CHKERRQ(ierr);
592   }
593   if (ly) {
594     if (dd->n < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
595     ierr = DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);CHKERRQ(ierr);
596     if (!dd->ly) {
597       ierr = PetscMalloc1(dd->n, &dd->ly);CHKERRQ(ierr);
598     }
599     ierr = PetscMemcpy(dd->ly, ly, dd->n*sizeof(PetscInt));CHKERRQ(ierr);
600   }
601   if (lz) {
602     if (dd->p < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
603     ierr = DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);CHKERRQ(ierr);
604     if (!dd->lz) {
605       ierr = PetscMalloc1(dd->p, &dd->lz);CHKERRQ(ierr);
606     }
607     ierr = PetscMemcpy(dd->lz, lz, dd->p*sizeof(PetscInt));CHKERRQ(ierr);
608   }
609   PetscFunctionReturn(0);
610 }
611 
612 /*@
613        DMDASetInterpolationType - Sets the type of interpolation that will be
614           returned by DMCreateInterpolation()
615 
616    Logically Collective on DMDA
617 
618    Input Parameter:
619 +  da - initial distributed array
620 .  ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms
621 
622    Level: intermediate
623 
624    Notes:
625     you should call this on the coarser of the two DMDAs you pass to DMCreateInterpolation()
626 
627 .keywords:  distributed array, interpolation
628 
629 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType
630 @*/
631 PetscErrorCode  DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
632 {
633   DM_DA *dd = (DM_DA*)da->data;
634 
635   PetscFunctionBegin;
636   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
637   PetscValidLogicalCollectiveEnum(da,ctype,2);
638   dd->interptype = ctype;
639   PetscFunctionReturn(0);
640 }
641 
642 /*@
643        DMDAGetInterpolationType - Gets the type of interpolation that will be
644           used by DMCreateInterpolation()
645 
646    Not Collective
647 
648    Input Parameter:
649 .  da - distributed array
650 
651    Output Parameter:
652 .  ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms)
653 
654    Level: intermediate
655 
656 .keywords:  distributed array, interpolation
657 
658 .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMCreateInterpolation()
659 @*/
660 PetscErrorCode  DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
661 {
662   DM_DA *dd = (DM_DA*)da->data;
663 
664   PetscFunctionBegin;
665   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
666   PetscValidPointer(ctype,2);
667   *ctype = dd->interptype;
668   PetscFunctionReturn(0);
669 }
670 
671 /*@C
672       DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
673         processes neighbors.
674 
675     Not Collective
676 
677    Input Parameter:
678 .     da - the DMDA object
679 
680    Output Parameters:
681 .     ranks - the neighbors ranks, stored with the x index increasing most rapidly.
682               this process itself is in the list
683 
684    Notes:
685     In 2d the array is of length 9, in 3d of length 27
686           Not supported in 1d
687           Do not free the array, it is freed when the DMDA is destroyed.
688 
689    Fortran Notes:
690     In fortran you must pass in an array of the appropriate length.
691 
692    Level: intermediate
693 
694 @*/
695 PetscErrorCode  DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
696 {
697   DM_DA *dd = (DM_DA*)da->data;
698 
699   PetscFunctionBegin;
700   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
701   *ranks = dd->neighbors;
702   PetscFunctionReturn(0);
703 }
704 
705 /*@C
706       DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process
707 
708     Not Collective
709 
710    Input Parameter:
711 .     da - the DMDA object
712 
713    Output Parameter:
714 +     lx - ownership along x direction (optional)
715 .     ly - ownership along y direction (optional)
716 -     lz - ownership along z direction (optional)
717 
718    Level: intermediate
719 
720     Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d()
721 
722     In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and
723     eighth arguments from DMDAGetInfo()
724 
725      In C you should not free these arrays, nor change the values in them. They will only have valid values while the
726     DMDA they came from still exists (has not been destroyed).
727 
728     These numbers are NOT multiplied by the number of dof per node.
729 
730 .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges()
731 @*/
732 PetscErrorCode  DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
733 {
734   DM_DA *dd = (DM_DA*)da->data;
735 
736   PetscFunctionBegin;
737   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
738   if (lx) *lx = dd->lx;
739   if (ly) *ly = dd->ly;
740   if (lz) *lz = dd->lz;
741   PetscFunctionReturn(0);
742 }
743 
744 /*@
745      DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined
746 
747     Logically Collective on DMDA
748 
749   Input Parameters:
750 +    da - the DMDA object
751 .    refine_x - ratio of fine grid to coarse in x direction (2 by default)
752 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
753 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
754 
755   Options Database:
756 +  -da_refine_x - refinement ratio in x direction
757 .  -da_refine_y - refinement ratio in y direction
758 -  -da_refine_z - refinement ratio in z direction
759 
760   Level: intermediate
761 
762     Notes:
763     Pass PETSC_IGNORE to leave a value unchanged
764 
765 .seealso: DMRefine(), DMDAGetRefinementFactor()
766 @*/
767 PetscErrorCode  DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
768 {
769   DM_DA *dd = (DM_DA*)da->data;
770 
771   PetscFunctionBegin;
772   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
773   PetscValidLogicalCollectiveInt(da,refine_x,2);
774   PetscValidLogicalCollectiveInt(da,refine_y,3);
775   PetscValidLogicalCollectiveInt(da,refine_z,4);
776 
777   if (refine_x > 0) dd->refine_x = refine_x;
778   if (refine_y > 0) dd->refine_y = refine_y;
779   if (refine_z > 0) dd->refine_z = refine_z;
780   PetscFunctionReturn(0);
781 }
782 
783 /*@C
784      DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined
785 
786     Not Collective
787 
788   Input Parameter:
789 .    da - the DMDA object
790 
791   Output Parameters:
792 +    refine_x - ratio of fine grid to coarse in x direction (2 by default)
793 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
794 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
795 
796   Level: intermediate
797 
798     Notes:
799     Pass NULL for values you do not need
800 
801 .seealso: DMRefine(), DMDASetRefinementFactor()
802 @*/
803 PetscErrorCode  DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
804 {
805   DM_DA *dd = (DM_DA*)da->data;
806 
807   PetscFunctionBegin;
808   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
809   if (refine_x) *refine_x = dd->refine_x;
810   if (refine_y) *refine_y = dd->refine_y;
811   if (refine_z) *refine_z = dd->refine_z;
812   PetscFunctionReturn(0);
813 }
814 
815 /*@C
816      DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix.
817 
818     Logically Collective on DMDA
819 
820   Input Parameters:
821 +    da - the DMDA object
822 -    f - the function that allocates the matrix for that specific DMDA
823 
824   Level: developer
825 
826    Notes:
827     See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for
828        the diagonal and off-diagonal blocks of the matrix
829 
830    Not supported from Fortran
831 
832 .seealso: DMCreateMatrix(), DMDASetBlockFills()
833 @*/
834 PetscErrorCode  DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, Mat*))
835 {
836   PetscFunctionBegin;
837   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
838   da->ops->creatematrix = f;
839   PetscFunctionReturn(0);
840 }
841 
842 /*
843   Creates "balanced" ownership ranges after refinement, constrained by the need for the
844   fine grid boundaries to fall within one stencil width of the coarse partition.
845 
846   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
847 */
848 static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[])
849 {
850   PetscInt       i,totalc = 0,remaining,startc = 0,startf = 0;
851   PetscErrorCode ierr;
852 
853   PetscFunctionBegin;
854   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
855   if (ratio == 1) {
856     ierr = PetscMemcpy(lf,lc,m*sizeof(lc[0]));CHKERRQ(ierr);
857     PetscFunctionReturn(0);
858   }
859   for (i=0; i<m; i++) totalc += lc[i];
860   remaining = (!periodic) + ratio * (totalc - (!periodic));
861   for (i=0; i<m; i++) {
862     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
863     if (i == m-1) lf[i] = want;
864     else {
865       const PetscInt nextc = startc + lc[i];
866       /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
867        * coarse stencil width of the first coarse node in the next subdomain. */
868       while ((startf+want)/ratio < nextc - stencil_width) want++;
869       /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
870        * coarse stencil width of the last coarse node in the current subdomain. */
871       while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
872       /* Make sure all constraints are satisfied */
873       if (want < 0 || want > remaining || ((startf+want)/ratio < nextc - stencil_width)
874           || ((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");
875     }
876     lf[i]      = want;
877     startc    += lc[i];
878     startf    += lf[i];
879     remaining -= lf[i];
880   }
881   PetscFunctionReturn(0);
882 }
883 
884 /*
885   Creates "balanced" ownership ranges after coarsening, constrained by the need for the
886   fine grid boundaries to fall within one stencil width of the coarse partition.
887 
888   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
889 */
890 static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[])
891 {
892   PetscInt       i,totalf,remaining,startc,startf;
893   PetscErrorCode ierr;
894 
895   PetscFunctionBegin;
896   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
897   if (ratio == 1) {
898     ierr = PetscMemcpy(lc,lf,m*sizeof(lf[0]));CHKERRQ(ierr);
899     PetscFunctionReturn(0);
900   }
901   for (i=0,totalf=0; i<m; i++) totalf += lf[i];
902   remaining = (!periodic) + (totalf - (!periodic)) / ratio;
903   for (i=0,startc=0,startf=0; i<m; i++) {
904     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
905     if (i == m-1) lc[i] = want;
906     else {
907       const PetscInt nextf = startf+lf[i];
908       /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
909        * node is within one stencil width. */
910       while (nextf/ratio < startc+want-stencil_width) want--;
911       /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
912        * fine node is within one stencil width. */
913       while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
914       if (want < 0 || want > remaining
915           || (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");
916     }
917     lc[i]      = want;
918     startc    += lc[i];
919     startf    += lf[i];
920     remaining -= lc[i];
921   }
922   PetscFunctionReturn(0);
923 }
924 
925 PetscErrorCode  DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
926 {
927   PetscErrorCode ierr;
928   PetscInt       M,N,P,i,dim;
929   DM             da2;
930   DM_DA          *dd = (DM_DA*)da->data,*dd2;
931 
932   PetscFunctionBegin;
933   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
934   PetscValidPointer(daref,3);
935 
936   ierr = DMGetDimension(da, &dim);CHKERRQ(ierr);
937   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
938     M = dd->refine_x*dd->M;
939   } else {
940     M = 1 + dd->refine_x*(dd->M - 1);
941   }
942   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
943     if (dim > 1) {
944       N = dd->refine_y*dd->N;
945     } else {
946       N = 1;
947     }
948   } else {
949     N = 1 + dd->refine_y*(dd->N - 1);
950   }
951   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
952     if (dim > 2) {
953       P = dd->refine_z*dd->P;
954     } else {
955       P = 1;
956     }
957   } else {
958     P = 1 + dd->refine_z*(dd->P - 1);
959   }
960   ierr = DMDACreate(PetscObjectComm((PetscObject)da),&da2);CHKERRQ(ierr);
961   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
962   ierr = DMSetDimension(da2,dim);CHKERRQ(ierr);
963   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
964   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
965   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
966   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
967   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
968   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
969   if (dim == 3) {
970     PetscInt *lx,*ly,*lz;
971     ierr = PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);CHKERRQ(ierr);
972     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
973     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
974     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
975     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
976     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
977   } else if (dim == 2) {
978     PetscInt *lx,*ly;
979     ierr = PetscMalloc2(dd->m,&lx,dd->n,&ly);CHKERRQ(ierr);
980     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
981     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
982     ierr = DMDASetOwnershipRanges(da2,lx,ly,NULL);CHKERRQ(ierr);
983     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
984   } else if (dim == 1) {
985     PetscInt *lx;
986     ierr = PetscMalloc1(dd->m,&lx);CHKERRQ(ierr);
987     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
988     ierr = DMDASetOwnershipRanges(da2,lx,NULL,NULL);CHKERRQ(ierr);
989     ierr = PetscFree(lx);CHKERRQ(ierr);
990   }
991   dd2 = (DM_DA*)da2->data;
992 
993   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
994   da2->ops->creatematrix = da->ops->creatematrix;
995   /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */
996   da2->ops->getcoloring = da->ops->getcoloring;
997   dd2->interptype       = dd->interptype;
998 
999   /* copy fill information if given */
1000   if (dd->dfill) {
1001     ierr = PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);CHKERRQ(ierr);
1002     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1003   }
1004   if (dd->ofill) {
1005     ierr = PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);CHKERRQ(ierr);
1006     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1007   }
1008   /* copy the refine information */
1009   dd2->coarsen_x = dd2->refine_x = dd->refine_x;
1010   dd2->coarsen_y = dd2->refine_y = dd->refine_y;
1011   dd2->coarsen_z = dd2->refine_z = dd->refine_z;
1012 
1013   if (dd->refine_z_hier) {
1014     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_z_hier_n) {
1015       dd2->refine_z = dd->refine_z_hier[da->levelup - da->leveldown + 1];
1016     }
1017     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_z_hier_n) {
1018       dd2->coarsen_z = dd->refine_z_hier[da->levelup - da->leveldown];
1019     }
1020     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1021     ierr = PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier);CHKERRQ(ierr);
1022     ierr = PetscMemcpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1023   }
1024   if (dd->refine_y_hier) {
1025     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_y_hier_n) {
1026       dd2->refine_y = dd->refine_y_hier[da->levelup - da->leveldown + 1];
1027     }
1028     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_y_hier_n) {
1029       dd2->coarsen_y = dd->refine_y_hier[da->levelup - da->leveldown];
1030     }
1031     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1032     ierr = PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier);CHKERRQ(ierr);
1033     ierr = PetscMemcpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1034   }
1035   if (dd->refine_x_hier) {
1036     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_x_hier_n) {
1037       dd2->refine_x = dd->refine_x_hier[da->levelup - da->leveldown + 1];
1038     }
1039     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_x_hier_n) {
1040       dd2->coarsen_x = dd->refine_x_hier[da->levelup - da->leveldown];
1041     }
1042     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1043     ierr = PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier);CHKERRQ(ierr);
1044     ierr = PetscMemcpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1045   }
1046 
1047 
1048   /* copy vector type information */
1049   ierr = DMSetVecType(da2,da->vectype);CHKERRQ(ierr);
1050 
1051   dd2->lf = dd->lf;
1052   dd2->lj = dd->lj;
1053 
1054   da2->leveldown = da->leveldown;
1055   da2->levelup   = da->levelup + 1;
1056 
1057   ierr = DMSetUp(da2);CHKERRQ(ierr);
1058 
1059   /* interpolate coordinates if they are set on the coarse grid */
1060   if (da->coordinates) {
1061     DM  cdaf,cdac;
1062     Vec coordsc,coordsf;
1063     Mat II;
1064 
1065     ierr = DMGetCoordinateDM(da,&cdac);CHKERRQ(ierr);
1066     ierr = DMGetCoordinates(da,&coordsc);CHKERRQ(ierr);
1067     ierr = DMGetCoordinateDM(da2,&cdaf);CHKERRQ(ierr);
1068     /* force creation of the coordinate vector */
1069     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
1070     ierr = DMGetCoordinates(da2,&coordsf);CHKERRQ(ierr);
1071     ierr = DMCreateInterpolation(cdac,cdaf,&II,NULL);CHKERRQ(ierr);
1072     ierr = MatInterpolate(II,coordsc,coordsf);CHKERRQ(ierr);
1073     ierr = MatDestroy(&II);CHKERRQ(ierr);
1074   }
1075 
1076   for (i=0; i<da->bs; i++) {
1077     const char *fieldname;
1078     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
1079     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
1080   }
1081 
1082   *daref = da2;
1083   PetscFunctionReturn(0);
1084 }
1085 
1086 
1087 PetscErrorCode  DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref)
1088 {
1089   PetscErrorCode ierr;
1090   PetscInt       M,N,P,i,dim;
1091   DM             da2;
1092   DM_DA          *dd = (DM_DA*)da->data,*dd2;
1093 
1094   PetscFunctionBegin;
1095   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
1096   PetscValidPointer(daref,3);
1097 
1098   ierr = DMGetDimension(da, &dim);CHKERRQ(ierr);
1099   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1100     M = dd->M / dd->coarsen_x;
1101   } else {
1102     M = 1 + (dd->M - 1) / dd->coarsen_x;
1103   }
1104   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1105     if (dim > 1) {
1106       N = dd->N / dd->coarsen_y;
1107     } else {
1108       N = 1;
1109     }
1110   } else {
1111     N = 1 + (dd->N - 1) / dd->coarsen_y;
1112   }
1113   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1114     if (dim > 2) {
1115       P = dd->P / dd->coarsen_z;
1116     } else {
1117       P = 1;
1118     }
1119   } else {
1120     P = 1 + (dd->P - 1) / dd->coarsen_z;
1121   }
1122   ierr = DMDACreate(PetscObjectComm((PetscObject)da),&da2);CHKERRQ(ierr);
1123   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
1124   ierr = DMSetDimension(da2,dim);CHKERRQ(ierr);
1125   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
1126   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
1127   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
1128   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
1129   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
1130   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
1131   if (dim == 3) {
1132     PetscInt *lx,*ly,*lz;
1133     ierr = PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);CHKERRQ(ierr);
1134     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1135     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1136     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
1137     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
1138     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
1139   } else if (dim == 2) {
1140     PetscInt *lx,*ly;
1141     ierr = PetscMalloc2(dd->m,&lx,dd->n,&ly);CHKERRQ(ierr);
1142     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1143     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1144     ierr = DMDASetOwnershipRanges(da2,lx,ly,NULL);CHKERRQ(ierr);
1145     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
1146   } else if (dim == 1) {
1147     PetscInt *lx;
1148     ierr = PetscMalloc1(dd->m,&lx);CHKERRQ(ierr);
1149     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1150     ierr = DMDASetOwnershipRanges(da2,lx,NULL,NULL);CHKERRQ(ierr);
1151     ierr = PetscFree(lx);CHKERRQ(ierr);
1152   }
1153   dd2 = (DM_DA*)da2->data;
1154 
1155   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
1156   /* da2->ops->createinterpolation = da->ops->createinterpolation; copying this one causes trouble for DMSetVI */
1157   da2->ops->creatematrix = da->ops->creatematrix;
1158   da2->ops->getcoloring  = da->ops->getcoloring;
1159   dd2->interptype        = dd->interptype;
1160 
1161   /* copy fill information if given */
1162   if (dd->dfill) {
1163     ierr = PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);CHKERRQ(ierr);
1164     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1165   }
1166   if (dd->ofill) {
1167     ierr = PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);CHKERRQ(ierr);
1168     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1169   }
1170   /* copy the refine information */
1171   dd2->coarsen_x = dd2->refine_x = dd->coarsen_x;
1172   dd2->coarsen_y = dd2->refine_y = dd->coarsen_y;
1173   dd2->coarsen_z = dd2->refine_z = dd->coarsen_z;
1174 
1175   if (dd->refine_z_hier) {
1176     if (da->levelup - da->leveldown -1 > -1 && da->levelup - da->leveldown - 1< dd->refine_z_hier_n) {
1177       dd2->refine_z = dd->refine_z_hier[da->levelup - da->leveldown - 1];
1178     }
1179     if (da->levelup - da->leveldown - 2 > -1 && da->levelup - da->leveldown - 2 < dd->refine_z_hier_n) {
1180       dd2->coarsen_z = dd->refine_z_hier[da->levelup - da->leveldown - 2];
1181     }
1182     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1183     ierr = PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier);CHKERRQ(ierr);
1184     ierr = PetscMemcpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1185   }
1186   if (dd->refine_y_hier) {
1187     if (da->levelup - da->leveldown - 1 > -1 && da->levelup - da->leveldown - 1< dd->refine_y_hier_n) {
1188       dd2->refine_y = dd->refine_y_hier[da->levelup - da->leveldown - 1];
1189     }
1190     if (da->levelup - da->leveldown - 2 > -1 && da->levelup - da->leveldown - 2 < dd->refine_y_hier_n) {
1191       dd2->coarsen_y = dd->refine_y_hier[da->levelup - da->leveldown - 2];
1192     }
1193     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1194     ierr = PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier);CHKERRQ(ierr);
1195     ierr = PetscMemcpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1196   }
1197   if (dd->refine_x_hier) {
1198     if (da->levelup - da->leveldown - 1 > -1 && da->levelup - da->leveldown - 1 < dd->refine_x_hier_n) {
1199       dd2->refine_x = dd->refine_x_hier[da->levelup - da->leveldown - 1];
1200     }
1201     if (da->levelup - da->leveldown - 2 > -1 && da->levelup - da->leveldown - 2 < dd->refine_x_hier_n) {
1202       dd2->coarsen_x = dd->refine_x_hier[da->levelup - da->leveldown - 2];
1203     }
1204     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1205     ierr = PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier);CHKERRQ(ierr);
1206     ierr = PetscMemcpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n*sizeof(PetscInt));CHKERRQ(ierr);
1207   }
1208 
1209   /* copy vector type information */
1210   ierr = DMSetVecType(da2,da->vectype);CHKERRQ(ierr);
1211 
1212   dd2->lf = dd->lf;
1213   dd2->lj = dd->lj;
1214 
1215   da2->leveldown = da->leveldown + 1;
1216   da2->levelup   = da->levelup;
1217 
1218   ierr = DMSetUp(da2);CHKERRQ(ierr);
1219 
1220   /* inject coordinates if they are set on the fine grid */
1221   if (da->coordinates) {
1222     DM         cdaf,cdac;
1223     Vec        coordsc,coordsf;
1224     Mat        inject;
1225     VecScatter vscat;
1226 
1227     ierr = DMGetCoordinateDM(da,&cdaf);CHKERRQ(ierr);
1228     ierr = DMGetCoordinates(da,&coordsf);CHKERRQ(ierr);
1229     ierr = DMGetCoordinateDM(da2,&cdac);CHKERRQ(ierr);
1230     /* force creation of the coordinate vector */
1231     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
1232     ierr = DMGetCoordinates(da2,&coordsc);CHKERRQ(ierr);
1233 
1234     ierr = DMCreateInjection(cdac,cdaf,&inject);CHKERRQ(ierr);
1235     ierr = MatScatterGetVecScatter(inject,&vscat);CHKERRQ(ierr);
1236     ierr = VecScatterBegin(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1237     ierr = VecScatterEnd(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1238     ierr = MatDestroy(&inject);CHKERRQ(ierr);
1239   }
1240 
1241   for (i=0; i<da->bs; i++) {
1242     const char *fieldname;
1243     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
1244     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
1245   }
1246 
1247   *daref = da2;
1248   PetscFunctionReturn(0);
1249 }
1250 
1251 PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
1252 {
1253   PetscErrorCode ierr;
1254   PetscInt       i,n,*refx,*refy,*refz;
1255 
1256   PetscFunctionBegin;
1257   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1258   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1259   if (nlevels == 0) PetscFunctionReturn(0);
1260   PetscValidPointer(daf,3);
1261 
1262   /* Get refinement factors, defaults taken from the coarse DMDA */
1263   ierr = PetscMalloc3(nlevels,&refx,nlevels,&refy,nlevels,&refz);CHKERRQ(ierr);
1264   for (i=0; i<nlevels; i++) {
1265     ierr = DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr);
1266   }
1267   n    = nlevels;
1268   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,NULL);CHKERRQ(ierr);
1269   n    = nlevels;
1270   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,NULL);CHKERRQ(ierr);
1271   n    = nlevels;
1272   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,NULL);CHKERRQ(ierr);
1273 
1274   ierr = DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr);
1275   ierr = DMRefine(da,PetscObjectComm((PetscObject)da),&daf[0]);CHKERRQ(ierr);
1276   for (i=1; i<nlevels; i++) {
1277     ierr = DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr);
1278     ierr = DMRefine(daf[i-1],PetscObjectComm((PetscObject)da),&daf[i]);CHKERRQ(ierr);
1279   }
1280   ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr);
1281   PetscFunctionReturn(0);
1282 }
1283 
1284 PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
1285 {
1286   PetscErrorCode ierr;
1287   PetscInt       i;
1288 
1289   PetscFunctionBegin;
1290   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1291   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1292   if (nlevels == 0) PetscFunctionReturn(0);
1293   PetscValidPointer(dac,3);
1294   ierr = DMCoarsen(da,PetscObjectComm((PetscObject)da),&dac[0]);CHKERRQ(ierr);
1295   for (i=1; i<nlevels; i++) {
1296     ierr = DMCoarsen(dac[i-1],PetscObjectComm((PetscObject)da),&dac[i]);CHKERRQ(ierr);
1297   }
1298   PetscFunctionReturn(0);
1299 }
1300 
1301 PetscErrorCode DMDASetGLLCoordinates_1d(DM dm,PetscInt n,PetscReal *nodes)
1302 {
1303   PetscErrorCode ierr;
1304   PetscInt       i,j,xs,xn,q;
1305   PetscScalar    *xx;
1306   PetscReal      h;
1307   Vec            x;
1308   DM_DA          *da = (DM_DA*)dm->data;
1309 
1310   PetscFunctionBegin;
1311   if (da->bx != DM_BOUNDARY_PERIODIC) {
1312     ierr = DMDAGetInfo(dm,NULL,&q,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);CHKERRQ(ierr);
1313     q    = (q-1)/(n-1);  /* number of spectral elements */
1314     h    = 2.0/q;
1315     ierr = DMDAGetCorners(dm,&xs,NULL,NULL,&xn,NULL,NULL);CHKERRQ(ierr);
1316     xs   = xs/(n-1);
1317     xn   = xn/(n-1);
1318     ierr = DMDASetUniformCoordinates(dm,-1.,1.,0.,0.,0.,0.);CHKERRQ(ierr);
1319     ierr = DMGetCoordinates(dm,&x);CHKERRQ(ierr);
1320     ierr = DMDAVecGetArray(dm,x,&xx);CHKERRQ(ierr);
1321 
1322     /* loop over local spectral elements */
1323     for (j=xs; j<xs+xn; j++) {
1324       /*
1325        Except for the first process, each process starts on the second GLL point of the first element on that process
1326        */
1327       for (i= (j == xs && xs > 0)? 1 : 0; i<n; i++) {
1328         xx[j*(n-1) + i] = -1.0 + h*j + h*(nodes[i]+1.0)/2.;
1329       }
1330     }
1331     ierr = DMDAVecRestoreArray(dm,x,&xx);CHKERRQ(ierr);
1332   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for periodic");
1333   PetscFunctionReturn(0);
1334 }
1335 
1336 /*@
1337 
1338      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
1339 
1340    Collective on DM
1341 
1342    Input Parameters:
1343 +   da - the DMDA object
1344 -   n - the number of GLL nodes
1345 -   nodes - the GLL nodes
1346 
1347    Notes:
1348     the parallel decomposition of grid points must correspond to the degree of the GLL. That is, the number of grid points
1349           on each process much be divisible by the number of GLL elements needed per process. This depends on whether the DM is
1350           periodic or not.
1351 
1352    Level: advanced
1353 
1354 .seealso:   DMDACreate(), PetscDTGaussLobattoLegendreQuadrature(), DMGetCoordinates()
1355 @*/
1356 PetscErrorCode DMDASetGLLCoordinates(DM da,PetscInt n,PetscReal *nodes)
1357 {
1358   PetscErrorCode ierr;
1359 
1360   PetscFunctionBegin;
1361   if (da->dim == 1) {
1362     ierr = DMDASetGLLCoordinates_1d(da,n,nodes);CHKERRQ(ierr);
1363   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for 2 or 3d");
1364   PetscFunctionReturn(0);
1365 }
1366 
1367 PETSC_INTERN PetscErrorCode DMGetCompatibility_DA(DM da1,DM dm2,PetscBool *compatible,PetscBool *set)
1368 {
1369   PetscErrorCode ierr;
1370   DM_DA          *dd1 = (DM_DA*)da1->data,*dd2;
1371   DM             da2;
1372   DMType         dmtype2;
1373   PetscBool      isda,compatibleLocal;
1374   PetscInt       i;
1375 
1376   PetscFunctionBegin;
1377   if (!da1->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da1),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on first DM before DMGetCompatibility()");
1378   ierr = DMGetType(dm2,&dmtype2);CHKERRQ(ierr);
1379   ierr = PetscStrcmp(dmtype2,DMDA,&isda);CHKERRQ(ierr);
1380   if (isda) {
1381     da2 = dm2;
1382     dd2 = (DM_DA*)da2->data;
1383     if (!da2->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da2),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on second DM before DMGetCompatibility()");
1384     compatibleLocal = (PetscBool)(da1->dim == da2->dim);
1385     if (compatibleLocal) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->s == dd2->s)); /* Stencil width */
1386     /*                                                                           Global size              ranks               Boundary type */
1387     if (compatibleLocal)                 compatibleLocal = (PetscBool)(compatibleLocal && (dd1->M == dd2->M) && (dd1->m == dd2->m) && (dd1->bx == dd2->bx));
1388     if (compatibleLocal && da1->dim > 1) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->N == dd2->N) && (dd1->n == dd2->n) && (dd1->by == dd2->by));
1389     if (compatibleLocal && da1->dim > 2) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->P == dd2->P) && (dd1->p == dd2->p) && (dd1->bz == dd2->bz));
1390     if (compatibleLocal) {
1391       for (i=0; i<dd1->m; ++i) {
1392         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lx[i] == dd2->lx[i]));           /* Local size     */
1393       }
1394     }
1395     if (compatibleLocal && da1->dim > 1) {
1396       for (i=0; i<dd1->n; ++i) {
1397         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->ly[i] == dd2->ly[i]));
1398       }
1399     }
1400     if (compatibleLocal && da1->dim > 2) {
1401       for (i=0; i<dd1->p; ++i) {
1402         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lz[i] == dd2->lz[i]));
1403       }
1404     }
1405     *compatible = compatibleLocal;
1406     *set = PETSC_TRUE;
1407   } else {
1408     /* Decline to determine compatibility with other DM types */
1409     *set = PETSC_FALSE;
1410   }
1411   PetscFunctionReturn(0);
1412 }
1413