xref: /petsc/src/dm/impls/da/da.c (revision 9a42bb27a39f0cdf3306a1e22d33cd9809484eaa)
1 #define PETSCDM_DLL
2 #include "private/daimpl.h"    /*I   "petscda.h"   I*/
3 
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "DASetDim"
7 /*@
8   DASetDim - Sets the dimension
9 
10   Collective on DA
11 
12   Input Parameters:
13 + da - the DA
14 - dim - the dimension (or PETSC_DECIDE)
15 
16   Level: intermediate
17 
18 .seealso: DaGetDim(), DASetSizes()
19 @*/
20 PetscErrorCode PETSCDM_DLLEXPORT DASetDim(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 DA 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__ "DASetSizes"
33 /*@
34   DASetSizes - Sets the global sizes
35 
36   Logically Collective on DA
37 
38   Input Parameters:
39 + da - the DA
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: DAGetSize(), PetscSplitOwnership()
47 @*/
48 PetscErrorCode PETSCDM_DLLEXPORT DASetSizes(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__ "DASetNumProcs"
66 /*@
67   DASetNumProcs - Sets the number of processes in each dimension
68 
69   Logically Collective on DA
70 
71   Input Parameters:
72 + da - the DA
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: DASetSizes(), DAGetSize(), PetscSplitOwnership()
80 @*/
81 PetscErrorCode PETSCDM_DLLEXPORT DASetNumProcs(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__ "DASetPeriodicity"
98 /*@
99   DASetPeriodicity - Sets the type of periodicity
100 
101   Not collective
102 
103   Input Parameter:
104 + da    - The DA
105 - ptype - One of DA_NONPERIODIC, DA_XPERIODIC, DA_YPERIODIC, DA_ZPERIODIC, DA_XYPERIODIC, DA_XZPERIODIC, DA_YZPERIODIC, or DA_XYZPERIODIC
106 
107   Level: intermediate
108 
109 .keywords:  distributed array, periodicity
110 .seealso: DACreate(), DMDestroy(), DA, DAPeriodicType
111 @*/
112 PetscErrorCode PETSCDM_DLLEXPORT DASetPeriodicity(DM da, DAPeriodicType 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__ "DASetDof"
124 /*@
125   DASetDof - Sets the number of degrees of freedom per vertex
126 
127   Not collective
128 
129   Input Parameter:
130 + da  - The DA
131 - dof - Number of degrees of freedom
132 
133   Level: intermediate
134 
135 .keywords:  distributed array, degrees of freedom
136 .seealso: DACreate(), DMDestroy(), DA
137 @*/
138 PetscErrorCode PETSCDM_DLLEXPORT DASetDof(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__ "DASetStencilType"
150 /*@
151   DASetStencilType - Sets the type of the communication stencil
152 
153   Logically Collective on DA
154 
155   Input Parameter:
156 + da    - The DA
157 - stype - The stencil type, use either DA_STENCIL_BOX or DA_STENCIL_STAR.
158 
159   Level: intermediate
160 
161 .keywords:  distributed array, stencil
162 .seealso: DACreate(), DMDestroy(), DA
163 @*/
164 PetscErrorCode PETSCDM_DLLEXPORT DASetStencilType(DM da, DAStencilType 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__ "DASetStencilWidth"
177 /*@
178   DASetStencilWidth - Sets the width of the communication stencil
179 
180   Logically Collective on DA
181 
182   Input Parameter:
183 + da    - The DA
184 - width - The stencil width
185 
186   Level: intermediate
187 
188 .keywords:  distributed array, stencil
189 .seealso: DACreate(), DMDestroy(), DA
190 @*/
191 PetscErrorCode PETSCDM_DLLEXPORT DASetStencilWidth(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__ "DACheckOwnershipRanges_Private"
204 static PetscErrorCode DACheckOwnershipRanges_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__ "DASetOwnershipRanges"
217 /*@
218   DASetOwnershipRanges - Sets the number of nodes in each direction on each process
219 
220   Logically Collective on DA
221 
222   Input Parameter:
223 + da - The DA
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: DACreate(), DMDestroy(), DA
232 @*/
233 PetscErrorCode PETSCDM_DLLEXPORT DASetOwnershipRanges(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 = DACheckOwnershipRanges_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 = DACheckOwnershipRanges_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 = DACheckOwnershipRanges_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__ "DACreateOwnershipRanges"
269 /*
270  Ensure that da->lx, ly, and lz exist.  Collective on DA.
271 */
272 PetscErrorCode PETSCDM_DLLEXPORT DACreateOwnershipRanges(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 = DAGetProcessorSubset(da,DA_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 = DAGetProcessorSubset(da,DA_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 = DAGetProcessorSubset(da,DA_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__ "DASetInterpolationType"
305 /*@
306        DASetInterpolationType - Sets the type of interpolation that will be
307           returned by DAGetInterpolation()
308 
309    Logically Collective on DA
310 
311    Input Parameter:
312 +  da - initial distributed array
313 .  ctype - DA_Q1 and DA_Q0 are currently the only supported forms
314 
315    Level: intermediate
316 
317    Notes: you should call this on the coarser of the two DAs you pass to DAGetInterpolation()
318 
319 .keywords:  distributed array, interpolation
320 
321 .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DMDestroy(), DA, DAInterpolationType
322 @*/
323 PetscErrorCode PETSCDM_DLLEXPORT DASetInterpolationType(DM da,DAInterpolationType 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__ "DAGetNeighbors"
337 /*@C
338       DAGetNeighbors - 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 DA 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 DA 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 DAGetNeighbors(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       DASetElementType - Sets the element type to be returned by DMGetElements()
370 
371     Not Collective
372 
373    Input Parameter:
374 .     da - the DA object
375 
376    Output Parameters:
377 .     etype - the element type, currently either DA_ELEMENT_P1 or ELEMENT_Q1
378 
379    Level: intermediate
380 
381 .seealso: DAElementType, DAGetElementType(), DMGetElements(), DMRestoreElements()
382 @*/
383 #undef __FUNCT__
384 #define __FUNCT__ "DASetElementType"
385 PetscErrorCode PETSCDM_DLLEXPORT DASetElementType(DM da, DAElementType 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       DAGetElementType - Gets the element type to be returned by DMGetElements()
404 
405     Not Collective
406 
407    Input Parameter:
408 .     da - the DA object
409 
410    Output Parameters:
411 .     etype - the element type, currently either DA_ELEMENT_P1 or ELEMENT_Q1
412 
413    Level: intermediate
414 
415 .seealso: DAElementType, DASetElementType(), DMGetElements(), DMRestoreElements()
416 @*/
417 #undef __FUNCT__
418 #define __FUNCT__ "DAGetElementType"
419 PetscErrorCode PETSCDM_DLLEXPORT DAGetElementType(DM da, DAElementType *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__ "DAGetOwnershipRanges"
487 /*@C
488       DAGetOwnershipRanges - 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 DA 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 DACreate(), DACreate2d(), DACreate3d()
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 DAGetInfo()
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     DA they came from still exists (has not been destroyed).
509 
510 .seealso: DAGetCorners(), DAGetGhostCorners(), DACreate(), DACreate1d(), DACreate2d(), DACreate3d(), VecGetOwnershipRanges()
511 @*/
512 PetscErrorCode PETSCDM_DLLEXPORT DAGetOwnershipRanges(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__ "DASetRefinementFactor"
526 /*@
527      DASetRefinementFactor - Set the ratios that the DA grid is refined
528 
529     Logically Collective on DA
530 
531   Input Parameters:
532 +    da - the DA 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: DARefine(), DAGetRefinementFactor()
547 @*/
548 PetscErrorCode PETSCDM_DLLEXPORT DASetRefinementFactor(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__ "DAGetRefinementFactor"
566 /*@C
567      DAGetRefinementFactor - Gets the ratios that the DA grid is refined
568 
569     Not Collective
570 
571   Input Parameter:
572 .    da - the DA 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: DARefine(), DASetRefinementFactor()
584 @*/
585 PetscErrorCode PETSCDM_DLLEXPORT DAGetRefinementFactor(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__ "DASetGetMatrix"
599 /*@C
600      DASetGetMatrix - Sets the routine used by the DA to allocate a matrix.
601 
602     Logically Collective on DA
603 
604   Input Parameters:
605 +    da - the DA object
606 -    f - the function that allocates the matrix for that specific DA
607 
608   Level: developer
609 
610    Notes: See DASetBlockFills() that provides a simple way to provide the nonzero structure for
611        the diagonal and off-diagonal blocks of the matrix
612 
613 .seealso: DAGetMatrix(), DASetBlockFills()
614 @*/
615 PetscErrorCode PETSCDM_DLLEXPORT DASetGetMatrix(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__ "DARefineOwnershipRanges"
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 DARefineOwnershipRanges(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       PetscInt diffc = (startf+want)/ratio - (startc + lc[i]);
649       while (PetscAbs(diffc) > stencil_width) {
650         want += (diffc < 0);
651         diffc = (startf+want)/ratio - (startc + lc[i]);
652       }
653     }
654     lf[i] = want;
655     startc += lc[i];
656     startf += lf[i];
657     remaining -= lf[i];
658   }
659   PetscFunctionReturn(0);
660 }
661 
662 #undef __FUNCT__
663 #define __FUNCT__ "DARefine"
664 /*@
665    DARefine - Creates a new distributed array that is a refinement of a given
666    distributed array.
667 
668    Collective on DA
669 
670    Input Parameter:
671 +  da - initial distributed array
672 -  comm - communicator to contain refined DA, must be either same as the da communicator or include the
673           da communicator and be 2, 4, or 8 times larger. Currently ignored
674 
675    Output Parameter:
676 .  daref - refined distributed array
677 
678    Level: advanced
679 
680    Note:
681    Currently, refinement consists of just doubling the number of grid spaces
682    in each dimension of the DA.
683 
684 .keywords:  distributed array, refine
685 
686 .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DMDestroy(), DAGetOwnershipRanges()
687 @*/
688 PetscErrorCode PETSCDM_DLLEXPORT DARefine(DM da,MPI_Comm comm,DM *daref)
689 {
690   PetscErrorCode ierr;
691   PetscInt       M,N,P;
692   DM             da2;
693   DM_DA          *dd = (DM_DA*)da->data,*dd2;
694 
695   PetscFunctionBegin;
696   PetscValidHeaderSpecific(da,DM_CLASSID,1);
697   PetscValidPointer(daref,3);
698 
699   if (DAXPeriodic(dd->wrap) || dd->interptype == DA_Q0){
700     M = dd->refine_x*dd->M;
701   } else {
702     M = 1 + dd->refine_x*(dd->M - 1);
703   }
704   if (DAYPeriodic(dd->wrap) || dd->interptype == DA_Q0){
705     N = dd->refine_y*dd->N;
706   } else {
707     N = 1 + dd->refine_y*(dd->N - 1);
708   }
709   if (DAZPeriodic(dd->wrap) || dd->interptype == DA_Q0){
710     P = dd->refine_z*dd->P;
711   } else {
712     P = 1 + dd->refine_z*(dd->P - 1);
713   }
714   ierr = DACreateOwnershipRanges(da);CHKERRQ(ierr);
715   if (dd->dim == 3) {
716     PetscInt *lx,*ly,*lz;
717     ierr = PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);CHKERRQ(ierr);
718     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAXPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
719     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAYPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
720     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAZPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
721     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);
722     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
723   } else if (dd->dim == 2) {
724     PetscInt *lx,*ly;
725     ierr = PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);CHKERRQ(ierr);
726     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAXPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
727     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAYPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
728     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);
729     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
730   } else if (dd->dim == 1) {
731     PetscInt *lx;
732     ierr = PetscMalloc(dd->m*sizeof(PetscInt),&lx);CHKERRQ(ierr);
733     ierr = DARefineOwnershipRanges(da,(PetscBool)(DAXPeriodic(dd->wrap) || dd->interptype == DA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
734     ierr = DACreate1d(((PetscObject)da)->comm,dd->wrap,M,dd->w,dd->s,lx,&da2);CHKERRQ(ierr);
735     ierr = PetscFree(lx);CHKERRQ(ierr);
736   }
737   dd2 = (DM_DA*)da2->data;
738 
739   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
740   da2->ops->getmatrix        = da->ops->getmatrix;
741   da2->ops->getinterpolation = da->ops->getinterpolation;
742   da2->ops->getcoloring      = da->ops->getcoloring;
743   dd2->interptype            = dd->interptype;
744 
745   /* copy fill information if given */
746   if (dd->dfill) {
747     ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr);
748     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
749   }
750   if (dd->ofill) {
751     ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr);
752     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
753   }
754   /* copy the refine information */
755   dd2->refine_x = dd->refine_x;
756   dd2->refine_y = dd->refine_y;
757   dd2->refine_z = dd->refine_z;
758 
759   /* copy vector type information */
760   ierr = PetscFree(da2->vectype);CHKERRQ(ierr);
761   ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr);
762   *daref = da2;
763   PetscFunctionReturn(0);
764 }
765 
766 #undef __FUNCT__
767 #define __FUNCT__ "DACoarsen"
768 /*@
769    DACoarsen - Creates a new distributed array that is a coarsenment of a given
770    distributed array.
771 
772    Collective on DA
773 
774    Input Parameter:
775 +  da - initial distributed array
776 -  comm - communicator to contain coarsend DA. Currently ignored
777 
778    Output Parameter:
779 .  daref - coarsend distributed array
780 
781    Level: advanced
782 
783    Note:
784    Currently, coarsenment consists of just dividing the number of grid spaces
785    in each dimension of the DA by refinex_x, refinex_y, ....
786 
787 .keywords:  distributed array, coarsen
788 
789 .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DMDestroy(), DAGetOwnershipRanges()
790 @*/
791 PetscErrorCode PETSCDM_DLLEXPORT DACoarsen(DM da, MPI_Comm comm,DM *daref)
792 {
793   PetscErrorCode ierr;
794   PetscInt       M,N,P;
795   DM             da2;
796   DM_DA          *dd = (DM_DA*)da->data,*dd2;
797 
798   PetscFunctionBegin;
799   PetscValidHeaderSpecific(da,DM_CLASSID,1);
800   PetscValidPointer(daref,3);
801 
802   if (DAXPeriodic(dd->wrap) || dd->interptype == DA_Q0){
803     if(dd->refine_x)
804       M = dd->M / dd->refine_x;
805     else
806       M = dd->M;
807   } else {
808     if(dd->refine_x)
809       M = 1 + (dd->M - 1) / dd->refine_x;
810     else
811       M = dd->M;
812   }
813   if (DAYPeriodic(dd->wrap) || dd->interptype == DA_Q0){
814     if(dd->refine_y)
815       N = dd->N / dd->refine_y;
816     else
817       N = dd->N;
818   } else {
819     if(dd->refine_y)
820       N = 1 + (dd->N - 1) / dd->refine_y;
821     else
822       N = dd->M;
823   }
824   if (DAZPeriodic(dd->wrap) || dd->interptype == DA_Q0){
825     if(dd->refine_z)
826       P = dd->P / dd->refine_z;
827     else
828       P = dd->P;
829   } else {
830     if(dd->refine_z)
831       P = 1 + (dd->P - 1) / dd->refine_z;
832     else
833       P = dd->P;
834   }
835   if (dd->dim == 3) {
836     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);
837   } else if (dd->dim == 2) {
838     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);
839   } else if (dd->dim == 1) {
840     ierr = DACreate1d(((PetscObject)da)->comm,dd->wrap,M,dd->w,dd->s,0,&da2);CHKERRQ(ierr);
841   }
842   dd2 = (DM_DA*)da2->data;
843 
844   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
845   da2->ops->getmatrix        = da->ops->getmatrix;
846   da2->ops->getinterpolation = da->ops->getinterpolation;
847   da2->ops->getcoloring      = da->ops->getcoloring;
848   dd2->interptype            = dd->interptype;
849 
850   /* copy fill information if given */
851   if (dd->dfill) {
852     ierr = PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);CHKERRQ(ierr);
853     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
854   }
855   if (dd->ofill) {
856     ierr = PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);CHKERRQ(ierr);
857     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
858   }
859   /* copy the refine information */
860   dd2->refine_x = dd->refine_x;
861   dd2->refine_y = dd->refine_y;
862   dd2->refine_z = dd->refine_z;
863 
864   /* copy vector type information */
865   ierr = PetscFree(da2->vectype);CHKERRQ(ierr);
866   ierr = PetscStrallocpy(da->vectype,&da2->vectype);CHKERRQ(ierr);
867 
868   *daref = da2;
869   PetscFunctionReturn(0);
870 }
871 
872 #undef __FUNCT__
873 #define __FUNCT__ "DARefineHierarchy"
874 /*@
875    DARefineHierarchy - Perform multiple levels of refinement.
876 
877    Collective on DA
878 
879    Input Parameter:
880 +  da - initial distributed array
881 -  nlevels - number of levels of refinement to perform
882 
883    Output Parameter:
884 .  daf - array of refined DAs
885 
886    Options Database:
887 +  -da_refine_hierarchy_x - list of refinement ratios in x direction
888 .  -da_refine_hierarchy_y - list of refinement ratios in y direction
889 -  -da_refine_hierarchy_z - list of refinement ratios in z direction
890 
891    Level: advanced
892 
893 .keywords: distributed array, refine
894 
895 .seealso: DARefine(), DACoarsenHierarchy()
896 @*/
897 PetscErrorCode PETSCDM_DLLEXPORT DARefineHierarchy(DM da,PetscInt nlevels,DM daf[])
898 {
899   PetscErrorCode ierr;
900   PetscInt       i,n,*refx,*refy,*refz;
901 
902   PetscFunctionBegin;
903   PetscValidHeaderSpecific(da,DM_CLASSID,1);
904   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
905   if (nlevels == 0) PetscFunctionReturn(0);
906   PetscValidPointer(daf,3);
907 
908   /* Get refinement factors, defaults taken from the coarse DA */
909   ierr = PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);CHKERRQ(ierr);
910   for (i=0; i<nlevels; i++) {
911     ierr = DAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr);
912   }
913   n = nlevels;
914   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);CHKERRQ(ierr);
915   n = nlevels;
916   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);CHKERRQ(ierr);
917   n = nlevels;
918   ierr = PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);CHKERRQ(ierr);
919 
920   ierr = DASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr);
921   ierr = DARefine(da,((PetscObject)da)->comm,&daf[0]);CHKERRQ(ierr);
922   for (i=1; i<nlevels; i++) {
923     ierr = DASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr);
924     ierr = DARefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);CHKERRQ(ierr);
925   }
926   ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr);
927   PetscFunctionReturn(0);
928 }
929 
930 #undef __FUNCT__
931 #define __FUNCT__ "DACoarsenHierarchy"
932 /*@
933    DACoarsenHierarchy - Perform multiple levels of coarsening
934 
935    Collective on DA
936 
937    Input Parameter:
938 +  da - initial distributed array
939 -  nlevels - number of levels of coarsening to perform
940 
941    Output Parameter:
942 .  dac - array of coarsened DAs
943 
944    Level: advanced
945 
946 .keywords: distributed array, coarsen
947 
948 .seealso: DACoarsen(), DARefineHierarchy()
949 @*/
950 PetscErrorCode PETSCDM_DLLEXPORT DACoarsenHierarchy(DM da,PetscInt nlevels,DM dac[])
951 {
952   PetscErrorCode ierr;
953   PetscInt i;
954 
955   PetscFunctionBegin;
956   PetscValidHeaderSpecific(da,DM_CLASSID,1);
957   if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
958   if (nlevels == 0) PetscFunctionReturn(0);
959   PetscValidPointer(dac,3);
960   ierr = DACoarsen(da,((PetscObject)da)->comm,&dac[0]);CHKERRQ(ierr);
961   for (i=1; i<nlevels; i++) {
962     ierr = DACoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);CHKERRQ(ierr);
963   }
964   PetscFunctionReturn(0);
965 }
966