xref: /petsc/src/dm/impls/da/da.c (revision 0f55b88d1ac75fa99e70a53aff055236a607e7f1)
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     if (dd->dim > 1) {
620       N = dd->refine_y*dd->N;
621     } else {
622       N = 1;
623     }
624   } else {
625     N = 1 + dd->refine_y*(dd->N - 1);
626   }
627   if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
628     if (dd->dim > 2) {
629       P = dd->refine_z*dd->P;
630     } else {
631       P = 1;
632     }
633   } else {
634     P = 1 + dd->refine_z*(dd->P - 1);
635   }
636   ierr = DMDACreate(((PetscObject)da)->comm,&da2);CHKERRQ(ierr);
637   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
638   ierr = DMDASetDim(da2,dd->dim);CHKERRQ(ierr);
639   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
640   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
641   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
642   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
643   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
644   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
645   if (dd->dim == 3) {
646     PetscInt *lx,*ly,*lz;
647     ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);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 = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
651     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
652     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
653   } else if (dd->dim == 2) {
654     PetscInt *lx,*ly;
655     ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr);
656     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);
657     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);
658     ierr = DMDASetOwnershipRanges(da2,lx,ly,PETSC_NULL);CHKERRQ(ierr);
659     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
660   } else if (dd->dim == 1) {
661     PetscInt *lx;
662     ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr);
663     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);
664     ierr = DMDASetOwnershipRanges(da2,lx,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
665     ierr = PetscFree(lx);CHKERRQ(ierr);
666   }
667   dd2 = (DM_DA*)da2->data;
668 
669   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
670   da2->ops->creatematrix        = da->ops->creatematrix;
671   /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */
672   da2->ops->getcoloring      = da->ops->getcoloring;
673   dd2->interptype            = dd->interptype;
674 
675   /* copy fill information if given */
676   if (dd->dfill) {
677     ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr);
678     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
679   }
680   if (dd->ofill) {
681     ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr);
682     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
683   }
684   /* copy the refine information */
685   dd2->coarsen_x = dd2->refine_x = dd->refine_x;
686   dd2->coarsen_y = dd2->refine_y = dd->refine_y;
687   dd2->coarsen_z = dd2->refine_z = dd->refine_z;
688 
689   /* copy vector type information */
690   ierr = PetscFree(da2->vectype);CHKERRQ(ierr);
691   ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr);
692 
693   dd2->lf = dd->lf;
694   dd2->lj = dd->lj;
695 
696   da2->leveldown = da->leveldown;
697   da2->levelup   = da->levelup + 1;
698   ierr = DMSetFromOptions(da2);CHKERRQ(ierr);
699   ierr = DMSetUp(da2);CHKERRQ(ierr);
700   ierr = DMView_DA_Private(da2);CHKERRQ(ierr);
701 
702   /* interpolate coordinates if they are set on the coarse grid */
703   if (dd->coordinates) {
704     DM  cdaf,cdac;
705     Vec coordsc,coordsf;
706     Mat II;
707 
708     ierr = DMDAGetCoordinateDA(da,&cdac);CHKERRQ(ierr);
709     ierr = DMDAGetCoordinates(da,&coordsc);CHKERRQ(ierr);
710     ierr = DMDAGetCoordinateDA(da2,&cdaf);CHKERRQ(ierr);
711     /* force creation of the coordinate vector */
712     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
713     ierr = DMDAGetCoordinates(da2,&coordsf);CHKERRQ(ierr);
714     ierr = DMCreateInterpolation(cdac,cdaf,&II,PETSC_NULL);CHKERRQ(ierr);
715     ierr = MatInterpolate(II,coordsc,coordsf);CHKERRQ(ierr);
716     ierr = MatDestroy(&II);CHKERRQ(ierr);
717   }
718 
719   for (i=0; i<da->bs; i++) {
720     const char *fieldname;
721     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
722     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
723   }
724 
725   *daref = da2;
726   PetscFunctionReturn(0);
727 }
728 
729 
730 #undef __FUNCT__
731 #define __FUNCT__ "DMCoarsen_DA"
732 PetscErrorCode  DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref)
733 {
734   PetscErrorCode ierr;
735   PetscInt       M,N,P,i;
736   DM             da2;
737   DM_DA          *dd = (DM_DA*)da->data,*dd2;
738 
739   PetscFunctionBegin;
740   PetscValidHeaderSpecific(da,DM_CLASSID,1);
741   PetscValidPointer(daref,3);
742 
743   if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
744     M = dd->M / dd->coarsen_x;
745   } else {
746     M = 1 + (dd->M - 1) / dd->coarsen_x;
747   }
748   if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
749     if (dd->dim > 1) {
750       N = dd->N / dd->coarsen_y;
751     } else {
752       N = 1;
753     }
754   } else {
755     N = 1 + (dd->N - 1) / dd->coarsen_y;
756   }
757   if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
758     if (dd->dim > 2) {
759       P = dd->P / dd->coarsen_z;
760     } else {
761       P = 1;
762     }
763   } else {
764     P = 1 + (dd->P - 1) / dd->coarsen_z;
765   }
766   ierr = DMDACreate(((PetscObject)da)->comm,&da2);CHKERRQ(ierr);
767   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
768   ierr = DMDASetDim(da2,dd->dim);CHKERRQ(ierr);
769   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
770   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
771   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
772   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
773   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
774   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
775   if (dd->dim == 3) {
776     PetscInt *lx,*ly,*lz;
777     ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr);
778     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);
779     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);
780     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);
781     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
782     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
783   } else if (dd->dim == 2) {
784     PetscInt *lx,*ly;
785     ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr);
786     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);
787     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);
788     ierr = DMDASetOwnershipRanges(da2,lx,ly,PETSC_NULL);CHKERRQ(ierr);
789     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
790   } else if (dd->dim == 1) {
791     PetscInt *lx;
792     ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr);
793     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);
794     ierr = DMDASetOwnershipRanges(da2,lx,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
795     ierr = PetscFree(lx);CHKERRQ(ierr);
796   }
797   dd2 = (DM_DA*)da2->data;
798 
799   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
800   /* da2->ops->createinterpolation = da->ops->createinterpolation; copying this one causes trouble for DMSetVI */
801   da2->ops->creatematrix        = da->ops->creatematrix;
802   da2->ops->getcoloring      = da->ops->getcoloring;
803   dd2->interptype            = dd->interptype;
804 
805   /* copy fill information if given */
806   if (dd->dfill) {
807     ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr);
808     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
809   }
810   if (dd->ofill) {
811     ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr);
812     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
813   }
814   /* copy the refine information */
815   dd2->coarsen_x = dd2->refine_x = dd->coarsen_x;
816   dd2->coarsen_y = dd2->refine_y = dd->coarsen_y;
817   dd2->coarsen_z = dd2->refine_z = dd->coarsen_z;
818 
819   /* copy vector type information */
820   ierr = PetscFree(da2->vectype);CHKERRQ(ierr);
821   ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr);
822 
823   dd2->lf = dd->lf;
824   dd2->lj = dd->lj;
825 
826   da2->leveldown = da->leveldown + 1;
827   da2->levelup   = da->levelup;
828   ierr = DMSetFromOptions(da2);CHKERRQ(ierr);
829   ierr = DMSetUp(da2);CHKERRQ(ierr);
830   ierr = DMView_DA_Private(da2);CHKERRQ(ierr);
831 
832   /* inject coordinates if they are set on the fine grid */
833   if (dd->coordinates) {
834     DM         cdaf,cdac;
835     Vec        coordsc,coordsf;
836     VecScatter inject;
837 
838     ierr = DMDAGetCoordinateDA(da,&cdaf);CHKERRQ(ierr);
839     ierr = DMDAGetCoordinates(da,&coordsf);CHKERRQ(ierr);
840     ierr = DMDAGetCoordinateDA(da2,&cdac);CHKERRQ(ierr);
841     /* force creation of the coordinate vector */
842     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
843     ierr = DMDAGetCoordinates(da2,&coordsc);CHKERRQ(ierr);
844 
845     ierr = DMCreateInjection(cdac,cdaf,&inject);CHKERRQ(ierr);
846     ierr = VecScatterBegin(inject,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
847     ierr = VecScatterEnd(inject  ,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
848     ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
849   }
850 
851   for (i=0; i<da->bs; i++) {
852     const char *fieldname;
853     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
854     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
855   }
856 
857   *daref = da2;
858   PetscFunctionReturn(0);
859 }
860 
861 #undef __FUNCT__
862 #define __FUNCT__ "DMRefineHierarchy_DA"
863 PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
864 {
865   PetscErrorCode ierr;
866   PetscInt       i,n,*refx,*refy,*refz;
867 
868   PetscFunctionBegin;
869   PetscValidHeaderSpecific(da,DM_CLASSID,1);
870   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
871   if (nlevels == 0) PetscFunctionReturn(0);
872   PetscValidPointer(daf,3);
873 
874   /* Get refinement factors, defaults taken from the coarse DMDA */
875   ierr = PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);CHKERRQ(ierr);
876   for (i=0; i<nlevels; i++) {
877     ierr = DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr);
878   }
879   n = nlevels;
880   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);CHKERRQ(ierr);
881   n = nlevels;
882   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);CHKERRQ(ierr);
883   n = nlevels;
884   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);CHKERRQ(ierr);
885 
886   ierr = DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr);
887   ierr = DMRefine(da,((PetscObject)da)->comm,&daf[0]);CHKERRQ(ierr);
888   for (i=1; i<nlevels; i++) {
889     ierr = DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr);
890     ierr = DMRefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);CHKERRQ(ierr);
891   }
892   ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr);
893   PetscFunctionReturn(0);
894 }
895 
896 #undef __FUNCT__
897 #define __FUNCT__ "DMCoarsenHierarchy_DA"
898 PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
899 {
900   PetscErrorCode ierr;
901   PetscInt       i;
902 
903   PetscFunctionBegin;
904   PetscValidHeaderSpecific(da,DM_CLASSID,1);
905   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
906   if (nlevels == 0) PetscFunctionReturn(0);
907   PetscValidPointer(dac,3);
908   ierr = DMCoarsen(da,((PetscObject)da)->comm,&dac[0]);CHKERRQ(ierr);
909   for (i=1; i<nlevels; i++) {
910     ierr = DMCoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);CHKERRQ(ierr);
911   }
912   PetscFunctionReturn(0);
913 }
914