Actual source code: da2.c
1: #define PETSCDM_DLL
2:
3: #include src/dm/da/daimpl.h
7: /*@C
8: DAGetElements - Gets an array containing the indices (in local coordinates)
9: of all the local elements
11: Not Collective
13: Input Parameter:
14: . da - the DA object
16: Output Parameters:
17: + n - number of local elements
18: - e - the indices of the elements vertices
20: Level: intermediate
22: .seealso: DAElementType, DASetElementType(), DARestoreElements()
23: @*/
24: PetscErrorCode DAGetElements(DA da,PetscInt *n,const PetscInt *e[])
25: {
29: (da->ops->getelements)(da,n,e);
30: return(0);
31: }
35: /*@C
36: DARestoreElements - Returns an array containing the indices (in local coordinates)
37: of all the local elements obtained with DAGetElements()
39: Not Collective
41: Input Parameter:
42: + da - the DA object
43: . n - number of local elements
44: - e - the indices of the elements vertices
46: Level: intermediate
48: .seealso: DAElementType, DASetElementType(), DAGetElements()
49: @*/
50: PetscErrorCode DARestoreElements(DA da,PetscInt *n,const PetscInt *e[])
51: {
55: if (da->ops->restoreelements) {
56: (da->ops->restoreelements)(da,n,e);
57: }
58: return(0);
59: }
63: PetscErrorCode DAGetOwnershipRange(DA da,PetscInt **lx,PetscInt **ly,PetscInt **lz)
64: {
67: if (lx) *lx = da->lx;
68: if (ly) *ly = da->ly;
69: if (lz) *lz = da->lz;
70: return(0);
71: }
75: PetscErrorCode DAView_2d(DA da,PetscViewer viewer)
76: {
78: PetscMPIInt rank;
79: PetscTruth iascii,isdraw;
82: MPI_Comm_rank(da->comm,&rank);
84: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
85: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_DRAW,&isdraw);
86: if (iascii) {
87: PetscViewerASCIISynchronizedPrintf(viewer,"Processor [%d] M %D N %D m %D n %D w %D s %D\n",rank,da->M,
88: da->N,da->m,da->n,da->w,da->s);
89: PetscViewerASCIISynchronizedPrintf(viewer,"X range of indices: %D %D, Y range of indices: %D %D\n",da->xs,da->xe,da->ys,da->ye);
90: PetscViewerFlush(viewer);
91: } else if (isdraw) {
92: PetscDraw draw;
93: double ymin = -1*da->s-1,ymax = da->N+da->s;
94: double xmin = -1*da->s-1,xmax = da->M+da->s;
95: double x,y;
96: PetscInt base,*idx;
97: char node[10];
98: PetscTruth isnull;
99:
100: PetscViewerDrawGetDraw(viewer,0,&draw);
101: PetscDrawIsNull(draw,&isnull); if (isnull) return(0);
102: if (!da->coordinates) {
103: PetscDrawSetCoordinates(draw,xmin,ymin,xmax,ymax);
104: }
105: PetscDrawSynchronizedClear(draw);
107: /* first processor draw all node lines */
108: if (!rank) {
109: ymin = 0.0; ymax = da->N - 1;
110: for (xmin=0; xmin<da->M; xmin++) {
111: PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_BLACK);
112: }
113: xmin = 0.0; xmax = da->M - 1;
114: for (ymin=0; ymin<da->N; ymin++) {
115: PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_BLACK);
116: }
117: }
118: PetscDrawSynchronizedFlush(draw);
119: PetscDrawPause(draw);
121: /* draw my box */
122: ymin = da->ys; ymax = da->ye - 1; xmin = da->xs/da->w;
123: xmax =(da->xe-1)/da->w;
124: PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_RED);
125: PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_RED);
126: PetscDrawLine(draw,xmin,ymax,xmax,ymax,PETSC_DRAW_RED);
127: PetscDrawLine(draw,xmax,ymin,xmax,ymax,PETSC_DRAW_RED);
129: /* put in numbers */
130: base = (da->base)/da->w;
131: for (y=ymin; y<=ymax; y++) {
132: for (x=xmin; x<=xmax; x++) {
133: sprintf(node,"%d",(int)base++);
134: PetscDrawString(draw,x,y,PETSC_DRAW_BLACK,node);
135: }
136: }
138: PetscDrawSynchronizedFlush(draw);
139: PetscDrawPause(draw);
140: /* overlay ghost numbers, useful for error checking */
141: /* put in numbers */
143: base = 0; idx = da->idx;
144: ymin = da->Ys; ymax = da->Ye; xmin = da->Xs; xmax = da->Xe;
145: for (y=ymin; y<ymax; y++) {
146: for (x=xmin; x<xmax; x++) {
147: if ((base % da->w) == 0) {
148: sprintf(node,"%d",(int)(idx[base]/da->w));
149: PetscDrawString(draw,x/da->w,y,PETSC_DRAW_BLUE,node);
150: }
151: base++;
152: }
153: }
154: PetscDrawSynchronizedFlush(draw);
155: PetscDrawPause(draw);
156: } else {
157: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for DA2d",((PetscObject)viewer)->type_name);
158: }
159: return(0);
160: }
164: PetscErrorCode DAPublish_Petsc(PetscObject obj)
165: {
167: return(0);
168: }
172: PetscErrorCode DAGetElements_2d_P1(DA da,PetscInt *n,const PetscInt *e[])
173: {
175: PetscInt i,j,cnt,xs,xe = da->xe,ys,ye = da->ye,Xs = da->Xs, Xe = da->Xe, Ys = da->Ys;
178: if (!da->e) {
179: if (da->xs == Xs) xs = da->xs; else xs = da->xs - 1;
180: if (da->ys == Ys) ys = da->ys; else ys = da->ys - 1;
181: da->ne = 2*(xe - xs - 1)*(ye - ys - 1);
182: PetscMalloc((1 + 3*da->ne)*sizeof(PetscInt),&da->e);
183: cnt = 0;
184: for (j=ys; j<ye-1; j++) {
185: for (i=xs; i<xe-1; i++) {
186: da->e[cnt] = i - Xs + (j - Ys)*(Xe - Xs);
187: da->e[cnt+1] = i - Xs + 1 + (j - Ys)*(Xe - Xs);
188: da->e[cnt+2] = i - Xs + (j - Ys + 1)*(Xe - Xs);
190: da->e[cnt+3] = i - Xs + 1 + (j - Ys + 1)*(Xe - Xs);
191: da->e[cnt+4] = i - Xs + (j - Ys + 1)*(Xe - Xs);
192: da->e[cnt+5] = i - Xs + 1 + (j - Ys)*(Xe - Xs);
193: cnt += 6;
194: }
195: }
196: }
197: *n = da->ne;
198: *e = da->e;
199: return(0);
200: }
205: /*@C
206: DACreate2d - Creates an object that will manage the communication of two-dimensional
207: regular array data that is distributed across some processors.
209: Collective on MPI_Comm
211: Input Parameters:
212: + comm - MPI communicator
213: . wrap - type of periodicity should the array have.
214: Use one of DA_NONPERIODIC, DA_XPERIODIC, DA_YPERIODIC, or DA_XYPERIODIC.
215: . stencil_type - stencil type. Use either DA_STENCIL_BOX or DA_STENCIL_STAR.
216: . M,N - global dimension in each direction of the array (use -M and or -N to indicate that it may be set to a different value
217: from the command line with -da_grid_x <M> -da_grid_y <N>)
218: . m,n - corresponding number of processors in each dimension
219: (or PETSC_DECIDE to have calculated)
220: . dof - number of degrees of freedom per node
221: . s - stencil width
222: - lx, ly - arrays containing the number of nodes in each cell along
223: the x and y coordinates, or PETSC_NULL. If non-null, these
224: must be of length as m and n, and the corresponding
225: m and n cannot be PETSC_DECIDE. The sum of the lx[] entries
226: must be M, and the sum of the ly[] entries must be N.
228: Output Parameter:
229: . inra - the resulting distributed array object
231: Options Database Key:
232: + -da_view - Calls DAView() at the conclusion of DACreate2d()
233: . -da_grid_x <nx> - number of grid points in x direction, if M < 0
234: . -da_grid_y <ny> - number of grid points in y direction, if N < 0
235: . -da_processors_x <nx> - number of processors in x direction
236: . -da_processors_y <ny> - number of processors in y direction
237: . -da_refine_x - refinement ratio in x direction
238: - -da_refine_y - refinement ratio in y direction
240: Level: beginner
242: Notes:
243: The stencil type DA_STENCIL_STAR with width 1 corresponds to the
244: standard 5-pt stencil, while DA_STENCIL_BOX with width 1 denotes
245: the standard 9-pt stencil.
247: The array data itself is NOT stored in the DA, it is stored in Vec objects;
248: The appropriate vector objects can be obtained with calls to DACreateGlobalVector()
249: and DACreateLocalVector() and calls to VecDuplicate() if more are needed.
251: .keywords: distributed array, create, two-dimensional
253: .seealso: DADestroy(), DAView(), DACreate1d(), DACreate3d(), DAGlobalToLocalBegin(), DAGetRefinementFactor(),
254: DAGlobalToLocalEnd(), DALocalToGlobal(), DALocalToLocalBegin(), DALocalToLocalEnd(), DASetRefinementFactor(),
255: DAGetInfo(), DACreateGlobalVector(), DACreateLocalVector(), DACreateNaturalVector(), DALoad(), DAView()
257: @*/
258: PetscErrorCode DACreate2d(MPI_Comm comm,DAPeriodicType wrap,DAStencilType stencil_type,
259: PetscInt M,PetscInt N,PetscInt m,PetscInt n,PetscInt dof,PetscInt s,PetscInt *lx,PetscInt *ly,DA *inra)
260: {
262: PetscMPIInt rank,size;
263: PetscInt xs,xe,ys,ye,x,y,Xs,Xe,Ys,Ye,start,end;
264: PetscInt up,down,left,i,n0,n1,n2,n3,n5,n6,n7,n8,*idx,nn;
265: PetscInt xbase,*bases,*ldims,j,x_t,y_t,s_t,base,count;
266: PetscInt s_x,s_y; /* s proportionalized to w */
267: PetscInt *flx = 0,*fly = 0;
268: PetscInt sn0 = 0,sn2 = 0,sn6 = 0,sn8 = 0,refine_x = 2, refine_y = 2,tM = M,tN = N;
269: DA da;
270: Vec local,global;
271: VecScatter ltog,gtol;
272: IS to,from;
276: *inra = 0;
277: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
278: DMInitializePackage(PETSC_NULL);
279: #endif
281: if (dof < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Must have 1 or more degrees of freedom per node: %D",dof);
282: if (s < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Stencil width cannot be negative: %D",s);
284: PetscOptionsBegin(comm,PETSC_NULL,"2d DA Options","DA");
285: if (M < 0){
286: tM = -M;
287: PetscOptionsInt("-da_grid_x","Number of grid points in x direction","DACreate2d",tM,&tM,PETSC_NULL);
288: }
289: if (N < 0){
290: tN = -N;
291: PetscOptionsInt("-da_grid_y","Number of grid points in y direction","DACreate2d",tN,&tN,PETSC_NULL);
292: }
293: PetscOptionsInt("-da_processors_x","Number of processors in x direction","DACreate2d",m,&m,PETSC_NULL);
294: PetscOptionsInt("-da_processors_y","Number of processors in y direction","DACreate2d",n,&n,PETSC_NULL);
295: PetscOptionsInt("-da_refine_x","Refinement ratio in x direction","DASetRefinementFactor",refine_x,&refine_x,PETSC_NULL);
296: PetscOptionsInt("-da_refine_y","Refinement ratio in y direction","DASetRefinementFactor",refine_y,&refine_y,PETSC_NULL);
297: PetscOptionsEnd();
298: M = tM; N = tN;
300: PetscHeaderCreate(da,_p_DA,struct _DAOps,DA_COOKIE,0,"DA",comm,DADestroy,DAView);
301: da->bops->publish = DAPublish_Petsc;
302: da->ops->createglobalvector = DACreateGlobalVector;
303: da->ops->getinterpolation = DAGetInterpolation;
304: da->ops->getcoloring = DAGetColoring;
305: da->ops->getmatrix = DAGetMatrix;
306: da->ops->refine = DARefine;
307: da->ops->getinjection = DAGetInjection;
308: da->ops->getelements = DAGetElements_2d_P1;
309: da->elementtype = DA_ELEMENT_P1;
311: PetscLogObjectMemory(da,sizeof(struct _p_DA));
312: da->dim = 2;
313: da->interptype = DA_Q1;
314: da->refine_x = refine_x;
315: da->refine_y = refine_y;
316: PetscMalloc(dof*sizeof(char*),&da->fieldname);
317: PetscMemzero(da->fieldname,dof*sizeof(char*));
319: MPI_Comm_size(comm,&size);
320: MPI_Comm_rank(comm,&rank);
322: if (m != PETSC_DECIDE) {
323: if (m < 1) {SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in X direction: %D",m);}
324: else if (m > size) {SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in X direction: %D %d",m,size);}
325: }
326: if (n != PETSC_DECIDE) {
327: if (n < 1) {SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Y direction: %D",n);}
328: else if (n > size) {SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Y direction: %D %d",n,size);}
329: }
331: if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
332: /* try for squarish distribution */
333: /* This should use MPI_Dims_create instead */
334: m = (PetscInt)(0.5 + sqrt(((double)M)*((double)size)/((double)N)));
335: if (!m) m = 1;
336: while (m > 0) {
337: n = size/m;
338: if (m*n == size) break;
339: m--;
340: }
341: if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
342: if (m*n != size) SETERRQ(PETSC_ERR_PLIB,"Internally Created Bad Partition");
343: } else if (m*n != size) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Given Bad partition");
345: if (M < m) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Partition in x direction is too fine! %D %D",M,m);
346: if (N < n) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Partition in y direction is too fine! %D %D",N,n);
348: /*
349: We should create an MPI Cartesian topology here, with reorder
350: set to true. That would create a NEW communicator that we would
351: need to use for operations on this distributed array
352: */
354: /*
355: Determine locally owned region
356: xs is the first local node number, x is the number of local nodes
357: */
358: if (!lx) { /* user sets distribution */
359: PetscMalloc(m*sizeof(PetscInt),&lx);
360: flx = lx;
361: for (i=0; i<m; i++) {
362: lx[i] = M/m + ((M % m) > i);
363: }
364: }
365: x = lx[rank % m];
366: xs = 0;
367: for (i=0; i<(rank % m); i++) {
368: xs += lx[i];
369: }
370: #if defined(PETSC_USE_DEBUG)
371: left = xs;
372: for (i=(rank % m); i<m; i++) {
373: left += lx[i];
374: }
375: if (left != M) {
376: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Sum of lx across processors not equal to M: %D %D",left,M);
377: }
378: #endif
380: /*
381: Determine locally owned region
382: ys is the first local node number, y is the number of local nodes
383: */
384: if (!ly) { /* user sets distribution */
385: PetscMalloc(n*sizeof(PetscInt),&ly);
386: fly = ly;
387: for (i=0; i<n; i++) {
388: ly[i] = N/n + ((N % n) > i);
389: }
390: }
391: y = ly[rank/m];
392: ys = 0;
393: for (i=0; i<(rank/m); i++) {
394: ys += ly[i];
395: }
396: #if defined(PETSC_USE_DEBUG)
397: left = ys;
398: for (i=(rank/m); i<n; i++) {
399: left += ly[i];
400: }
401: if (left != N) {
402: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Sum of ly across processors not equal to N: %D %D",left,N);
403: }
404: #endif
406: xe = xs + x;
407: ye = ys + y;
409: /* determine ghost region */
410: /* Assume No Periodicity */
411: if (xs-s > 0) Xs = xs - s; else Xs = 0;
412: if (ys-s > 0) Ys = ys - s; else Ys = 0;
413: if (xe+s <= M) Xe = xe + s; else Xe = M;
414: if (ye+s <= N) Ye = ye + s; else Ye = N;
416: /* X Periodic */
417: if (DAXPeriodic(wrap)){
418: Xs = xs - s;
419: Xe = xe + s;
420: }
422: /* Y Periodic */
423: if (DAYPeriodic(wrap)){
424: Ys = ys - s;
425: Ye = ye + s;
426: }
428: /* Resize all X parameters to reflect w */
429: x *= dof;
430: xs *= dof;
431: xe *= dof;
432: Xs *= dof;
433: Xe *= dof;
434: s_x = s*dof;
435: s_y = s;
437: /* determine starting point of each processor */
438: nn = x*y;
439: PetscMalloc((2*size+1)*sizeof(PetscInt),&bases);
440: ldims = bases+size+1;
441: MPI_Allgather(&nn,1,MPIU_INT,ldims,1,MPIU_INT,comm);
442: bases[0] = 0;
443: for (i=1; i<=size; i++) {
444: bases[i] = ldims[i-1];
445: }
446: for (i=1; i<=size; i++) {
447: bases[i] += bases[i-1];
448: }
450: /* allocate the base parallel and sequential vectors */
451: da->Nlocal = x*y;
452: VecCreateMPIWithArray(comm,da->Nlocal,PETSC_DECIDE,0,&global);
453: VecSetBlockSize(global,dof);
454: da->nlocal = (Xe-Xs)*(Ye-Ys);
455: VecCreateSeqWithArray(PETSC_COMM_SELF,da->nlocal,0,&local);
456: VecSetBlockSize(local,dof);
459: /* generate appropriate vector scatters */
460: /* local to global inserts non-ghost point region into global */
461: VecGetOwnershipRange(global,&start,&end);
462: ISCreateStride(comm,x*y,start,1,&to);
464: left = xs - Xs; down = ys - Ys; up = down + y;
465: PetscMalloc(x*(up - down)*sizeof(PetscInt),&idx);
466: count = 0;
467: for (i=down; i<up; i++) {
468: for (j=0; j<x/dof; j++) {
469: idx[count++] = left + i*(Xe-Xs) + j*dof;
470: }
471: }
472: ISCreateBlock(comm,dof,count,idx,&from);
473: PetscFree(idx);
475: VecScatterCreate(local,from,global,to,<og);
476: PetscLogObjectParent(da,to);
477: PetscLogObjectParent(da,from);
478: PetscLogObjectParent(da,ltog);
479: ISDestroy(from);
480: ISDestroy(to);
482: /* global to local must include ghost points */
483: if (stencil_type == DA_STENCIL_BOX) {
484: ISCreateStride(comm,(Xe-Xs)*(Ye-Ys),0,1,&to);
485: } else {
486: /* must drop into cross shape region */
487: /* ---------|
488: | top |
489: |--- ---|
490: | middle |
491: | |
492: ---- ----
493: | bottom |
494: -----------
495: Xs xs xe Xe */
496: /* bottom */
497: left = xs - Xs; down = ys - Ys; up = down + y;
498: count = down*(xe-xs) + (up-down)*(Xe-Xs) + (Ye-Ys-up)*(xe-xs);
499: PetscMalloc(count*sizeof(PetscInt)/dof,&idx);
500: count = 0;
501: for (i=0; i<down; i++) {
502: for (j=0; j<xe-xs; j += dof) {
503: idx[count++] = left + i*(Xe-Xs) + j;
504: }
505: }
506: /* middle */
507: for (i=down; i<up; i++) {
508: for (j=0; j<Xe-Xs; j += dof) {
509: idx[count++] = i*(Xe-Xs) + j;
510: }
511: }
512: /* top */
513: for (i=up; i<Ye-Ys; i++) {
514: for (j=0; j<xe-xs; j += dof) {
515: idx[count++] = left + i*(Xe-Xs) + j;
516: }
517: }
518: ISCreateBlock(comm,dof,count,idx,&to);
519: PetscFree(idx);
520: }
523: /* determine who lies on each side of us stored in n6 n7 n8
524: n3 n5
525: n0 n1 n2
526: */
528: /* Assume the Non-Periodic Case */
529: n1 = rank - m;
530: if (rank % m) {
531: n0 = n1 - 1;
532: } else {
533: n0 = -1;
534: }
535: if ((rank+1) % m) {
536: n2 = n1 + 1;
537: n5 = rank + 1;
538: n8 = rank + m + 1; if (n8 >= m*n) n8 = -1;
539: } else {
540: n2 = -1; n5 = -1; n8 = -1;
541: }
542: if (rank % m) {
543: n3 = rank - 1;
544: n6 = n3 + m; if (n6 >= m*n) n6 = -1;
545: } else {
546: n3 = -1; n6 = -1;
547: }
548: n7 = rank + m; if (n7 >= m*n) n7 = -1;
551: /* Modify for Periodic Cases */
552: if (wrap == DA_YPERIODIC) { /* Handle Top and Bottom Sides */
553: if (n1 < 0) n1 = rank + m * (n-1);
554: if (n7 < 0) n7 = rank - m * (n-1);
555: if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
556: if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
557: if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
558: if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
559: } else if (wrap == DA_XPERIODIC) { /* Handle Left and Right Sides */
560: if (n3 < 0) n3 = rank + (m-1);
561: if (n5 < 0) n5 = rank - (m-1);
562: if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
563: if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
564: if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
565: if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
566: } else if (wrap == DA_XYPERIODIC) {
568: /* Handle all four corners */
569: if ((n6 < 0) && (n7 < 0) && (n3 < 0)) n6 = m-1;
570: if ((n8 < 0) && (n7 < 0) && (n5 < 0)) n8 = 0;
571: if ((n2 < 0) && (n5 < 0) && (n1 < 0)) n2 = size-m;
572: if ((n0 < 0) && (n3 < 0) && (n1 < 0)) n0 = size-1;
574: /* Handle Top and Bottom Sides */
575: if (n1 < 0) n1 = rank + m * (n-1);
576: if (n7 < 0) n7 = rank - m * (n-1);
577: if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
578: if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
579: if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
580: if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
582: /* Handle Left and Right Sides */
583: if (n3 < 0) n3 = rank + (m-1);
584: if (n5 < 0) n5 = rank - (m-1);
585: if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
586: if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
587: if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
588: if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
589: }
591: if (stencil_type == DA_STENCIL_STAR) {
592: /* save corner processor numbers */
593: sn0 = n0; sn2 = n2; sn6 = n6; sn8 = n8;
594: n0 = n2 = n6 = n8 = -1;
595: }
597: PetscMalloc((x+2*s_x)*(y+2*s_y)*sizeof(PetscInt),&idx);
598: PetscLogObjectMemory(da,(x+2*s_x)*(y+2*s_y)*sizeof(PetscInt));
599: nn = 0;
601: xbase = bases[rank];
602: for (i=1; i<=s_y; i++) {
603: if (n0 >= 0) { /* left below */
604: x_t = lx[n0 % m]*dof;
605: y_t = ly[(n0/m)];
606: s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
607: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
608: }
609: if (n1 >= 0) { /* directly below */
610: x_t = x;
611: y_t = ly[(n1/m)];
612: s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
613: for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
614: }
615: if (n2 >= 0) { /* right below */
616: x_t = lx[n2 % m]*dof;
617: y_t = ly[(n2/m)];
618: s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
619: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
620: }
621: }
623: for (i=0; i<y; i++) {
624: if (n3 >= 0) { /* directly left */
625: x_t = lx[n3 % m]*dof;
626: /* y_t = y; */
627: s_t = bases[n3] + (i+1)*x_t - s_x;
628: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
629: }
631: for (j=0; j<x; j++) { idx[nn++] = xbase++; } /* interior */
633: if (n5 >= 0) { /* directly right */
634: x_t = lx[n5 % m]*dof;
635: /* y_t = y; */
636: s_t = bases[n5] + (i)*x_t;
637: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
638: }
639: }
641: for (i=1; i<=s_y; i++) {
642: if (n6 >= 0) { /* left above */
643: x_t = lx[n6 % m]*dof;
644: /* y_t = ly[(n6/m)]; */
645: s_t = bases[n6] + (i)*x_t - s_x;
646: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
647: }
648: if (n7 >= 0) { /* directly above */
649: x_t = x;
650: /* y_t = ly[(n7/m)]; */
651: s_t = bases[n7] + (i-1)*x_t;
652: for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
653: }
654: if (n8 >= 0) { /* right above */
655: x_t = lx[n8 % m]*dof;
656: /* y_t = ly[(n8/m)]; */
657: s_t = bases[n8] + (i-1)*x_t;
658: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
659: }
660: }
662: base = bases[rank];
663: {
664: PetscInt nnn = nn/dof,*iidx;
665: PetscMalloc(nnn*sizeof(PetscInt),&iidx);
666: for (i=0; i<nnn; i++) {
667: iidx[i] = idx[dof*i];
668: }
669: ISCreateBlock(comm,dof,nnn,iidx,&from);
670: PetscFree(iidx);
671: }
672: VecScatterCreate(global,from,local,to,>ol);
673: PetscLogObjectParent(da,to);
674: PetscLogObjectParent(da,from);
675: PetscLogObjectParent(da,gtol);
676: ISDestroy(to);
677: ISDestroy(from);
679: if (stencil_type == DA_STENCIL_STAR) {
680: /*
681: Recompute the local to global mappings, this time keeping the
682: information about the cross corner processor numbers.
683: */
684: n0 = sn0; n2 = sn2; n6 = sn6; n8 = sn8;
685: nn = 0;
686: xbase = bases[rank];
687: for (i=1; i<=s_y; i++) {
688: if (n0 >= 0) { /* left below */
689: x_t = lx[n0 % m]*dof;
690: y_t = ly[(n0/m)];
691: s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
692: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
693: }
694: if (n1 >= 0) { /* directly below */
695: x_t = x;
696: y_t = ly[(n1/m)];
697: s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
698: for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
699: }
700: if (n2 >= 0) { /* right below */
701: x_t = lx[n2 % m]*dof;
702: y_t = ly[(n2/m)];
703: s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
704: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
705: }
706: }
708: for (i=0; i<y; i++) {
709: if (n3 >= 0) { /* directly left */
710: x_t = lx[n3 % m]*dof;
711: /* y_t = y; */
712: s_t = bases[n3] + (i+1)*x_t - s_x;
713: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
714: }
716: for (j=0; j<x; j++) { idx[nn++] = xbase++; } /* interior */
718: if (n5 >= 0) { /* directly right */
719: x_t = lx[n5 % m]*dof;
720: /* y_t = y; */
721: s_t = bases[n5] + (i)*x_t;
722: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
723: }
724: }
726: for (i=1; i<=s_y; i++) {
727: if (n6 >= 0) { /* left above */
728: x_t = lx[n6 % m]*dof;
729: /* y_t = ly[(n6/m)]; */
730: s_t = bases[n6] + (i)*x_t - s_x;
731: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
732: }
733: if (n7 >= 0) { /* directly above */
734: x_t = x;
735: /* y_t = ly[(n7/m)]; */
736: s_t = bases[n7] + (i-1)*x_t;
737: for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
738: }
739: if (n8 >= 0) { /* right above */
740: x_t = lx[n8 % m]*dof;
741: /* y_t = ly[(n8/m)]; */
742: s_t = bases[n8] + (i-1)*x_t;
743: for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
744: }
745: }
746: }
747: PetscFree(bases);
749: da->M = M; da->N = N; da->m = m; da->n = n; da->w = dof; da->s = s;
750: da->xs = xs; da->xe = xe; da->ys = ys; da->ye = ye; da->zs = 0; da->ze = 1;
751: da->Xs = Xs; da->Xe = Xe; da->Ys = Ys; da->Ye = Ye; da->Zs = 0; da->Ze = 1;
752: da->P = 1; da->p = 1;
754: VecDestroy(local);
755: VecDestroy(global);
757: da->gtol = gtol;
758: da->ltog = ltog;
759: da->idx = idx;
760: da->Nl = nn;
761: da->base = base;
762: da->wrap = wrap;
763: da->ops->view = DAView_2d;
764: da->stencil_type = stencil_type;
766: /*
767: Set the local to global ordering in the global vector, this allows use
768: of VecSetValuesLocal().
769: */
770: ISLocalToGlobalMappingCreateNC(comm,nn,idx,&da->ltogmap);
771: ISLocalToGlobalMappingBlock(da->ltogmap,da->w,&da->ltogmapb);
772: PetscLogObjectParent(da,da->ltogmap);
774: *inra = da;
776: da->ltol = PETSC_NULL;
777: da->ao = PETSC_NULL;
780: if (!flx) {
781: PetscMalloc(m*sizeof(PetscInt),&flx);
782: PetscMemcpy(flx,lx,m*sizeof(PetscInt));
783: }
784: if (!fly) {
785: PetscMalloc(n*sizeof(PetscInt),&fly);
786: PetscMemcpy(fly,ly,n*sizeof(PetscInt));
787: }
788: da->lx = flx;
789: da->ly = fly;
790: DAView_Private(da);
791: PetscPublishAll(da);
792: return(0);
793: }
797: /*@
798: DARefine - Creates a new distributed array that is a refinement of a given
799: distributed array.
801: Collective on DA
803: Input Parameter:
804: + da - initial distributed array
805: - comm - communicator to contain refined DA, must be either same as the da communicator or include the
806: da communicator and be 2, 4, or 8 times larger. Currently ignored
808: Output Parameter:
809: . daref - refined distributed array
811: Level: advanced
813: Note:
814: Currently, refinement consists of just doubling the number of grid spaces
815: in each dimension of the DA.
817: .keywords: distributed array, refine
819: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy()
820: @*/
821: PetscErrorCode DARefine(DA da,MPI_Comm comm,DA *daref)
822: {
824: PetscInt M,N,P;
825: DA da2;
831: if (DAXPeriodic(da->wrap) || da->interptype == DA_Q0){
832: M = da->refine_x*da->M;
833: } else {
834: M = 1 + da->refine_x*(da->M - 1);
835: }
836: if (DAYPeriodic(da->wrap) || da->interptype == DA_Q0){
837: N = da->refine_y*da->N;
838: } else {
839: N = 1 + da->refine_y*(da->N - 1);
840: }
841: if (DAZPeriodic(da->wrap) || da->interptype == DA_Q0){
842: P = da->refine_z*da->P;
843: } else {
844: P = 1 + da->refine_z*(da->P - 1);
845: }
846: DACreate(da->comm,da->dim,da->wrap,da->stencil_type,M,N,P,da->m,da->n,da->p,da->w,da->s,0,0,0,&da2);
848: /* allow overloaded (user replaced) operations to be inherited by refinement clones */
849: da2->ops->getmatrix = da->ops->getmatrix;
850: da2->ops->getinterpolation = da->ops->getinterpolation;
851: da2->ops->getcoloring = da->ops->getcoloring;
852: da2->interptype = da->interptype;
853:
854: /* copy fill information if given */
855: if (da->dfill) {
856: PetscMalloc((da->dfill[da->w]+da->w+1)*sizeof(PetscInt),&da2->dfill);
857: PetscMemcpy(da2->dfill,da->dfill,(da->dfill[da->w]+da->w+1)*sizeof(PetscInt));
858: }
859: if (da->ofill) {
860: PetscMalloc((da->ofill[da->w]+da->w+1)*sizeof(PetscInt),&da2->ofill);
861: PetscMemcpy(da2->ofill,da->ofill,(da->ofill[da->w]+da->w+1)*sizeof(PetscInt));
862: }
863: /* copy the refine information */
864: da2->refine_x = da->refine_x;
865: da2->refine_y = da->refine_y;
866: da2->refine_z = da->refine_z;
867: *daref = da2;
868: return(0);
869: }
871: /*@C
872: DASetRefinementFactor - Set the ratios that the DA grid is refined
874: Collective on DA
876: Input Parameters:
877: + da - the DA object
878: . refine_x - ratio of fine grid to coarse in x direction (2 by default)
879: . refine_y - ratio of fine grid to coarse in y direction (2 by default)
880: - refine_z - ratio of fine grid to coarse in z direction (2 by default)
882: Options Database:
883: + -da_refine_x - refinement ratio in x direction
884: . -da_refine_y - refinement ratio in y direction
885: - -da_refine_y - refinement ratio in z direction
887: Level: intermediate
889: Notes: Pass PETSC_IGNORE to leave a value unchanged
891: .seealso: DARefine(), DAGetRefinementFactor()
892: @*/
893: PetscErrorCode DASetRefinementFactor(DA da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
894: {
896: if (refine_x > 0) da->refine_x = refine_x;
897: if (refine_y > 0) da->refine_y = refine_y;
898: if (refine_z > 0) da->refine_z = refine_z;
899: return(0);
900: }
902: /*@C
903: DAGetRefinementFactor - Gets the ratios that the DA grid is refined
905: Not Collective
907: Input Parameter:
908: . da - the DA object
910: Output Parameters:
911: + refine_x - ratio of fine grid to coarse in x direction (2 by default)
912: . refine_y - ratio of fine grid to coarse in y direction (2 by default)
913: - refine_z - ratio of fine grid to coarse in z direction (2 by default)
915: Level: intermediate
917: Notes: Pass PETSC_NULL for values you do not need
919: .seealso: DARefine(), DASetRefinementFactor()
920: @*/
921: PetscErrorCode DAGetRefinementFactor(DA da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
922: {
924: if (refine_x) *refine_x = da->refine_x;
925: if (refine_y) *refine_y = da->refine_y;
926: if (refine_z) *refine_z = da->refine_z;
927: return(0);
928: }
930: /*@C
931: DASetGetMatrix - Sets the routine used by the DA to allocate a matrix.
933: Collective on DA
935: Input Parameters:
936: + da - the DA object
937: - f - the function that allocates the matrix for that specific DA
939: Level: developer
941: Notes: See DASetBlockFills() that provides a simple way to provide the nonzero structure for
942: the diagonal and off-diagonal blocks of the matrix
944: .seealso: DAGetMatrix(), DASetBlockFills()
945: @*/
946: PetscErrorCode DASetGetMatrix(DA da,PetscErrorCode (*f)(DA, MatType,Mat*))
947: {
949: da->ops->getmatrix = f;
950: return(0);
951: }
953: /*
954: M is number of grid points
955: m is number of processors
957: */
960: PetscErrorCode DASplitComm2d(MPI_Comm comm,PetscInt M,PetscInt N,PetscInt sw,MPI_Comm *outcomm)
961: {
963: PetscInt m,n = 0,x = 0,y = 0;
964: PetscMPIInt size,csize,rank;
967: MPI_Comm_size(comm,&size);
968: MPI_Comm_rank(comm,&rank);
970: csize = 4*size;
971: do {
972: if (csize % 4) SETERRQ4(PETSC_ERR_ARG_INCOMP,"Cannot split communicator of size %d tried %d %D %D",size,csize,x,y);
973: csize = csize/4;
974:
975: m = (PetscInt)(0.5 + sqrt(((double)M)*((double)csize)/((double)N)));
976: if (!m) m = 1;
977: while (m > 0) {
978: n = csize/m;
979: if (m*n == csize) break;
980: m--;
981: }
982: if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
984: x = M/m + ((M % m) > ((csize-1) % m));
985: y = (N + (csize-1)/m)/n;
986: } while ((x < 4 || y < 4) && csize > 1);
987: if (size != csize) {
988: MPI_Group entire_group,sub_group;
989: PetscMPIInt i,*groupies;
991: MPI_Comm_group(comm,&entire_group);
992: PetscMalloc(csize*sizeof(PetscInt),&groupies);
993: for (i=0; i<csize; i++) {
994: groupies[i] = (rank/csize)*csize + i;
995: }
996: MPI_Group_incl(entire_group,csize,groupies,&sub_group);
997: PetscFree(groupies);
998: MPI_Comm_create(comm,sub_group,outcomm);
999: MPI_Group_free(&entire_group);
1000: MPI_Group_free(&sub_group);
1001: PetscInfo1(0,"DASplitComm2d:Creating redundant coarse problems of size %d\n",csize);
1002: } else {
1003: *outcomm = comm;
1004: }
1005: return(0);
1006: }
1010: /*@C
1011: DASetLocalFunction - Caches in a DA a local function.
1013: Collective on DA
1015: Input Parameter:
1016: + da - initial distributed array
1017: - lf - the local function
1019: Level: intermediate
1021: Notes: The routine SNESDAFormFunction() uses this the cached function to evaluate the user provided function.
1023: .keywords: distributed array, refine
1025: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunctioni()
1026: @*/
1027: PetscErrorCode DASetLocalFunction(DA da,DALocalFunction1 lf)
1028: {
1031: da->lf = lf;
1032: return(0);
1033: }
1037: /*@C
1038: DASetLocalFunctioni - Caches in a DA a local function that evaluates a single component
1040: Collective on DA
1042: Input Parameter:
1043: + da - initial distributed array
1044: - lfi - the local function
1046: Level: intermediate
1048: .keywords: distributed array, refine
1050: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction()
1051: @*/
1052: PetscErrorCode DASetLocalFunctioni(DA da,PetscErrorCode (*lfi)(DALocalInfo*,MatStencil*,void*,PetscScalar*,void*))
1053: {
1056: da->lfi = lfi;
1057: return(0);
1058: }
1062: /*@C
1063: DASetLocalFunctionib - Caches in a DA a block local function that evaluates a single component
1065: Collective on DA
1067: Input Parameter:
1068: + da - initial distributed array
1069: - lfi - the local function
1071: Level: intermediate
1073: .keywords: distributed array, refine
1075: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction()
1076: @*/
1077: PetscErrorCode DASetLocalFunctionib(DA da,PetscErrorCode (*lfi)(DALocalInfo*,MatStencil*,void*,PetscScalar*,void*))
1078: {
1081: da->lfib = lfi;
1082: return(0);
1083: }
1087: PetscErrorCode DASetLocalAdicFunction_Private(DA da,DALocalFunction1 ad_lf)
1088: {
1091: da->adic_lf = ad_lf;
1092: return(0);
1093: }
1095: /*MC
1096: DASetLocalAdicFunctioni - Caches in a DA a local functioni computed by ADIC/ADIFOR
1098: Collective on DA
1100: Synopsis:
1101: PetscErrorCode DASetLocalAdicFunctioni(DA da,PetscInt (ad_lf*)(DALocalInfo*,MatStencil*,void*,void*,void*)
1102:
1103: Input Parameter:
1104: + da - initial distributed array
1105: - ad_lfi - the local function as computed by ADIC/ADIFOR
1107: Level: intermediate
1109: .keywords: distributed array, refine
1111: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction(),
1112: DASetLocalJacobian(), DASetLocalFunctioni()
1113: M*/
1117: PetscErrorCode DASetLocalAdicFunctioni_Private(DA da,PetscErrorCode (*ad_lfi)(DALocalInfo*,MatStencil*,void*,void*,void*))
1118: {
1121: da->adic_lfi = ad_lfi;
1122: return(0);
1123: }
1125: /*MC
1126: DASetLocalAdicMFFunctioni - Caches in a DA a local functioni computed by ADIC/ADIFOR
1128: Collective on DA
1130: Synopsis:
1131: PetscErrorCode DASetLocalAdicFunctioni(DA da,int (ad_lf*)(DALocalInfo*,MatStencil*,void*,void*,void*)
1132:
1133: Input Parameter:
1134: + da - initial distributed array
1135: - admf_lfi - the local matrix-free function as computed by ADIC/ADIFOR
1137: Level: intermediate
1139: .keywords: distributed array, refine
1141: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction(),
1142: DASetLocalJacobian(), DASetLocalFunctioni()
1143: M*/
1147: PetscErrorCode DASetLocalAdicMFFunctioni_Private(DA da,PetscErrorCode (*admf_lfi)(DALocalInfo*,MatStencil*,void*,void*,void*))
1148: {
1151: da->adicmf_lfi = admf_lfi;
1152: return(0);
1153: }
1155: /*MC
1156: DASetLocalAdicFunctionib - Caches in a DA a block local functioni computed by ADIC/ADIFOR
1158: Collective on DA
1160: Synopsis:
1161: PetscErrorCode DASetLocalAdicFunctionib(DA da,PetscInt (ad_lf*)(DALocalInfo*,MatStencil*,void*,void*,void*)
1162:
1163: Input Parameter:
1164: + da - initial distributed array
1165: - ad_lfi - the local function as computed by ADIC/ADIFOR
1167: Level: intermediate
1169: .keywords: distributed array, refine
1171: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction(),
1172: DASetLocalJacobian(), DASetLocalFunctionib()
1173: M*/
1177: PetscErrorCode DASetLocalAdicFunctionib_Private(DA da,PetscErrorCode (*ad_lfi)(DALocalInfo*,MatStencil*,void*,void*,void*))
1178: {
1181: da->adic_lfib = ad_lfi;
1182: return(0);
1183: }
1185: /*MC
1186: DASetLocalAdicMFFunctionib - Caches in a DA a block local functioni computed by ADIC/ADIFOR
1188: Collective on DA
1190: Synopsis:
1191: PetscErrorCode DASetLocalAdicFunctionib(DA da,int (ad_lf*)(DALocalInfo*,MatStencil*,void*,void*,void*)
1192:
1193: Input Parameter:
1194: + da - initial distributed array
1195: - admf_lfi - the local matrix-free function as computed by ADIC/ADIFOR
1197: Level: intermediate
1199: .keywords: distributed array, refine
1201: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction(),
1202: DASetLocalJacobian(), DASetLocalFunctionib()
1203: M*/
1207: PetscErrorCode DASetLocalAdicMFFunctionib_Private(DA da,PetscErrorCode (*admf_lfi)(DALocalInfo*,MatStencil*,void*,void*,void*))
1208: {
1211: da->adicmf_lfib = admf_lfi;
1212: return(0);
1213: }
1215: /*MC
1216: DASetLocalAdicMFFunction - Caches in a DA a local function computed by ADIC/ADIFOR
1218: Collective on DA
1220: Synopsis:
1221: PetscErrorCode DASetLocalAdicMFFunction(DA da,DALocalFunction1 ad_lf)
1222:
1223: Input Parameter:
1224: + da - initial distributed array
1225: - ad_lf - the local function as computed by ADIC/ADIFOR
1227: Level: intermediate
1229: .keywords: distributed array, refine
1231: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction(),
1232: DASetLocalJacobian()
1233: M*/
1237: PetscErrorCode DASetLocalAdicMFFunction_Private(DA da,DALocalFunction1 ad_lf)
1238: {
1241: da->adicmf_lf = ad_lf;
1242: return(0);
1243: }
1245: /*@C
1246: DASetLocalJacobian - Caches in a DA a local Jacobian
1248: Collective on DA
1250:
1251: Input Parameter:
1252: + da - initial distributed array
1253: - lj - the local Jacobian
1255: Level: intermediate
1257: Notes: The routine SNESDAFormFunction() uses this the cached function to evaluate the user provided function.
1259: .keywords: distributed array, refine
1261: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DAGetLocalFunction(), DASetLocalFunction()
1262: @*/
1265: PetscErrorCode DASetLocalJacobian(DA da,DALocalFunction1 lj)
1266: {
1269: da->lj = lj;
1270: return(0);
1271: }
1275: /*@C
1276: DAGetLocalFunction - Gets from a DA a local function and its ADIC/ADIFOR Jacobian
1278: Collective on DA
1280: Input Parameter:
1281: . da - initial distributed array
1283: Output Parameters:
1284: . lf - the local function
1286: Level: intermediate
1288: .keywords: distributed array, refine
1290: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DASetLocalFunction()
1291: @*/
1292: PetscErrorCode DAGetLocalFunction(DA da,DALocalFunction1 *lf)
1293: {
1296: if (lf) *lf = da->lf;
1297: return(0);
1298: }
1302: /*@
1303: DAFormFunction - Evaluates a user provided function on each processor that
1304: share a DA
1306: Input Parameters:
1307: + da - the DA that defines the grid
1308: . vu - input vector
1309: . vfu - output vector
1310: - w - any user data
1312: Notes: Does NOT do ghost updates on vu upon entry
1314: This should eventually replace DAFormFunction1
1316: Level: advanced
1318: .seealso: DAComputeJacobian1WithAdic()
1320: @*/
1321: PetscErrorCode DAFormFunction(DA da,PetscErrorCode (*lf)(void),Vec vu,Vec vfu,void *w)
1322: {
1324: void *u,*fu;
1325: DALocalInfo info;
1326: PetscErrorCode (*f)(DALocalInfo*,void*,void*,void*) = (PetscErrorCode (*)(DALocalInfo*,void*,void*,void*))lf;
1327:
1329: DAGetLocalInfo(da,&info);
1330: DAVecGetArray(da,vu,&u);
1331: DAVecGetArray(da,vfu,&fu);
1333: (*f)(&info,u,fu,w);
1334: if (PetscExceptionValue(ierr)) {
1335: PetscErrorCode pDAVecRestoreArray(da,vu,&u);CHKERRQ(pierr);
1336: pDAVecRestoreArray(da,vfu,&fu);CHKERRQ(pierr);
1337: }
1338:
1340: DAVecRestoreArray(da,vu,&u);
1341: DAVecRestoreArray(da,vfu,&fu);
1342: return(0);
1343: }
1347: /*@C
1348: DAFormFunctionLocal - This is a universal function evaluation routine for
1349: a local DA function.
1351: Collective on DA
1353: Input Parameters:
1354: + da - the DA context
1355: . func - The local function
1356: . X - input vector
1357: . F - function vector
1358: - ctx - A user context
1360: Level: intermediate
1362: .seealso: DASetLocalFunction(), DASetLocalJacobian(), DASetLocalAdicFunction(), DASetLocalAdicMFFunction(),
1363: SNESSetFunction(), SNESSetJacobian()
1365: @*/
1366: PetscErrorCode DAFormFunctionLocal(DA da, DALocalFunction1 func, Vec X, Vec F, void *ctx)
1367: {
1368: Vec localX;
1369: DALocalInfo info;
1370: void *u;
1371: void *fu;
1375: DAGetLocalVector(da,&localX);
1376: /*
1377: Scatter ghost points to local vector, using the 2-step process
1378: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
1379: */
1380: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
1381: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
1382: DAGetLocalInfo(da,&info);
1383: DAVecGetArray(da,localX,&u);
1384: DAVecGetArray(da,F,&fu);
1385: (*func)(&info,u,fu,ctx);
1386: if (PetscExceptionValue(ierr)) {
1387: PetscErrorCode pDAVecRestoreArray(da,localX,&u);CHKERRQ(pierr);
1388: pDAVecRestoreArray(da,F,&fu);CHKERRQ(pierr);
1389: }
1390:
1391: DAVecRestoreArray(da,localX,&u);
1392: DAVecRestoreArray(da,F,&fu);
1393: if (PetscExceptionValue(ierr)) {
1394: PetscErrorCode pDARestoreLocalVector(da,&localX);CHKERRQ(pierr);
1395: }
1396:
1397: DARestoreLocalVector(da,&localX);
1398: return(0);
1399: }
1403: /*@
1404: DAFormFunction1 - Evaluates a user provided function on each processor that
1405: share a DA
1407: Input Parameters:
1408: + da - the DA that defines the grid
1409: . vu - input vector
1410: . vfu - output vector
1411: - w - any user data
1413: Notes: Does NOT do ghost updates on vu upon entry
1415: Level: advanced
1417: .seealso: DAComputeJacobian1WithAdic()
1419: @*/
1420: PetscErrorCode DAFormFunction1(DA da,Vec vu,Vec vfu,void *w)
1421: {
1423: void *u,*fu;
1424: DALocalInfo info;
1425:
1428: DAGetLocalInfo(da,&info);
1429: DAVecGetArray(da,vu,&u);
1430: DAVecGetArray(da,vfu,&fu);
1432: CHKMEMQ;
1433: (*da->lf)(&info,u,fu,w);
1434: if (PetscExceptionValue(ierr)) {
1435: PetscErrorCode pDAVecRestoreArray(da,vu,&u);CHKERRQ(pierr);
1436: pDAVecRestoreArray(da,vfu,&fu);CHKERRQ(pierr);
1437: }
1438:
1439: CHKMEMQ;
1441: DAVecRestoreArray(da,vu,&u);
1442: DAVecRestoreArray(da,vfu,&fu);
1443: return(0);
1444: }
1448: PetscErrorCode DAFormFunctioniTest1(DA da,void *w)
1449: {
1450: Vec vu,fu,fui;
1452: PetscInt i,n;
1453: PetscScalar *ui;
1454: PetscRandom rnd;
1455: PetscReal norm;
1458: DAGetLocalVector(da,&vu);
1459: PetscRandomCreate(PETSC_COMM_SELF,&rnd);
1460: PetscRandomSetFromOptions(rnd);
1461: VecSetRandom(vu,rnd);
1462: PetscRandomDestroy(rnd);
1464: DAGetGlobalVector(da,&fu);
1465: DAGetGlobalVector(da,&fui);
1466:
1467: DAFormFunction1(da,vu,fu,w);
1469: VecGetArray(fui,&ui);
1470: VecGetLocalSize(fui,&n);
1471: for (i=0; i<n; i++) {
1472: DAFormFunctioni1(da,i,vu,ui+i,w);
1473: }
1474: VecRestoreArray(fui,&ui);
1476: VecAXPY(fui,-1.0,fu);
1477: VecNorm(fui,NORM_2,&norm);
1478: PetscPrintf(da->comm,"Norm of difference in vectors %G\n",norm);
1479: VecView(fu,0);
1480: VecView(fui,0);
1482: DARestoreLocalVector(da,&vu);
1483: DARestoreGlobalVector(da,&fu);
1484: DARestoreGlobalVector(da,&fui);
1485: return(0);
1486: }
1490: /*@
1491: DAFormFunctioni1 - Evaluates a user provided point-wise function
1493: Input Parameters:
1494: + da - the DA that defines the grid
1495: . i - the component of the function we wish to compute (must be local)
1496: . vu - input vector
1497: . vfu - output value
1498: - w - any user data
1500: Notes: Does NOT do ghost updates on vu upon entry
1502: Level: advanced
1504: .seealso: DAComputeJacobian1WithAdic()
1506: @*/
1507: PetscErrorCode DAFormFunctioni1(DA da,PetscInt i,Vec vu,PetscScalar *vfu,void *w)
1508: {
1510: void *u;
1511: DALocalInfo info;
1512: MatStencil stencil;
1513:
1516: DAGetLocalInfo(da,&info);
1517: DAVecGetArray(da,vu,&u);
1519: /* figure out stencil value from i */
1520: stencil.c = i % info.dof;
1521: stencil.i = (i % (info.xm*info.dof))/info.dof;
1522: stencil.j = (i % (info.xm*info.ym*info.dof))/(info.xm*info.dof);
1523: stencil.k = i/(info.xm*info.ym*info.dof);
1525: (*da->lfi)(&info,&stencil,u,vfu,w);
1527: DAVecRestoreArray(da,vu,&u);
1528: return(0);
1529: }
1533: /*@
1534: DAFormFunctionib1 - Evaluates a user provided point-block function
1536: Input Parameters:
1537: + da - the DA that defines the grid
1538: . i - the component of the function we wish to compute (must be local)
1539: . vu - input vector
1540: . vfu - output value
1541: - w - any user data
1543: Notes: Does NOT do ghost updates on vu upon entry
1545: Level: advanced
1547: .seealso: DAComputeJacobian1WithAdic()
1549: @*/
1550: PetscErrorCode DAFormFunctionib1(DA da,PetscInt i,Vec vu,PetscScalar *vfu,void *w)
1551: {
1553: void *u;
1554: DALocalInfo info;
1555: MatStencil stencil;
1556:
1558: DAGetLocalInfo(da,&info);
1559: DAVecGetArray(da,vu,&u);
1561: /* figure out stencil value from i */
1562: stencil.c = i % info.dof;
1563: if (stencil.c) SETERRQ(PETSC_ERR_ARG_WRONG,"Point-block functions can only be called for the entire block");
1564: stencil.i = (i % (info.xm*info.dof))/info.dof;
1565: stencil.j = (i % (info.xm*info.ym*info.dof))/(info.xm*info.dof);
1566: stencil.k = i/(info.xm*info.ym*info.dof);
1568: (*da->lfib)(&info,&stencil,u,vfu,w);
1570: DAVecRestoreArray(da,vu,&u);
1571: return(0);
1572: }
1574: #if defined(new)
1577: /*
1578: DAGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix where local
1579: function lives on a DA
1581: y ~= (F(u + ha) - F(u))/h,
1582: where F = nonlinear function, as set by SNESSetFunction()
1583: u = current iterate
1584: h = difference interval
1585: */
1586: PetscErrorCode DAGetDiagonal_MFFD(DA da,Vec U,Vec a)
1587: {
1588: PetscScalar h,*aa,*ww,v;
1589: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
1591: PetscInt gI,nI;
1592: MatStencil stencil;
1593: DALocalInfo info;
1594:
1596: (*ctx->func)(0,U,a,ctx->funcctx);
1597: (*ctx->funcisetbase)(U,ctx->funcctx);
1599: VecGetArray(U,&ww);
1600: VecGetArray(a,&aa);
1601:
1602: nI = 0;
1603: h = ww[gI];
1604: if (h == 0.0) h = 1.0;
1605: #if !defined(PETSC_USE_COMPLEX)
1606: if (h < umin && h >= 0.0) h = umin;
1607: else if (h < 0.0 && h > -umin) h = -umin;
1608: #else
1609: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
1610: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
1611: #endif
1612: h *= epsilon;
1613:
1614: ww[gI += h;
1615: (*ctx->funci)(i,w,&v,ctx->funcctx);
1616: aa[nI] = (v - aa[nI])/h;
1617: ww[gI] -= h;
1618: nI++;
1619: }
1620: VecRestoreArray(U,&ww);
1621: VecRestoreArray(a,&aa);
1622: return(0);
1623: }
1624: #endif
1626: #if defined(PETSC_HAVE_ADIC)
1628: #include "adic/ad_utils.h"
1633: /*@C
1634: DAComputeJacobian1WithAdic - Evaluates a adiC provided Jacobian function on each processor that
1635: share a DA
1637: Input Parameters:
1638: + da - the DA that defines the grid
1639: . vu - input vector (ghosted)
1640: . J - output matrix
1641: - w - any user data
1643: Level: advanced
1645: Notes: Does NOT do ghost updates on vu upon entry
1647: .seealso: DAFormFunction1()
1649: @*/
1650: PetscErrorCode DAComputeJacobian1WithAdic(DA da,Vec vu,Mat J,void *w)
1651: {
1653: PetscInt gtdof,tdof;
1654: PetscScalar *ustart;
1655: DALocalInfo info;
1656: void *ad_u,*ad_f,*ad_ustart,*ad_fstart;
1657: ISColoring iscoloring;
1660: DAGetLocalInfo(da,&info);
1662: PetscADResetIndep();
1664: /* get space for derivative objects. */
1665: DAGetAdicArray(da,PETSC_TRUE,(void **)&ad_u,&ad_ustart,>dof);
1666: DAGetAdicArray(da,PETSC_FALSE,(void **)&ad_f,&ad_fstart,&tdof);
1667: VecGetArray(vu,&ustart);
1668: DAGetColoring(da,IS_COLORING_GHOSTED,&iscoloring);
1670: PetscADSetValueAndColor(ad_ustart,gtdof,iscoloring->colors,ustart);
1672: VecRestoreArray(vu,&ustart);
1673: ISColoringDestroy(iscoloring);
1674: PetscADIncrementTotalGradSize(iscoloring->n);
1675: PetscADSetIndepDone();
1678: (*da->adic_lf)(&info,ad_u,ad_f,w);
1681: /* stick the values into the matrix */
1682: MatSetValuesAdic(J,(PetscScalar**)ad_fstart);
1684: /* return space for derivative objects. */
1685: DARestoreAdicArray(da,PETSC_TRUE,(void **)&ad_u,&ad_ustart,>dof);
1686: DARestoreAdicArray(da,PETSC_FALSE,(void **)&ad_f,&ad_fstart,&tdof);
1687: return(0);
1688: }
1692: /*@C
1693: DAMultiplyByJacobian1WithAdic - Applies an ADIC-provided Jacobian function to a vector on
1694: each processor that shares a DA.
1696: Input Parameters:
1697: + da - the DA that defines the grid
1698: . vu - Jacobian is computed at this point (ghosted)
1699: . v - product is done on this vector (ghosted)
1700: . fu - output vector = J(vu)*v (not ghosted)
1701: - w - any user data
1703: Notes:
1704: This routine does NOT do ghost updates on vu upon entry.
1706: Level: advanced
1708: .seealso: DAFormFunction1()
1710: @*/
1711: PetscErrorCode DAMultiplyByJacobian1WithAdic(DA da,Vec vu,Vec v,Vec f,void *w)
1712: {
1714: PetscInt i,gtdof,tdof;
1715: PetscScalar *avu,*av,*af,*ad_vustart,*ad_fstart;
1716: DALocalInfo info;
1717: void *ad_vu,*ad_f;
1720: DAGetLocalInfo(da,&info);
1722: /* get space for derivative objects. */
1723: DAGetAdicMFArray(da,PETSC_TRUE,(void **)&ad_vu,(void**)&ad_vustart,>dof);
1724: DAGetAdicMFArray(da,PETSC_FALSE,(void **)&ad_f,(void**)&ad_fstart,&tdof);
1726: /* copy input vector into derivative object */
1727: VecGetArray(vu,&avu);
1728: VecGetArray(v,&av);
1729: for (i=0; i<gtdof; i++) {
1730: ad_vustart[2*i] = avu[i];
1731: ad_vustart[2*i+1] = av[i];
1732: }
1733: VecRestoreArray(vu,&avu);
1734: VecRestoreArray(v,&av);
1736: PetscADResetIndep();
1737: PetscADIncrementTotalGradSize(1);
1738: PetscADSetIndepDone();
1740: (*da->adicmf_lf)(&info,ad_vu,ad_f,w);
1742: /* stick the values into the vector */
1743: VecGetArray(f,&af);
1744: for (i=0; i<tdof; i++) {
1745: af[i] = ad_fstart[2*i+1];
1746: }
1747: VecRestoreArray(f,&af);
1749: /* return space for derivative objects. */
1750: DARestoreAdicMFArray(da,PETSC_TRUE,(void **)&ad_vu,(void**)&ad_vustart,>dof);
1751: DARestoreAdicMFArray(da,PETSC_FALSE,(void **)&ad_f,(void**)&ad_fstart,&tdof);
1752: return(0);
1753: }
1754: #endif
1758: /*@
1759: DAComputeJacobian1 - Evaluates a local Jacobian function on each processor that
1760: share a DA
1762: Input Parameters:
1763: + da - the DA that defines the grid
1764: . vu - input vector (ghosted)
1765: . J - output matrix
1766: - w - any user data
1768: Notes: Does NOT do ghost updates on vu upon entry
1770: Level: advanced
1772: .seealso: DAFormFunction1()
1774: @*/
1775: PetscErrorCode DAComputeJacobian1(DA da,Vec vu,Mat J,void *w)
1776: {
1778: void *u;
1779: DALocalInfo info;
1782: DAGetLocalInfo(da,&info);
1783: DAVecGetArray(da,vu,&u);
1784: (*da->lj)(&info,u,J,w);
1785: DAVecRestoreArray(da,vu,&u);
1786: return(0);
1787: }
1792: /*
1793: DAComputeJacobian1WithAdifor - Evaluates a ADIFOR provided Jacobian local function on each processor that
1794: share a DA
1796: Input Parameters:
1797: + da - the DA that defines the grid
1798: . vu - input vector (ghosted)
1799: . J - output matrix
1800: - w - any user data
1802: Notes: Does NOT do ghost updates on vu upon entry
1804: .seealso: DAFormFunction1()
1806: */
1807: PetscErrorCode DAComputeJacobian1WithAdifor(DA da,Vec vu,Mat J,void *w)
1808: {
1809: PetscErrorCode ierr;
1810: PetscInt i,Nc,N;
1811: ISColoringValue *color;
1812: DALocalInfo info;
1813: PetscScalar *u,*g_u,*g_f,*f,*p_u;
1814: ISColoring iscoloring;
1815: void (*lf)(PetscInt*,DALocalInfo*,PetscScalar*,PetscScalar*,PetscInt*,PetscScalar*,PetscScalar*,PetscInt*,void*,PetscErrorCode*) =
1816: (void (*)(PetscInt*,DALocalInfo*,PetscScalar*,PetscScalar*,PetscInt*,PetscScalar*,PetscScalar*,PetscInt*,void*,PetscErrorCode*))*da->adifor_lf;
1819: DAGetColoring(da,IS_COLORING_GHOSTED,&iscoloring);
1820: Nc = iscoloring->n;
1821: DAGetLocalInfo(da,&info);
1822: N = info.gxm*info.gym*info.gzm*info.dof;
1824: /* get space for derivative objects. */
1825: PetscMalloc(Nc*info.gxm*info.gym*info.gzm*info.dof*sizeof(PetscScalar),&g_u);
1826: PetscMemzero(g_u,Nc*info.gxm*info.gym*info.gzm*info.dof*sizeof(PetscScalar));
1827: p_u = g_u;
1828: color = iscoloring->colors;
1829: for (i=0; i<N; i++) {
1830: p_u[*color++] = 1.0;
1831: p_u += Nc;
1832: }
1833: ISColoringDestroy(iscoloring);
1834: PetscMalloc(Nc*info.xm*info.ym*info.zm*info.dof*sizeof(PetscScalar),&g_f);
1835: PetscMalloc(info.xm*info.ym*info.zm*info.dof*sizeof(PetscScalar),&f);
1837: /* Seed the input array g_u with coloring information */
1838:
1839: VecGetArray(vu,&u);
1840: (lf)(&Nc,&info,u,g_u,&Nc,f,g_f,&Nc,w,&ierr);
1841: VecRestoreArray(vu,&u);
1843: /* stick the values into the matrix */
1844: /* PetscScalarView(Nc*info.xm*info.ym,g_f,0); */
1845: MatSetValuesAdifor(J,Nc,g_f);
1847: /* return space for derivative objects. */
1848: PetscFree(g_u);
1849: PetscFree(g_f);
1850: PetscFree(f);
1851: return(0);
1852: }
1856: /*@C
1857: DAMultiplyByJacobian1WithAD - Applies a Jacobian function supplied by ADIFOR or ADIC
1858: to a vector on each processor that shares a DA.
1860: Input Parameters:
1861: + da - the DA that defines the grid
1862: . vu - Jacobian is computed at this point (ghosted)
1863: . v - product is done on this vector (ghosted)
1864: . fu - output vector = J(vu)*v (not ghosted)
1865: - w - any user data
1867: Notes:
1868: This routine does NOT do ghost updates on vu and v upon entry.
1869:
1870: Automatically calls DAMultiplyByJacobian1WithAdifor() or DAMultiplyByJacobian1WithAdic()
1871: depending on whether DASetLocalAdicMFFunction() or DASetLocalAdiforMFFunction() was called.
1873: Level: advanced
1875: .seealso: DAFormFunction1(), DAMultiplyByJacobian1WithAdifor(), DAMultiplyByJacobian1WithAdic()
1877: @*/
1878: PetscErrorCode DAMultiplyByJacobian1WithAD(DA da,Vec u,Vec v,Vec f,void *w)
1879: {
1883: if (da->adicmf_lf) {
1884: #if defined(PETSC_HAVE_ADIC)
1885: DAMultiplyByJacobian1WithAdic(da,u,v,f,w);
1886: #else
1887: SETERRQ(PETSC_ERR_SUP_SYS,"Requires ADIC to be installed and cannot use complex numbers");
1888: #endif
1889: } else if (da->adiformf_lf) {
1890: DAMultiplyByJacobian1WithAdifor(da,u,v,f,w);
1891: } else {
1892: SETERRQ(PETSC_ERR_ORDER,"Must call DASetLocalAdiforMFFunction() or DASetLocalAdicMFFunction() before using");
1893: }
1894: return(0);
1895: }
1900: /*@C
1901: DAMultiplyByJacobian1WithAdifor - Applies a ADIFOR provided Jacobian function on each processor that
1902: share a DA to a vector
1904: Input Parameters:
1905: + da - the DA that defines the grid
1906: . vu - Jacobian is computed at this point (ghosted)
1907: . v - product is done on this vector (ghosted)
1908: . fu - output vector = J(vu)*v (not ghosted)
1909: - w - any user data
1911: Notes: Does NOT do ghost updates on vu and v upon entry
1913: Level: advanced
1915: .seealso: DAFormFunction1()
1917: @*/
1918: PetscErrorCode DAMultiplyByJacobian1WithAdifor(DA da,Vec u,Vec v,Vec f,void *w)
1919: {
1921: PetscScalar *au,*av,*af,*awork;
1922: Vec work;
1923: DALocalInfo info;
1924: void (*lf)(DALocalInfo*,PetscScalar*,PetscScalar*,PetscScalar*,PetscScalar*,void*,PetscErrorCode*) =
1925: (void (*)(DALocalInfo*,PetscScalar*,PetscScalar*,PetscScalar*,PetscScalar*,void*,PetscErrorCode*))*da->adiformf_lf;
1928: DAGetLocalInfo(da,&info);
1930: DAGetGlobalVector(da,&work);
1931: VecGetArray(u,&au);
1932: VecGetArray(v,&av);
1933: VecGetArray(f,&af);
1934: VecGetArray(work,&awork);
1935: (lf)(&info,au,av,awork,af,w,&ierr);
1936: VecRestoreArray(u,&au);
1937: VecRestoreArray(v,&av);
1938: VecRestoreArray(f,&af);
1939: VecRestoreArray(work,&awork);
1940: DARestoreGlobalVector(da,&work);
1942: return(0);
1943: }
1947: /*@C
1948: DASetInterpolationType - Sets the type of interpolation that will be
1949: returned by DAGetInterpolation()
1951: Collective on DA
1953: Input Parameter:
1954: + da - initial distributed array
1955: . ctype - DA_Q1 and DA_Q0 are currently the only supported forms
1957: Level: intermediate
1959: Notes: you should call this on the coarser of the two DAs you pass to DAGetInterpolation()
1961: .keywords: distributed array, interpolation
1963: .seealso: DACreate1d(), DACreate2d(), DACreate3d(), DADestroy(), DA, DAInterpolationType
1964: @*/
1965: PetscErrorCode DASetInterpolationType(DA da,DAInterpolationType ctype)
1966: {
1969: da->interptype = ctype;
1970: return(0);
1971: }