xref: /petsc/src/dm/impls/da/da.c (revision dbbe0bcd3f3a8fbab5a45420dc06f8387e5764c6)
1 #include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/
2 
3 /*@
4   DMDASetSizes - Sets the number of grid points in the three dimensional directions
5 
6   Logically Collective on da
7 
8   Input Parameters:
9 + da - the DMDA
10 . M - the global X size
11 . N - the global Y size
12 - P - the global Z size
13 
14   Level: intermediate
15 
16   Developer Notes:
17   Since the dimension may not yet have been set the code cannot error check for non-positive Y and Z number of grid points
18 
19 .seealso: `PetscSplitOwnership()`
20 @*/
21 PetscErrorCode  DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P)
22 {
23   DM_DA *dd = (DM_DA*)da->data;
24 
25   PetscFunctionBegin;
26   PetscValidHeaderSpecificType(da, DM_CLASSID, 1,DMDA);
27   PetscValidLogicalCollectiveInt(da,M,2);
28   PetscValidLogicalCollectiveInt(da,N,3);
29   PetscValidLogicalCollectiveInt(da,P,4);
30   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
31   PetscCheck(M >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in X direction must be positive");
32   PetscCheck(N >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in Y direction must be positive");
33   PetscCheck(P >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Number of grid points in Z direction must be positive");
34 
35   dd->M = M;
36   dd->N = N;
37   dd->P = P;
38   PetscFunctionReturn(0);
39 }
40 
41 /*@
42   DMDASetNumProcs - Sets the number of processes in each dimension
43 
44   Logically Collective on da
45 
46   Input Parameters:
47 + da - the DMDA
48 . m - the number of X procs (or PETSC_DECIDE)
49 . n - the number of Y procs (or PETSC_DECIDE)
50 - p - the number of Z procs (or PETSC_DECIDE)
51 
52   Level: intermediate
53 
54 .seealso: `DMDASetSizes()`, `PetscSplitOwnership()`
55 @*/
56 PetscErrorCode  DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p)
57 {
58   DM_DA          *dd = (DM_DA*)da->data;
59 
60   PetscFunctionBegin;
61   PetscValidHeaderSpecificType(da, DM_CLASSID, 1,DMDA);
62   PetscValidLogicalCollectiveInt(da,m,2);
63   PetscValidLogicalCollectiveInt(da,n,3);
64   PetscValidLogicalCollectiveInt(da,p,4);
65   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
66   dd->m = m;
67   dd->n = n;
68   dd->p = p;
69   if (da->dim == 2) {
70     PetscMPIInt size;
71     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)da),&size));
72     if ((dd->m > 0) && (dd->n < 0)) {
73       dd->n = size/dd->m;
74       PetscCheck(dd->n*dd->m == size,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%" PetscInt_FMT " processes in X direction not divisible into comm size %d",m,size);
75     }
76     if ((dd->n > 0) && (dd->m < 0)) {
77       dd->m = size/dd->n;
78       PetscCheck(dd->n*dd->m == size,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%" PetscInt_FMT " processes in Y direction not divisible into comm size %d",n,size);
79     }
80   }
81   PetscFunctionReturn(0);
82 }
83 
84 /*@
85   DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries.
86 
87   Not collective
88 
89   Input Parameters:
90 + da    - The DMDA
91 - bx,by,bz - One of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC
92 
93   Level: intermediate
94 
95 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`, `DMBoundaryType`
96 @*/
97 PetscErrorCode  DMDASetBoundaryType(DM da,DMBoundaryType bx,DMBoundaryType by,DMBoundaryType bz)
98 {
99   DM_DA *dd = (DM_DA*)da->data;
100 
101   PetscFunctionBegin;
102   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
103   PetscValidLogicalCollectiveEnum(da,bx,2);
104   PetscValidLogicalCollectiveEnum(da,by,3);
105   PetscValidLogicalCollectiveEnum(da,bz,4);
106   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
107   dd->bx = bx;
108   dd->by = by;
109   dd->bz = bz;
110   PetscFunctionReturn(0);
111 }
112 
113 /*@
114   DMDASetDof - Sets the number of degrees of freedom per vertex
115 
116   Not collective
117 
118   Input Parameters:
119 + da  - The DMDA
120 - dof - Number of degrees of freedom
121 
122   Level: intermediate
123 
124 .seealso: `DMDAGetDof()`, `DMDACreate()`, `DMDestroy()`, `DMDA`
125 @*/
126 PetscErrorCode  DMDASetDof(DM da, PetscInt dof)
127 {
128   DM_DA *dd = (DM_DA*)da->data;
129 
130   PetscFunctionBegin;
131   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
132   PetscValidLogicalCollectiveInt(da,dof,2);
133   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
134   dd->w  = dof;
135   da->bs = dof;
136   PetscFunctionReturn(0);
137 }
138 
139 /*@
140   DMDAGetDof - Gets the number of degrees of freedom per vertex
141 
142   Not collective
143 
144   Input Parameter:
145 . da  - The DMDA
146 
147   Output Parameter:
148 . dof - Number of degrees of freedom
149 
150   Level: intermediate
151 
152 .seealso: `DMDASetDof()`, `DMDACreate()`, `DMDestroy()`, `DMDA`
153 @*/
154 PetscErrorCode DMDAGetDof(DM da, PetscInt *dof)
155 {
156   DM_DA *dd = (DM_DA *) da->data;
157 
158   PetscFunctionBegin;
159   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
160   PetscValidIntPointer(dof,2);
161   *dof = dd->w;
162   PetscFunctionReturn(0);
163 }
164 
165 /*@
166   DMDAGetOverlap - Gets the size of the per-processor overlap.
167 
168   Not collective
169 
170   Input Parameter:
171 . da  - The DMDA
172 
173   Output Parameters:
174 + x   - Overlap in the x direction
175 . y   - Overlap in the y direction
176 - z   - Overlap in the z direction
177 
178   Level: intermediate
179 
180 .seealso: `DMCreateDomainDecomposition()`, `DMDASetOverlap()`, `DMDA`
181 @*/
182 PetscErrorCode  DMDAGetOverlap(DM da,PetscInt *x,PetscInt *y,PetscInt *z)
183 {
184   DM_DA *dd = (DM_DA*)da->data;
185 
186   PetscFunctionBegin;
187   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
188   if (x) *x = dd->xol;
189   if (y) *y = dd->yol;
190   if (z) *z = dd->zol;
191   PetscFunctionReturn(0);
192 }
193 
194 /*@
195   DMDASetOverlap - Sets the size of the per-processor overlap.
196 
197   Not collective
198 
199   Input Parameters:
200 + da  - The DMDA
201 . x   - Overlap in the x direction
202 . y   - Overlap in the y direction
203 - z   - Overlap in the z direction
204 
205   Level: intermediate
206 
207 .seealso: `DMCreateDomainDecomposition()`, `DMDAGetOverlap()`, `DMDA`
208 @*/
209 PetscErrorCode  DMDASetOverlap(DM da,PetscInt x,PetscInt y,PetscInt z)
210 {
211   DM_DA *dd = (DM_DA*)da->data;
212 
213   PetscFunctionBegin;
214   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
215   PetscValidLogicalCollectiveInt(da,x,2);
216   PetscValidLogicalCollectiveInt(da,y,3);
217   PetscValidLogicalCollectiveInt(da,z,4);
218   dd->xol = x;
219   dd->yol = y;
220   dd->zol = z;
221   PetscFunctionReturn(0);
222 }
223 
224 /*@
225   DMDAGetNumLocalSubDomains - Gets the number of local subdomains created upon decomposition.
226 
227   Not collective
228 
229   Input Parameters:
230 . da  - The DMDA
231 
232   Output Parameters:
233 . Nsub   - Number of local subdomains created upon decomposition
234 
235   Level: intermediate
236 
237 .seealso: `DMCreateDomainDecomposition()`, `DMDASetNumLocalSubDomains()`, `DMDA`
238 @*/
239 PetscErrorCode  DMDAGetNumLocalSubDomains(DM da,PetscInt *Nsub)
240 {
241   DM_DA *dd = (DM_DA*)da->data;
242 
243   PetscFunctionBegin;
244   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
245   if (Nsub) *Nsub = dd->Nsub;
246   PetscFunctionReturn(0);
247 }
248 
249 /*@
250   DMDASetNumLocalSubDomains - Sets the number of local subdomains created upon decomposition.
251 
252   Not collective
253 
254   Input Parameters:
255 + da  - The DMDA
256 - Nsub - The number of local subdomains requested
257 
258   Level: intermediate
259 
260 .seealso: `DMCreateDomainDecomposition()`, `DMDAGetNumLocalSubDomains()`, `DMDA`
261 @*/
262 PetscErrorCode  DMDASetNumLocalSubDomains(DM da,PetscInt Nsub)
263 {
264   DM_DA *dd = (DM_DA*)da->data;
265 
266   PetscFunctionBegin;
267   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
268   PetscValidLogicalCollectiveInt(da,Nsub,2);
269   dd->Nsub = Nsub;
270   PetscFunctionReturn(0);
271 }
272 
273 /*@
274   DMDASetOffset - Sets the index offset of the DA.
275 
276   Collective on DA
277 
278   Input Parameters:
279 + da  - The DMDA
280 . xo  - The offset in the x direction
281 . yo  - The offset in the y direction
282 - zo  - The offset in the z direction
283 
284   Level: intermediate
285 
286   Notes:
287     This is used primarily to overlap a computation on a local DA with that on a global DA without
288   changing boundary conditions or subdomain features that depend upon the global offsets.
289 
290 .seealso: `DMDAGetOffset()`, `DMDAVecGetArray()`
291 @*/
292 PetscErrorCode  DMDASetOffset(DM da, PetscInt xo, PetscInt yo, PetscInt zo, PetscInt Mo, PetscInt No, PetscInt Po)
293 {
294   DM_DA          *dd = (DM_DA*)da->data;
295 
296   PetscFunctionBegin;
297   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
298   PetscValidLogicalCollectiveInt(da,xo,2);
299   PetscValidLogicalCollectiveInt(da,yo,3);
300   PetscValidLogicalCollectiveInt(da,zo,4);
301   PetscValidLogicalCollectiveInt(da,Mo,5);
302   PetscValidLogicalCollectiveInt(da,No,6);
303   PetscValidLogicalCollectiveInt(da,Po,7);
304   dd->xo = xo;
305   dd->yo = yo;
306   dd->zo = zo;
307   dd->Mo = Mo;
308   dd->No = No;
309   dd->Po = Po;
310 
311   if (da->coordinates[0].dm) PetscCall(DMDASetOffset(da->coordinates[0].dm,xo,yo,zo,Mo,No,Po));
312   PetscFunctionReturn(0);
313 }
314 
315 /*@
316   DMDAGetOffset - Gets the index offset of the DA.
317 
318   Not collective
319 
320   Input Parameter:
321 . da  - The DMDA
322 
323   Output Parameters:
324 + xo  - The offset in the x direction
325 . yo  - The offset in the y direction
326 . zo  - The offset in the z direction
327 . Mo  - The global size in the x direction
328 . No  - The global size in the y direction
329 - Po  - The global size in the z direction
330 
331   Level: intermediate
332 
333 .seealso: `DMDASetOffset()`, `DMDAVecGetArray()`
334 @*/
335 PetscErrorCode  DMDAGetOffset(DM da,PetscInt *xo,PetscInt *yo,PetscInt *zo,PetscInt *Mo,PetscInt *No,PetscInt *Po)
336 {
337   DM_DA *dd = (DM_DA*)da->data;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
341   if (xo) *xo = dd->xo;
342   if (yo) *yo = dd->yo;
343   if (zo) *zo = dd->zo;
344   if (Mo) *Mo = dd->Mo;
345   if (No) *No = dd->No;
346   if (Po) *Po = dd->Po;
347   PetscFunctionReturn(0);
348 }
349 
350 /*@
351   DMDAGetNonOverlappingRegion - Gets the indices of the nonoverlapping region of a subdomain DM.
352 
353   Not collective
354 
355   Input Parameter:
356 . da  - The DMDA
357 
358   Output Parameters:
359 + xs  - The start of the region in x
360 . ys  - The start of the region in y
361 . zs  - The start of the region in z
362 . xs  - The size of the region in x
363 . ys  - The size of the region in y
364 - zs  - The size of the region in z
365 
366   Level: intermediate
367 
368 .seealso: `DMDAGetOffset()`, `DMDAVecGetArray()`
369 @*/
370 PetscErrorCode  DMDAGetNonOverlappingRegion(DM da, PetscInt *xs, PetscInt *ys, PetscInt *zs, PetscInt *xm, PetscInt *ym, PetscInt *zm)
371 {
372   DM_DA          *dd = (DM_DA*)da->data;
373 
374   PetscFunctionBegin;
375   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
376   if (xs) *xs = dd->nonxs;
377   if (ys) *ys = dd->nonys;
378   if (zs) *zs = dd->nonzs;
379   if (xm) *xm = dd->nonxm;
380   if (ym) *ym = dd->nonym;
381   if (zm) *zm = dd->nonzm;
382   PetscFunctionReturn(0);
383 }
384 
385 /*@
386   DMDASetNonOverlappingRegion - Sets the indices of the nonoverlapping region of a subdomain DM.
387 
388   Collective on DA
389 
390   Input Parameters:
391 + da  - The DMDA
392 . xs  - The start of the region in x
393 . ys  - The start of the region in y
394 . zs  - The start of the region in z
395 . xs  - The size of the region in x
396 . ys  - The size of the region in y
397 - zs  - The size of the region in z
398 
399   Level: intermediate
400 
401 .seealso: `DMDAGetOffset()`, `DMDAVecGetArray()`
402 @*/
403 PetscErrorCode  DMDASetNonOverlappingRegion(DM da, PetscInt xs, PetscInt ys, PetscInt zs, PetscInt xm, PetscInt ym, PetscInt zm)
404 {
405   DM_DA          *dd = (DM_DA*)da->data;
406 
407   PetscFunctionBegin;
408   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
409   PetscValidLogicalCollectiveInt(da,xs,2);
410   PetscValidLogicalCollectiveInt(da,ys,3);
411   PetscValidLogicalCollectiveInt(da,zs,4);
412   PetscValidLogicalCollectiveInt(da,xm,5);
413   PetscValidLogicalCollectiveInt(da,ym,6);
414   PetscValidLogicalCollectiveInt(da,zm,7);
415   dd->nonxs = xs;
416   dd->nonys = ys;
417   dd->nonzs = zs;
418   dd->nonxm = xm;
419   dd->nonym = ym;
420   dd->nonzm = zm;
421 
422   PetscFunctionReturn(0);
423 }
424 
425 /*@
426   DMDASetStencilType - Sets the type of the communication stencil
427 
428   Logically Collective on da
429 
430   Input Parameters:
431 + da    - The DMDA
432 - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
433 
434   Level: intermediate
435 
436 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`
437 @*/
438 PetscErrorCode  DMDASetStencilType(DM da, DMDAStencilType stype)
439 {
440   DM_DA *dd = (DM_DA*)da->data;
441 
442   PetscFunctionBegin;
443   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
444   PetscValidLogicalCollectiveEnum(da,stype,2);
445   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
446   dd->stencil_type = stype;
447   PetscFunctionReturn(0);
448 }
449 
450 /*@
451   DMDAGetStencilType - Gets the type of the communication stencil
452 
453   Not collective
454 
455   Input Parameter:
456 . da    - The DMDA
457 
458   Output Parameter:
459 . stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
460 
461   Level: intermediate
462 
463 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`
464 @*/
465 PetscErrorCode DMDAGetStencilType(DM da, DMDAStencilType *stype)
466 {
467   DM_DA *dd = (DM_DA*)da->data;
468 
469   PetscFunctionBegin;
470   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
471   PetscValidPointer(stype,2);
472   *stype = dd->stencil_type;
473   PetscFunctionReturn(0);
474 }
475 
476 /*@
477   DMDASetStencilWidth - Sets the width of the communication stencil
478 
479   Logically Collective on da
480 
481   Input Parameters:
482 + da    - The DMDA
483 - width - The stencil width
484 
485   Level: intermediate
486 
487 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`
488 @*/
489 PetscErrorCode  DMDASetStencilWidth(DM da, PetscInt width)
490 {
491   DM_DA *dd = (DM_DA*)da->data;
492 
493   PetscFunctionBegin;
494   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
495   PetscValidLogicalCollectiveInt(da,width,2);
496   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
497   dd->s = width;
498   PetscFunctionReturn(0);
499 }
500 
501 /*@
502   DMDAGetStencilWidth - Gets the width of the communication stencil
503 
504   Not collective
505 
506   Input Parameter:
507 . da    - The DMDA
508 
509   Output Parameter:
510 . width - The stencil width
511 
512   Level: intermediate
513 
514 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`
515 @*/
516 PetscErrorCode DMDAGetStencilWidth(DM da, PetscInt *width)
517 {
518   DM_DA *dd = (DM_DA *) da->data;
519 
520   PetscFunctionBegin;
521   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
522   PetscValidIntPointer(width,2);
523   *width = dd->s;
524   PetscFunctionReturn(0);
525 }
526 
527 static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
528 {
529   PetscInt i,sum;
530 
531   PetscFunctionBegin;
532   PetscCheck(M >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
533   for (i=sum=0; i<m; i++) sum += lx[i];
534   PetscCheck(sum == M,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %" PetscInt_FMT " but global dimension is %" PetscInt_FMT,sum,M);
535   PetscFunctionReturn(0);
536 }
537 
538 /*@
539   DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process
540 
541   Logically Collective on da
542 
543   Input Parameters:
544 + da - The DMDA
545 . lx - array containing number of nodes in the X direction on each process, or NULL. If non-null, must be of length da->m
546 . ly - array containing number of nodes in the Y direction on each process, or NULL. If non-null, must be of length da->n
547 - lz - array containing number of nodes in the Z direction on each process, or NULL. If non-null, must be of length da->p.
548 
549   Level: intermediate
550 
551   Note: these numbers are NOT multiplied by the number of dof per node.
552 
553 .seealso: `DMDACreate()`, `DMDestroy()`, `DMDA`
554 @*/
555 PetscErrorCode  DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
556 {
557   DM_DA          *dd = (DM_DA*)da->data;
558 
559   PetscFunctionBegin;
560   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
561   PetscCheck(!da->setupcalled,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
562   if (lx) {
563     PetscCheck(dd->m >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
564     PetscCall(DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx));
565     if (!dd->lx) {
566       PetscCall(PetscMalloc1(dd->m, &dd->lx));
567     }
568     PetscCall(PetscArraycpy(dd->lx, lx, dd->m));
569   }
570   if (ly) {
571     PetscCheck(dd->n >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
572     PetscCall(DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly));
573     if (!dd->ly) {
574       PetscCall(PetscMalloc1(dd->n, &dd->ly));
575     }
576     PetscCall(PetscArraycpy(dd->ly, ly, dd->n));
577   }
578   if (lz) {
579     PetscCheck(dd->p >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
580     PetscCall(DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz));
581     if (!dd->lz) {
582       PetscCall(PetscMalloc1(dd->p, &dd->lz));
583     }
584     PetscCall(PetscArraycpy(dd->lz, lz, dd->p));
585   }
586   PetscFunctionReturn(0);
587 }
588 
589 /*@
590        DMDASetInterpolationType - Sets the type of interpolation that will be
591           returned by DMCreateInterpolation()
592 
593    Logically Collective on da
594 
595    Input Parameters:
596 +  da - initial distributed array
597 -  ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms
598 
599    Level: intermediate
600 
601    Notes:
602     you should call this on the coarser of the two DMDAs you pass to DMCreateInterpolation()
603 
604 .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMDestroy()`, `DMDA`, `DMDAInterpolationType`
605 @*/
606 PetscErrorCode  DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
607 {
608   DM_DA *dd = (DM_DA*)da->data;
609 
610   PetscFunctionBegin;
611   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
612   PetscValidLogicalCollectiveEnum(da,ctype,2);
613   dd->interptype = ctype;
614   PetscFunctionReturn(0);
615 }
616 
617 /*@
618        DMDAGetInterpolationType - Gets the type of interpolation that will be
619           used by DMCreateInterpolation()
620 
621    Not Collective
622 
623    Input Parameter:
624 .  da - distributed array
625 
626    Output Parameter:
627 .  ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms)
628 
629    Level: intermediate
630 
631 .seealso: `DMDA`, `DMDAInterpolationType`, `DMDASetInterpolationType()`, `DMCreateInterpolation()`
632 @*/
633 PetscErrorCode  DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
634 {
635   DM_DA *dd = (DM_DA*)da->data;
636 
637   PetscFunctionBegin;
638   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
639   PetscValidPointer(ctype,2);
640   *ctype = dd->interptype;
641   PetscFunctionReturn(0);
642 }
643 
644 /*@C
645       DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
646         processes neighbors.
647 
648     Not Collective
649 
650    Input Parameter:
651 .     da - the DMDA object
652 
653    Output Parameters:
654 .     ranks - the neighbors ranks, stored with the x index increasing most rapidly.
655               this process itself is in the list
656 
657    Notes:
658     In 2d the array is of length 9, in 3d of length 27
659           Not supported in 1d
660           Do not free the array, it is freed when the DMDA is destroyed.
661 
662    Fortran Notes:
663     In fortran you must pass in an array of the appropriate length.
664 
665    Level: intermediate
666 
667 @*/
668 PetscErrorCode  DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
669 {
670   DM_DA *dd = (DM_DA*)da->data;
671 
672   PetscFunctionBegin;
673   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
674   *ranks = dd->neighbors;
675   PetscFunctionReturn(0);
676 }
677 
678 /*@C
679       DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process
680 
681     Not Collective
682 
683    Input Parameter:
684 .     da - the DMDA object
685 
686    Output Parameters:
687 +     lx - ownership along x direction (optional)
688 .     ly - ownership along y direction (optional)
689 -     lz - ownership along z direction (optional)
690 
691    Level: intermediate
692 
693     Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d()
694 
695     In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and
696     eighth arguments from DMDAGetInfo()
697 
698      In C you should not free these arrays, nor change the values in them. They will only have valid values while the
699     DMDA they came from still exists (has not been destroyed).
700 
701     These numbers are NOT multiplied by the number of dof per node.
702 
703 .seealso: `DMDAGetCorners()`, `DMDAGetGhostCorners()`, `DMDACreate()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `VecGetOwnershipRanges()`
704 @*/
705 PetscErrorCode  DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
706 {
707   DM_DA *dd = (DM_DA*)da->data;
708 
709   PetscFunctionBegin;
710   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
711   if (lx) *lx = dd->lx;
712   if (ly) *ly = dd->ly;
713   if (lz) *lz = dd->lz;
714   PetscFunctionReturn(0);
715 }
716 
717 /*@
718      DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined
719 
720     Logically Collective on da
721 
722   Input Parameters:
723 +    da - the DMDA object
724 .    refine_x - ratio of fine grid to coarse in x direction (2 by default)
725 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
726 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
727 
728   Options Database:
729 +  -da_refine_x refine_x - refinement ratio in x direction
730 .  -da_refine_y rafine_y - refinement ratio in y direction
731 .  -da_refine_z refine_z - refinement ratio in z direction
732 -  -da_refine <n> - refine the DMDA object n times when it is created.
733 
734   Level: intermediate
735 
736     Notes:
737     Pass PETSC_IGNORE to leave a value unchanged
738 
739 .seealso: `DMRefine()`, `DMDAGetRefinementFactor()`
740 @*/
741 PetscErrorCode  DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
742 {
743   DM_DA *dd = (DM_DA*)da->data;
744 
745   PetscFunctionBegin;
746   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
747   PetscValidLogicalCollectiveInt(da,refine_x,2);
748   PetscValidLogicalCollectiveInt(da,refine_y,3);
749   PetscValidLogicalCollectiveInt(da,refine_z,4);
750 
751   if (refine_x > 0) dd->refine_x = refine_x;
752   if (refine_y > 0) dd->refine_y = refine_y;
753   if (refine_z > 0) dd->refine_z = refine_z;
754   PetscFunctionReturn(0);
755 }
756 
757 /*@C
758      DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined
759 
760     Not Collective
761 
762   Input Parameter:
763 .    da - the DMDA object
764 
765   Output Parameters:
766 +    refine_x - ratio of fine grid to coarse in x direction (2 by default)
767 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
768 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
769 
770   Level: intermediate
771 
772     Notes:
773     Pass NULL for values you do not need
774 
775 .seealso: `DMRefine()`, `DMDASetRefinementFactor()`
776 @*/
777 PetscErrorCode  DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
778 {
779   DM_DA *dd = (DM_DA*)da->data;
780 
781   PetscFunctionBegin;
782   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
783   if (refine_x) *refine_x = dd->refine_x;
784   if (refine_y) *refine_y = dd->refine_y;
785   if (refine_z) *refine_z = dd->refine_z;
786   PetscFunctionReturn(0);
787 }
788 
789 /*@C
790      DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix.
791 
792     Logically Collective on da
793 
794   Input Parameters:
795 +    da - the DMDA object
796 -    f - the function that allocates the matrix for that specific DMDA
797 
798   Level: developer
799 
800    Notes:
801     See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for
802        the diagonal and off-diagonal blocks of the matrix
803 
804    Not supported from Fortran
805 
806 .seealso: `DMCreateMatrix()`, `DMDASetBlockFills()`
807 @*/
808 PetscErrorCode  DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, Mat*))
809 {
810   PetscFunctionBegin;
811   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
812   da->ops->creatematrix = f;
813   PetscFunctionReturn(0);
814 }
815 
816 /*@
817    DMDAMapMatStencilToGlobal - Map a list of MatStencils on a grid to global indices.
818 
819    Not Collective
820 
821    Input Parameters:
822 +  da - the DMDA object
823 .  m - number of MatStencils
824 -  idxm - grid points (and component number when dof > 1)
825 
826    Output Parameter:
827 .  gidxm - global row indices
828 
829    Level: intermediate
830 
831 .seealso: `MatStencil`
832 @*/
833 PetscErrorCode DMDAMapMatStencilToGlobal(DM da,PetscInt m,const MatStencil idxm[],PetscInt gidxm[])
834 {
835   const DM_DA            *dd = (const DM_DA*)da->data;
836   const PetscInt         *dxm = (const PetscInt*)idxm;
837   PetscInt               i,j,sdim,tmp,dim;
838   PetscInt               dims[4],starts[4],dims2[3],starts2[3],dof = dd->w;
839   ISLocalToGlobalMapping ltog;
840 
841   PetscFunctionBegin;
842   if (m <= 0) PetscFunctionReturn(0);
843 
844   /* Code adapted from DMDAGetGhostCorners() */
845   starts2[0] = dd->Xs/dof + dd->xo;
846   starts2[1] = dd->Ys  + dd->yo;
847   starts2[2] = dd->Zs  + dd->zo;
848   dims2[0]   = (dd->Xe - dd->Xs)/dof;
849   dims2[1]   = (dd->Ye - dd->Ys);
850   dims2[2]   = (dd->Ze - dd->Zs);
851 
852   /* As if we do MatSetStencil() to get dims[]/starts[] of mat->stencil */
853   dim  = da->dim; /* DA dim: 1 to 3 */
854   sdim = dim + (dof > 1? 1 : 0); /* Dimensions in MatStencil's (k,j,i,c) view */
855   for (i=0; i<dim; i++) { /* Reverse the order and also skip the unused dimensions */
856     dims[i]   = dims2[dim-i-1]; /* ex. dims/starts[] are in order of {i} for 1D, {j,i} for 2D and {k,j,i} for 3D */
857     starts[i] = starts2[dim-i-1];
858   }
859   starts[dim] = 0; /* Append the extra dim for dof (won't be used below if dof=1) */
860   dims[dim]   = dof;
861 
862   /* Map stencils to local indices (code adapted from MatSetValuesStencil()) */
863   for (i=0; i<m; i++) {
864     dxm += 3-dim; /* Input is {k,j,i,c}; move the pointer to the first used index, e.g., j in 2D */
865     tmp  = 0;
866     for (j=0; j<sdim; j++) { /* Iter over, ex. j,i or j,i,c in 2D */
867       if (tmp < 0 || dxm[j] < starts[j] || dxm[j] >= (starts[j] + dims[j])) tmp = -1; /* Beyond the ghost region, therefore ignored with negative indices */
868       else tmp = tmp*dims[j] + (dxm[j] - starts[j]);
869     }
870     gidxm[i] = tmp;
871     /* Move to the next MatStencil point */
872     if (dof > 1) dxm += sdim; /* c is already counted in sdim */
873     else dxm += sdim + 1; /* skip the unused c */
874   }
875 
876   /* Map local indices to global indices */
877   PetscCall(DMGetLocalToGlobalMapping(da,&ltog));
878   PetscCall(ISLocalToGlobalMappingApply(ltog,m,gidxm,gidxm));
879   PetscFunctionReturn(0);
880 }
881 
882 /*
883   Creates "balanced" ownership ranges after refinement, constrained by the need for the
884   fine grid boundaries to fall within one stencil width of the coarse partition.
885 
886   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
887 */
888 static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[])
889 {
890   PetscInt       i,totalc = 0,remaining,startc = 0,startf = 0;
891 
892   PetscFunctionBegin;
893   PetscCheck(ratio >= 1,PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %" PetscInt_FMT " must be at least 1",ratio);
894   if (ratio == 1) {
895     PetscCall(PetscArraycpy(lf,lc,m));
896     PetscFunctionReturn(0);
897   }
898   for (i=0; i<m; i++) totalc += lc[i];
899   remaining = (!periodic) + ratio * (totalc - (!periodic));
900   for (i=0; i<m; i++) {
901     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
902     if (i == m-1) lf[i] = want;
903     else {
904       const PetscInt nextc = startc + lc[i];
905       /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
906        * coarse stencil width of the first coarse node in the next subdomain. */
907       while ((startf+want)/ratio < nextc - stencil_width) want++;
908       /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
909        * coarse stencil width of the last coarse node in the current subdomain. */
910       while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
911       /* Make sure all constraints are satisfied */
912       if (want < 0 || want > remaining || ((startf+want)/ratio < nextc - stencil_width)
913           || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range");
914     }
915     lf[i]      = want;
916     startc    += lc[i];
917     startf    += lf[i];
918     remaining -= lf[i];
919   }
920   PetscFunctionReturn(0);
921 }
922 
923 /*
924   Creates "balanced" ownership ranges after coarsening, constrained by the need for the
925   fine grid boundaries to fall within one stencil width of the coarse partition.
926 
927   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
928 */
929 static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[])
930 {
931   PetscInt       i,totalf,remaining,startc,startf;
932 
933   PetscFunctionBegin;
934   PetscCheck(ratio >= 1,PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %" PetscInt_FMT " must be at least 1",ratio);
935   if (ratio == 1) {
936     PetscCall(PetscArraycpy(lc,lf,m));
937     PetscFunctionReturn(0);
938   }
939   for (i=0,totalf=0; i<m; i++) totalf += lf[i];
940   remaining = (!periodic) + (totalf - (!periodic)) / ratio;
941   for (i=0,startc=0,startf=0; i<m; i++) {
942     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
943     if (i == m-1) lc[i] = want;
944     else {
945       const PetscInt nextf = startf+lf[i];
946       /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
947        * node is within one stencil width. */
948       while (nextf/ratio < startc+want-stencil_width) want--;
949       /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
950        * fine node is within one stencil width. */
951       while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
952       if (want < 0 || want > remaining
953           || (nextf/ratio < startc+want-stencil_width) || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range");
954     }
955     lc[i]      = want;
956     startc    += lc[i];
957     startf    += lf[i];
958     remaining -= lc[i];
959   }
960   PetscFunctionReturn(0);
961 }
962 
963 PetscErrorCode DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
964 {
965   PetscInt M,N,P,i,dim;
966   Vec      coordsc, coordsf;
967   DM       da2;
968   DM_DA   *dd = (DM_DA*)da->data,*dd2;
969 
970   PetscFunctionBegin;
971   PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
972   PetscValidPointer(daref,3);
973 
974   PetscCall(DMGetDimension(da, &dim));
975   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
976     M = dd->refine_x*dd->M;
977   } else {
978     M = 1 + dd->refine_x*(dd->M - 1);
979   }
980   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
981     if (dim > 1) {
982       N = dd->refine_y*dd->N;
983     } else {
984       N = 1;
985     }
986   } else {
987     N = 1 + dd->refine_y*(dd->N - 1);
988   }
989   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
990     if (dim > 2) {
991       P = dd->refine_z*dd->P;
992     } else {
993       P = 1;
994     }
995   } else {
996     P = 1 + dd->refine_z*(dd->P - 1);
997   }
998   PetscCall(DMDACreate(PetscObjectComm((PetscObject)da),&da2));
999   PetscCall(DMSetOptionsPrefix(da2,((PetscObject)da)->prefix));
1000   PetscCall(DMSetDimension(da2,dim));
1001   PetscCall(DMDASetSizes(da2,M,N,P));
1002   PetscCall(DMDASetNumProcs(da2,dd->m,dd->n,dd->p));
1003   PetscCall(DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz));
1004   PetscCall(DMDASetDof(da2,dd->w));
1005   PetscCall(DMDASetStencilType(da2,dd->stencil_type));
1006   PetscCall(DMDASetStencilWidth(da2,dd->s));
1007   if (dim == 3) {
1008     PetscInt *lx,*ly,*lz;
1009     PetscCall(PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz));
1010     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx));
1011     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly));
1012     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz));
1013     PetscCall(DMDASetOwnershipRanges(da2,lx,ly,lz));
1014     PetscCall(PetscFree3(lx,ly,lz));
1015   } else if (dim == 2) {
1016     PetscInt *lx,*ly;
1017     PetscCall(PetscMalloc2(dd->m,&lx,dd->n,&ly));
1018     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx));
1019     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly));
1020     PetscCall(DMDASetOwnershipRanges(da2,lx,ly,NULL));
1021     PetscCall(PetscFree2(lx,ly));
1022   } else if (dim == 1) {
1023     PetscInt *lx;
1024     PetscCall(PetscMalloc1(dd->m,&lx));
1025     PetscCall(DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx));
1026     PetscCall(DMDASetOwnershipRanges(da2,lx,NULL,NULL));
1027     PetscCall(PetscFree(lx));
1028   }
1029   dd2 = (DM_DA*)da2->data;
1030 
1031   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
1032   da2->ops->creatematrix = da->ops->creatematrix;
1033   /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */
1034   da2->ops->getcoloring = da->ops->getcoloring;
1035   dd2->interptype       = dd->interptype;
1036 
1037   /* copy fill information if given */
1038   if (dd->dfill) {
1039     PetscCall(PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill));
1040     PetscCall(PetscArraycpy(dd2->dfill,dd->dfill,dd->dfill[dd->w]+dd->w+1));
1041   }
1042   if (dd->ofill) {
1043     PetscCall(PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill));
1044     PetscCall(PetscArraycpy(dd2->ofill,dd->ofill,dd->ofill[dd->w]+dd->w+1));
1045   }
1046   /* copy the refine information */
1047   dd2->coarsen_x = dd2->refine_x = dd->refine_x;
1048   dd2->coarsen_y = dd2->refine_y = dd->refine_y;
1049   dd2->coarsen_z = dd2->refine_z = dd->refine_z;
1050 
1051   if (dd->refine_z_hier) {
1052     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_z_hier_n) {
1053       dd2->refine_z = dd->refine_z_hier[da->levelup - da->leveldown + 1];
1054     }
1055     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_z_hier_n) {
1056       dd2->coarsen_z = dd->refine_z_hier[da->levelup - da->leveldown];
1057     }
1058     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1059     PetscCall(PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier));
1060     PetscCall(PetscArraycpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n));
1061   }
1062   if (dd->refine_y_hier) {
1063     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_y_hier_n) {
1064       dd2->refine_y = dd->refine_y_hier[da->levelup - da->leveldown + 1];
1065     }
1066     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_y_hier_n) {
1067       dd2->coarsen_y = dd->refine_y_hier[da->levelup - da->leveldown];
1068     }
1069     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1070     PetscCall(PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier));
1071     PetscCall(PetscArraycpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n));
1072   }
1073   if (dd->refine_x_hier) {
1074     if (da->levelup - da->leveldown + 1 > -1 && da->levelup - da->leveldown + 1 < dd->refine_x_hier_n) {
1075       dd2->refine_x = dd->refine_x_hier[da->levelup - da->leveldown + 1];
1076     }
1077     if (da->levelup - da->leveldown > -1 && da->levelup - da->leveldown < dd->refine_x_hier_n) {
1078       dd2->coarsen_x = dd->refine_x_hier[da->levelup - da->leveldown];
1079     }
1080     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1081     PetscCall(PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier));
1082     PetscCall(PetscArraycpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n));
1083   }
1084 
1085   /* copy vector type information */
1086   PetscCall(DMSetVecType(da2,da->vectype));
1087 
1088   dd2->lf = dd->lf;
1089   dd2->lj = dd->lj;
1090 
1091   da2->leveldown = da->leveldown;
1092   da2->levelup   = da->levelup + 1;
1093 
1094   PetscCall(DMSetUp(da2));
1095 
1096   /* interpolate coordinates if they are set on the coarse grid */
1097   PetscCall(DMGetCoordinates(da, &coordsc));
1098   if (coordsc) {
1099     DM  cdaf,cdac;
1100     Mat II;
1101 
1102     PetscCall(DMGetCoordinateDM(da,&cdac));
1103     PetscCall(DMGetCoordinateDM(da2,&cdaf));
1104     /* force creation of the coordinate vector */
1105     PetscCall(DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0));
1106     PetscCall(DMGetCoordinates(da2,&coordsf));
1107     PetscCall(DMCreateInterpolation(cdac,cdaf,&II,NULL));
1108     PetscCall(MatInterpolate(II,coordsc,coordsf));
1109     PetscCall(MatDestroy(&II));
1110   }
1111 
1112   for (i=0; i<da->bs; i++) {
1113     const char *fieldname;
1114     PetscCall(DMDAGetFieldName(da,i,&fieldname));
1115     PetscCall(DMDASetFieldName(da2,i,fieldname));
1116   }
1117 
1118   *daref = da2;
1119   PetscFunctionReturn(0);
1120 }
1121 
1122 PetscErrorCode  DMCoarsen_DA(DM dmf, MPI_Comm comm,DM *dmc)
1123 {
1124   PetscInt       M,N,P,i,dim;
1125   Vec            coordsc, coordsf;
1126   DM             dmc2;
1127   DM_DA          *dd = (DM_DA*)dmf->data,*dd2;
1128 
1129   PetscFunctionBegin;
1130   PetscValidHeaderSpecificType(dmf,DM_CLASSID,1,DMDA);
1131   PetscValidPointer(dmc,3);
1132 
1133   PetscCall(DMGetDimension(dmf, &dim));
1134   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1135     M = dd->M / dd->coarsen_x;
1136   } else {
1137     M = 1 + (dd->M - 1) / dd->coarsen_x;
1138   }
1139   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1140     if (dim > 1) {
1141       N = dd->N / dd->coarsen_y;
1142     } else {
1143       N = 1;
1144     }
1145   } else {
1146     N = 1 + (dd->N - 1) / dd->coarsen_y;
1147   }
1148   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1149     if (dim > 2) {
1150       P = dd->P / dd->coarsen_z;
1151     } else {
1152       P = 1;
1153     }
1154   } else {
1155     P = 1 + (dd->P - 1) / dd->coarsen_z;
1156   }
1157   PetscCall(DMDACreate(PetscObjectComm((PetscObject)dmf),&dmc2));
1158   PetscCall(DMSetOptionsPrefix(dmc2,((PetscObject)dmf)->prefix));
1159   PetscCall(DMSetDimension(dmc2,dim));
1160   PetscCall(DMDASetSizes(dmc2,M,N,P));
1161   PetscCall(DMDASetNumProcs(dmc2,dd->m,dd->n,dd->p));
1162   PetscCall(DMDASetBoundaryType(dmc2,dd->bx,dd->by,dd->bz));
1163   PetscCall(DMDASetDof(dmc2,dd->w));
1164   PetscCall(DMDASetStencilType(dmc2,dd->stencil_type));
1165   PetscCall(DMDASetStencilWidth(dmc2,dd->s));
1166   if (dim == 3) {
1167     PetscInt *lx,*ly,*lz;
1168     PetscCall(PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz));
1169     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx));
1170     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly));
1171     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_z,dd->p,dd->lz,lz));
1172     PetscCall(DMDASetOwnershipRanges(dmc2,lx,ly,lz));
1173     PetscCall(PetscFree3(lx,ly,lz));
1174   } else if (dim == 2) {
1175     PetscInt *lx,*ly;
1176     PetscCall(PetscMalloc2(dd->m,&lx,dd->n,&ly));
1177     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx));
1178     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly));
1179     PetscCall(DMDASetOwnershipRanges(dmc2,lx,ly,NULL));
1180     PetscCall(PetscFree2(lx,ly));
1181   } else if (dim == 1) {
1182     PetscInt *lx;
1183     PetscCall(PetscMalloc1(dd->m,&lx));
1184     PetscCall(DMDACoarsenOwnershipRanges(dmf,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx));
1185     PetscCall(DMDASetOwnershipRanges(dmc2,lx,NULL,NULL));
1186     PetscCall(PetscFree(lx));
1187   }
1188   dd2 = (DM_DA*)dmc2->data;
1189 
1190   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
1191   /* dmc2->ops->createinterpolation = dmf->ops->createinterpolation; copying this one causes trouble for DMSetVI */
1192   dmc2->ops->creatematrix = dmf->ops->creatematrix;
1193   dmc2->ops->getcoloring  = dmf->ops->getcoloring;
1194   dd2->interptype         = dd->interptype;
1195 
1196   /* copy fill information if given */
1197   if (dd->dfill) {
1198     PetscCall(PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill));
1199     PetscCall(PetscArraycpy(dd2->dfill,dd->dfill,dd->dfill[dd->w]+dd->w+1));
1200   }
1201   if (dd->ofill) {
1202     PetscCall(PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill));
1203     PetscCall(PetscArraycpy(dd2->ofill,dd->ofill,dd->ofill[dd->w]+dd->w+1));
1204   }
1205   /* copy the refine information */
1206   dd2->coarsen_x = dd2->refine_x = dd->coarsen_x;
1207   dd2->coarsen_y = dd2->refine_y = dd->coarsen_y;
1208   dd2->coarsen_z = dd2->refine_z = dd->coarsen_z;
1209 
1210   if (dd->refine_z_hier) {
1211     if (dmf->levelup - dmf->leveldown -1 > -1 && dmf->levelup - dmf->leveldown - 1< dd->refine_z_hier_n) {
1212       dd2->refine_z = dd->refine_z_hier[dmf->levelup - dmf->leveldown - 1];
1213     }
1214     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_z_hier_n) {
1215       dd2->coarsen_z = dd->refine_z_hier[dmf->levelup - dmf->leveldown - 2];
1216     }
1217     dd2->refine_z_hier_n = dd->refine_z_hier_n;
1218     PetscCall(PetscMalloc1(dd2->refine_z_hier_n,&dd2->refine_z_hier));
1219     PetscCall(PetscArraycpy(dd2->refine_z_hier,dd->refine_z_hier,dd2->refine_z_hier_n));
1220   }
1221   if (dd->refine_y_hier) {
1222     if (dmf->levelup - dmf->leveldown - 1 > -1 && dmf->levelup - dmf->leveldown - 1< dd->refine_y_hier_n) {
1223       dd2->refine_y = dd->refine_y_hier[dmf->levelup - dmf->leveldown - 1];
1224     }
1225     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_y_hier_n) {
1226       dd2->coarsen_y = dd->refine_y_hier[dmf->levelup - dmf->leveldown - 2];
1227     }
1228     dd2->refine_y_hier_n = dd->refine_y_hier_n;
1229     PetscCall(PetscMalloc1(dd2->refine_y_hier_n,&dd2->refine_y_hier));
1230     PetscCall(PetscArraycpy(dd2->refine_y_hier,dd->refine_y_hier,dd2->refine_y_hier_n));
1231   }
1232   if (dd->refine_x_hier) {
1233     if (dmf->levelup - dmf->leveldown - 1 > -1 && dmf->levelup - dmf->leveldown - 1 < dd->refine_x_hier_n) {
1234       dd2->refine_x = dd->refine_x_hier[dmf->levelup - dmf->leveldown - 1];
1235     }
1236     if (dmf->levelup - dmf->leveldown - 2 > -1 && dmf->levelup - dmf->leveldown - 2 < dd->refine_x_hier_n) {
1237       dd2->coarsen_x = dd->refine_x_hier[dmf->levelup - dmf->leveldown - 2];
1238     }
1239     dd2->refine_x_hier_n = dd->refine_x_hier_n;
1240     PetscCall(PetscMalloc1(dd2->refine_x_hier_n,&dd2->refine_x_hier));
1241     PetscCall(PetscArraycpy(dd2->refine_x_hier,dd->refine_x_hier,dd2->refine_x_hier_n));
1242   }
1243 
1244   /* copy vector type information */
1245   PetscCall(DMSetVecType(dmc2,dmf->vectype));
1246 
1247   dd2->lf = dd->lf;
1248   dd2->lj = dd->lj;
1249 
1250   dmc2->leveldown = dmf->leveldown + 1;
1251   dmc2->levelup   = dmf->levelup;
1252 
1253   PetscCall(DMSetUp(dmc2));
1254 
1255   /* inject coordinates if they are set on the fine grid */
1256   PetscCall(DMGetCoordinates(dmf, &coordsf));
1257   if (coordsf) {
1258     DM         cdaf,cdac;
1259     Mat        inject;
1260     VecScatter vscat;
1261 
1262     PetscCall(DMGetCoordinateDM(dmf,&cdaf));
1263     PetscCall(DMGetCoordinateDM(dmc2,&cdac));
1264     /* force creation of the coordinate vector */
1265     PetscCall(DMDASetUniformCoordinates(dmc2,0.0,1.0,0.0,1.0,0.0,1.0));
1266     PetscCall(DMGetCoordinates(dmc2,&coordsc));
1267 
1268     PetscCall(DMCreateInjection(cdac,cdaf,&inject));
1269     PetscCall(MatScatterGetVecScatter(inject,&vscat));
1270     PetscCall(VecScatterBegin(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD));
1271     PetscCall(VecScatterEnd(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD));
1272     PetscCall(MatDestroy(&inject));
1273   }
1274 
1275   for (i=0; i<dmf->bs; i++) {
1276     const char *fieldname;
1277     PetscCall(DMDAGetFieldName(dmf,i,&fieldname));
1278     PetscCall(DMDASetFieldName(dmc2,i,fieldname));
1279   }
1280 
1281   *dmc = dmc2;
1282   PetscFunctionReturn(0);
1283 }
1284 
1285 PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
1286 {
1287   PetscInt       i,n,*refx,*refy,*refz;
1288 
1289   PetscFunctionBegin;
1290   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1291   PetscCheck(nlevels >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1292   if (nlevels == 0) PetscFunctionReturn(0);
1293   PetscValidPointer(daf,3);
1294 
1295   /* Get refinement factors, defaults taken from the coarse DMDA */
1296   PetscCall(PetscMalloc3(nlevels,&refx,nlevels,&refy,nlevels,&refz));
1297   for (i=0; i<nlevels; i++) {
1298     PetscCall(DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]));
1299   }
1300   n    = nlevels;
1301   PetscCall(PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,NULL));
1302   n    = nlevels;
1303   PetscCall(PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,NULL));
1304   n    = nlevels;
1305   PetscCall(PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,NULL));
1306 
1307   PetscCall(DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]));
1308   PetscCall(DMRefine(da,PetscObjectComm((PetscObject)da),&daf[0]));
1309   for (i=1; i<nlevels; i++) {
1310     PetscCall(DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]));
1311     PetscCall(DMRefine(daf[i-1],PetscObjectComm((PetscObject)da),&daf[i]));
1312   }
1313   PetscCall(PetscFree3(refx,refy,refz));
1314   PetscFunctionReturn(0);
1315 }
1316 
1317 PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
1318 {
1319   PetscInt       i;
1320 
1321   PetscFunctionBegin;
1322   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1323   PetscCheck(nlevels >= 0,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1324   if (nlevels == 0) PetscFunctionReturn(0);
1325   PetscValidPointer(dac,3);
1326   PetscCall(DMCoarsen(da,PetscObjectComm((PetscObject)da),&dac[0]));
1327   for (i=1; i<nlevels; i++) {
1328     PetscCall(DMCoarsen(dac[i-1],PetscObjectComm((PetscObject)da),&dac[i]));
1329   }
1330   PetscFunctionReturn(0);
1331 }
1332 
1333 PetscErrorCode DMDASetGLLCoordinates_1d(DM dm,PetscInt n,PetscReal *nodes)
1334 {
1335   PetscInt       i,j,xs,xn,q;
1336   PetscScalar    *xx;
1337   PetscReal      h;
1338   Vec            x;
1339   DM_DA          *da = (DM_DA*)dm->data;
1340 
1341   PetscFunctionBegin;
1342   if (da->bx != DM_BOUNDARY_PERIODIC) {
1343     PetscCall(DMDAGetInfo(dm,NULL,&q,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
1344     q    = (q-1)/(n-1);  /* number of spectral elements */
1345     h    = 2.0/q;
1346     PetscCall(DMDAGetCorners(dm,&xs,NULL,NULL,&xn,NULL,NULL));
1347     xs   = xs/(n-1);
1348     xn   = xn/(n-1);
1349     PetscCall(DMDASetUniformCoordinates(dm,-1.,1.,0.,0.,0.,0.));
1350     PetscCall(DMGetCoordinates(dm,&x));
1351     PetscCall(DMDAVecGetArray(dm,x,&xx));
1352 
1353     /* loop over local spectral elements */
1354     for (j=xs; j<xs+xn; j++) {
1355       /*
1356        Except for the first process, each process starts on the second GLL point of the first element on that process
1357        */
1358       for (i= (j == xs && xs > 0)? 1 : 0; i<n; i++) {
1359         xx[j*(n-1) + i] = -1.0 + h*j + h*(nodes[i]+1.0)/2.;
1360       }
1361     }
1362     PetscCall(DMDAVecRestoreArray(dm,x,&xx));
1363   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for periodic");
1364   PetscFunctionReturn(0);
1365 }
1366 
1367 /*@
1368 
1369      DMDASetGLLCoordinates - Sets the global coordinates from -1 to 1 to the GLL points of as many GLL elements that fit the number of grid points
1370 
1371    Collective on da
1372 
1373    Input Parameters:
1374 +   da - the DMDA object
1375 -   n - the number of GLL nodes
1376 -   nodes - the GLL nodes
1377 
1378    Notes:
1379     the parallel decomposition of grid points must correspond to the degree of the GLL. That is, the number of grid points
1380           on each process much be divisible by the number of GLL elements needed per process. This depends on whether the DM is
1381           periodic or not.
1382 
1383    Level: advanced
1384 
1385 .seealso: `DMDACreate()`, `PetscDTGaussLobattoLegendreQuadrature()`, `DMGetCoordinates()`
1386 @*/
1387 PetscErrorCode DMDASetGLLCoordinates(DM da,PetscInt n,PetscReal *nodes)
1388 {
1389   PetscFunctionBegin;
1390   if (da->dim == 1) {
1391     PetscCall(DMDASetGLLCoordinates_1d(da,n,nodes));
1392   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Not yet implemented for 2 or 3d");
1393   PetscFunctionReturn(0);
1394 }
1395 
1396 PETSC_INTERN PetscErrorCode DMGetCompatibility_DA(DM da1,DM dm2,PetscBool *compatible,PetscBool *set)
1397 {
1398   DM_DA          *dd1 = (DM_DA*)da1->data,*dd2;
1399   DM             da2;
1400   DMType         dmtype2;
1401   PetscBool      isda,compatibleLocal;
1402   PetscInt       i;
1403 
1404   PetscFunctionBegin;
1405   PetscCheck(da1->setupcalled,PetscObjectComm((PetscObject)da1),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on first DM before DMGetCompatibility()");
1406   PetscCall(DMGetType(dm2,&dmtype2));
1407   PetscCall(PetscStrcmp(dmtype2,DMDA,&isda));
1408   if (isda) {
1409     da2 = dm2;
1410     dd2 = (DM_DA*)da2->data;
1411     PetscCheck(da2->setupcalled,PetscObjectComm((PetscObject)da2),PETSC_ERR_ARG_WRONGSTATE,"DMSetUp() must be called on second DM before DMGetCompatibility()");
1412     compatibleLocal = (PetscBool)(da1->dim == da2->dim);
1413     if (compatibleLocal) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->s == dd2->s)); /* Stencil width */
1414     /*                                                                           Global size              ranks               Boundary type */
1415     if (compatibleLocal)                 compatibleLocal = (PetscBool)(compatibleLocal && (dd1->M == dd2->M) && (dd1->m == dd2->m) && (dd1->bx == dd2->bx));
1416     if (compatibleLocal && da1->dim > 1) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->N == dd2->N) && (dd1->n == dd2->n) && (dd1->by == dd2->by));
1417     if (compatibleLocal && da1->dim > 2) compatibleLocal = (PetscBool)(compatibleLocal && (dd1->P == dd2->P) && (dd1->p == dd2->p) && (dd1->bz == dd2->bz));
1418     if (compatibleLocal) {
1419       for (i=0; i<dd1->m; ++i) {
1420         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lx[i] == dd2->lx[i]));           /* Local size     */
1421       }
1422     }
1423     if (compatibleLocal && da1->dim > 1) {
1424       for (i=0; i<dd1->n; ++i) {
1425         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->ly[i] == dd2->ly[i]));
1426       }
1427     }
1428     if (compatibleLocal && da1->dim > 2) {
1429       for (i=0; i<dd1->p; ++i) {
1430         compatibleLocal = (PetscBool)(compatibleLocal && (dd1->lz[i] == dd2->lz[i]));
1431       }
1432     }
1433     *compatible = compatibleLocal;
1434     *set = PETSC_TRUE;
1435   } else {
1436     /* Decline to determine compatibility with other DM types */
1437     *set = PETSC_FALSE;
1438   }
1439   PetscFunctionReturn(0);
1440 }
1441