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