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