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