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