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