Actual source code: inpututils.c

  1: /*
  2:        Utilities for inputing, creating and managing simple two dimensional grids
  3: */

 5:  #include src/dm/ao/aoimpl.h
 6:  #include petscbt.h
 7:  #include petscdraw.h

  9: /*
 10:     cell_n        - number of cells
 11:     max_cell      - maximum space allocated for cell
 12:     cell_vertex   - vertices of each cell
 13:     cell_edge     - edges of the cell
 14:     cell_cell     - neighbors of cell
 15:     vertex_n      - number of vertices
 16:     vertex_max    - maximum space allocated for vertices
 17:     x,y           - vertex coordinates

 19:     xmin,ymin,xmax,ymax - bounding box of grid

 21:     edge_n        - total edges in the grid
 22:     edge_vertex   - vertex of all edges 
 23:     edge_max      - maximum space allocated for edge
 24:     edge_cell     - two neighbor cells who share edge

 26:     vertex_boundary - indicates for each vertex if it is a boundary

 28: */



 34: PetscErrorCode AOData2dGridToAOData(AOData2dGrid agrid,AOData *ao)
 35: {
 37:   PetscInt       *keys,nmax,i;
 38:   AOData         aodata;

 41:   /*
 42:       Create the database 
 43:   */
 44:   nmax = PetscMax(agrid->cell_n,agrid->vertex_n);
 45:   nmax = PetscMax(nmax,agrid->edge_n);
 46:   PetscMalloc(nmax*sizeof(PetscInt),&keys);
 47:   for (i=0; i<nmax; i++) {
 48:     keys[i] = i;
 49:   }
 50:   AODataCreateBasic(PETSC_COMM_WORLD,&aodata);
 51:     AODataKeyAdd(aodata,"cell",PETSC_DECIDE,agrid->cell_n);
 52:       AODataSegmentAdd(aodata,"cell","cell",4,agrid->cell_n,keys,agrid->cell_cell,PETSC_INT);
 53:       AODataSegmentAdd(aodata,"cell","vertex",4,agrid->cell_n,keys,agrid->cell_vertex,PETSC_INT);
 54:       AODataSegmentAdd(aodata,"cell","edge",4,agrid->cell_n,keys,agrid->cell_edge,PETSC_INT);
 55:     AODataKeyAdd(aodata,"edge",PETSC_DECIDE,agrid->edge_n);
 56:       AODataSegmentAdd(aodata,"edge","vertex",2,agrid->edge_n,keys,agrid->edge_vertex,PETSC_INT);
 57:       AODataSegmentAdd(aodata,"edge","cell",2,agrid->edge_n,keys,agrid->edge_cell,PETSC_INT);
 58:     AODataKeyAdd(aodata,"vertex",PETSC_DECIDE,agrid->vertex_n);
 59:       AODataSegmentAdd(aodata,"vertex","values",2,agrid->vertex_n,keys,agrid->vertex,PETSC_DOUBLE);
 60:       AODataSegmentAdd(aodata,"vertex","boundary",1,agrid->vertex_n,keys,agrid->vertex_boundary,PETSC_LOGICAL);
 61:   PetscFree(keys);
 62:   *ao = aodata;
 63:   return(0);
 64: }

 68: /*
 69:        User input the cell by drawing them one at a time
 70: */
 71: PetscErrorCode AOData2dGridInput(AOData2dGrid agrid,PetscDraw draw)
 72: {
 73:   PetscDraw       popup;                           /* help window */
 74:   PetscDrawButton button;                          /* mouse button pressed */
 76:   PetscInt             cn, *cell;
 77:   PetscReal       *vertex,cx,cy;
 78:   char            title[120];

 81:   agrid->cell_max      = 500;
 82:   agrid->cell_n        = 0;
 83:   agrid->vertex_max    = 500;
 84:   agrid->vertex_n      = 0;
 85:   agrid->xmin          = PETSC_MAX;
 86:   agrid->xmax          = PETSC_MIN;
 87:   agrid->ymin          = PETSC_MAX;
 88:   agrid->ymax          = PETSC_MIN;

 90:   /*
 91:      Allocate large arrays to hold the nodes and cellrilateral lists 
 92:   */
 93:   PetscMalloc(2*agrid->vertex_max*sizeof(PetscReal),&agrid->vertex);
 94:   vertex = agrid->vertex;
 95:   PetscMalloc(4*agrid->cell_max*sizeof(PetscInt),&agrid->cell_vertex);
 96:   cell   = agrid->cell_vertex;


 99:   /*
100:      Open help window and enter helpful messages
101:   */
102:   PetscDrawGetPopup(draw,&popup);
103:   PetscDrawString(popup,.1,.9,PETSC_DRAW_BLUE,"Use left button to\n   enter cell.");
104:   PetscDrawString(popup,.1,.7,PETSC_DRAW_BLUE,"Use center button to\n   end.");
105:   PetscDrawFlush(popup);

107:   PetscDrawGetMouseButton(draw,&button,&cx,&cy,PETSC_NULL,PETSC_NULL);
108:   AOData2dGridAddNode(agrid,cx,cy,&cn);
109:   cell[0] = cn;
110:   sprintf(title,"Input grid: Number vertex %d Number cell %d",(int)agrid->vertex_n,(int)agrid->cell_n);
111:   PetscDrawSetTitle(draw,title);
112:   while (button == BUTTON_LEFT) {
113:     /* wait for second vertex */
114:     PetscDrawGetMouseButton(draw,&button,&cx,&cy,PETSC_NULL,PETSC_NULL);
115:     if (button != BUTTON_LEFT) {
116:       SETERRQ(PETSC_ERR_USER,"Must press left button to complete quadrilateral");
117:     }
118:     AOData2dGridAddNode(agrid,cx,cy,&cn);
119:     cell[4*agrid->cell_n+1] = cn;
120:     PetscDrawLine(draw,vertex[2*cell[4*agrid->cell_n]],vertex[1+2*cell[4*agrid->cell_n]],
121:                          vertex[2*cell[4*agrid->cell_n+1]],vertex[1+2*cell[4*agrid->cell_n+1]],
122:                          PETSC_DRAW_RED);
123:     sprintf(title,"Input grid: Number vertex %d Number cell %d",(int)agrid->vertex_n,(int)agrid->cell_n);
124:     PetscDrawSetTitle(draw,title);
125:     /* wait for third vertex */
126:     PetscDrawGetMouseButton(draw,&button,&cx,&cy,PETSC_NULL,PETSC_NULL);
127:     if (button != BUTTON_LEFT) {
128:       SETERRQ(PETSC_ERR_USER,"Must press left button to complete quadrilateral");
129:     }
130:     AOData2dGridAddNode(agrid,cx,cy,&cn);
131:     cell[4*agrid->cell_n+2] = cn;
132:     PetscDrawLine(draw,vertex[2*cell[4*agrid->cell_n+1]],vertex[1+2*cell[4*agrid->cell_n+1]],
133:                          vertex[2*cell[4*agrid->cell_n+2]],vertex[1+2*cell[4*agrid->cell_n+2]],
134:                          PETSC_DRAW_RED);
135:     sprintf(title,"Input grid: Number vertex %d Number cell %d",(int)agrid->vertex_n,(int)agrid->cell_n);
136:     PetscDrawSetTitle(draw,title);
137:     /* wait for fourth vertex */
138:     PetscDrawGetMouseButton(draw,&button,&cx,&cy,PETSC_NULL,PETSC_NULL);
139:     if (button != BUTTON_LEFT) {
140:       SETERRQ(PETSC_ERR_USER,"Must press left button to complete quadrilateral");
141:     }
142:     AOData2dGridAddNode(agrid,cx,cy,&cn);
143:     cell[4*agrid->cell_n+3] = cn;
144:     PetscDrawLine(draw,vertex[2*cell[4*agrid->cell_n+2]],vertex[1+2*cell[4*agrid->cell_n+2]],
145:                          vertex[2*cell[4*agrid->cell_n+3]],vertex[1+2*cell[4*agrid->cell_n+3]],
146:                          PETSC_DRAW_RED);
147:     PetscDrawLine(draw,vertex[2*cell[4*agrid->cell_n]],vertex[1+2*cell[4*agrid->cell_n]],
148:                          vertex[2*cell[4*agrid->cell_n+3]],vertex[1+2*cell[4*agrid->cell_n+3]],
149:                          PETSC_DRAW_RED);
150:     agrid->cell_n++;
151:     sprintf(title,"Input grid: Number vertex %d Number cell %d",(int)agrid->vertex_n,(int)agrid->cell_n);
152:     PetscDrawSetTitle(draw,title);

154:     /* Get the first for the next cellralateral, or BUTTON_CENTER to end */
155:     PetscDrawGetMouseButton(draw,&button,&cx,&cy,PETSC_NULL,PETSC_NULL);
156:     if (button != BUTTON_LEFT) {break;}
157:     AOData2dGridAddNode(agrid,cx,cy,&cn);
158:     cell[4*agrid->cell_n] = cn;

160:     sprintf(title,"Input grid: Number vertex %d Number cell %d",(int)agrid->vertex_n,(int)agrid->cell_n);
161:     PetscDrawSetTitle(draw,title);
162:   }
163:   return(0);
164: }

168: /*
169:    Changes the node numbering for the cell to make sure they are all in 
170:    clockwise ordering
171: */
172: PetscErrorCode AOData2dGridFlipCells(AOData2dGrid agrid)
173: {
174:   PetscInt       i,*cell = agrid->cell_vertex, cell_n = agrid->cell_n;
175:   PetscReal *vertex = agrid->vertex, sign;

178:   for (i=0; i<cell_n; i++) {
179:     /*
180:        compute the quantity

182:             x0      x1    x2      x3
183:             y0      y1    y2      y3
184:      */

186:      sign = vertex[2*cell[4*i]]*vertex[1+2*cell[4*i+1]]   + vertex[2*cell[4*i+1]]*vertex[1+2*cell[4*i+2]] +
187:             vertex[2*cell[4*i+2]]*vertex[1+2*cell[4*i+3]] + vertex[2*cell[4*i+3]]*vertex[1+2*cell[4*i]]   -
188:             vertex[1+2*cell[4*i]]*vertex[2*cell[4*i+1]]   - vertex[1+2*cell[4*i+1]]*vertex[2*cell[4*i+2]] -
189:             vertex[1+2*cell[4*i+2]]*vertex[2*cell[4*i+3]] - vertex[1+2*cell[4*i+3]]*vertex[2*cell[4*i]];

191:      if (sign == 0.0) {
192:        SETERRQ(PETSC_ERR_USER,"Bad cell, zero area");
193:      } else if (sign > 0) {
194:        PetscInt q1tmp = cell[4*i+1];
195:        cell[4*i+1] = cell[4*i+3];
196:        cell[4*i+3] = q1tmp;
197:      }
198:   }
199:   return(0);
200: }

204: /*
205:      AOData2dGridAddNode - Maintains a list of nodes given so far
206: */
207: PetscErrorCode AOData2dGridAddNode(AOData2dGrid agrid, PetscReal cx, PetscReal cy, PetscInt *cn)
208: {
209:   PetscInt i;

212:   for (i=0; i<agrid->vertex_n; i++) {
213:     if ((PetscAbsReal(agrid->vertex[2*i] - cx) < 1.e-9) && (PetscAbsReal(agrid->vertex[1+2*i] - cy) < 1.e-9)) {
214:       *cn = i;
215:       return(0);
216:     }
217:   }
218:   agrid->vertex[2*agrid->vertex_n] = cx;
219:   agrid->vertex[1+2*agrid->vertex_n] = cy;
220:   *cn     = (agrid->vertex_n)++;

222:   if (cx < agrid->xmin)      agrid->xmin = cx;
223:   else if (cx > agrid->xmax) agrid->xmax = cx;
224:   if (cy < agrid->ymin)      agrid->ymin = cy;
225:   else if (cy > agrid->ymax) agrid->ymax = cy;
226:   return(0);
227: }

231: PetscErrorCode AOData2dGridComputeNeighbors(AOData2dGrid agrid)
232: {
234:   PetscInt  i,j,*cell_edge,*edge_cell,*edge,*cell,*neighbors,e;

237:   agrid->edge_max = 2*agrid->vertex_n;
238:   agrid->edge_n   = 0;
239:   PetscMalloc(2*agrid->edge_max*sizeof(PetscInt),&agrid->edge_vertex);
240:   edge      = agrid->edge_vertex;
241:   PetscMalloc(4*agrid->cell_max*sizeof(PetscInt),agrid->cell_edge);
242:   cell_edge = agrid->cell_edge;
243:   PetscMalloc(2*agrid->edge_max*sizeof(PetscInt),&agrid->edge_cell);
244:   edge_cell = agrid->edge_cell;

246:   cell      = agrid->cell_vertex;

248:   /*
249:        Mark all neighbors (to start) with -1 to indicate missing neighbor
250:   */
251:   for (i=0; i<2*agrid->edge_max; i++) {
252:     edge_cell[i] = -1;
253:   }

255:   for (i=0; i<agrid->cell_n; i++) {
256:     for (j=0; j<agrid->edge_n; j++) {
257:       if (cell[4*i] == edge[2*j+1] && cell[4*i+1] == edge[2*j]) {
258:         cell_edge[4*i]   = j;
259:         edge_cell[2*j+1] = i;
260:         goto found0;
261:       }
262:     }
263:     /*
264:        Add a new edge to the list 
265:     */
266:     edge_cell[2*agrid->edge_n]   = i;
267:     edge[2*agrid->edge_n]        = cell[4*i];
268:     edge[2*agrid->edge_n+1]      = cell[4*i+1];
269:     cell_edge[4*i]                = agrid->edge_n;
270:     agrid->edge_n++;
271:     found0:;
272:     for (j=0; j<agrid->edge_n; j++) {
273:       if (cell[4*i+1] == edge[2*j+1] && cell[4*i+2] == edge[2*j]) {
274:         cell_edge[4*i+1] = j;
275:         edge_cell[2*j+1] = i;
276:         goto found1;
277:       }
278:     }
279:     /*
280:        Add a new edge to the list 
281:     */
282:     edge_cell[2*agrid->edge_n]   = i;
283:     edge[2*agrid->edge_n]        = cell[4*i+1];
284:     edge[2*agrid->edge_n+1]      = cell[4*i+2];
285:     cell_edge[4*i+1]              = agrid->edge_n;
286:     agrid->edge_n++;
287:     found1:;
288:     for (j=0; j<agrid->edge_n; j++) {
289:       if (cell[4*i+2] == edge[2*j+1] && cell[4*i+3] == edge[2*j]) {
290:         cell_edge[4*i+2] = j;
291:         edge_cell[2*j+1] = i;
292:         goto found2;
293:       }
294:     }
295:     /*
296:        Add a new edge to the list 
297:     */
298:     edge_cell[2*agrid->edge_n]   = i;
299:     edge[2*agrid->edge_n]        = cell[4*i+2];
300:     edge[2*agrid->edge_n+1]      = cell[4*i+3];
301:     cell_edge[4*i+2]              = agrid->edge_n;
302:     agrid->edge_n++;
303:     found2:;
304:     for (j=0; j<agrid->edge_n; j++) {
305:       if (cell[4*i+3] == edge[2*j+1] && cell[4*i] == edge[2*j]) {
306:         cell_edge[4*i+3] = j;
307:         edge_cell[2*j+1] = i;
308:         goto found3;
309:       }
310:     }
311:     /*
312:        Add a new edge to the list 
313:     */
314:     edge_cell[2*agrid->edge_n]   = i;
315:     edge[2*agrid->edge_n]        = cell[4*i+3];
316:     edge[2*agrid->edge_n+1]      = cell[4*i];
317:     cell_edge[4*i+3]              = agrid->edge_n;
318:     agrid->edge_n++;
319:     found3:;

321:   }

323:   PetscMalloc(4*agrid->cell_n*sizeof(PetscInt),&agrid->cell_cell);
324:   neighbors = agrid->cell_cell;
325:   for (i=0; i<agrid->cell_n; i++) {
326:     for (j=0; j<4; j++) {
327:       e = 2*agrid->cell_edge[4*i+j];

329:       /* get the edge neighbor that is not the current cell */
330:       if (i == agrid->edge_cell[e]) e++;
331:       neighbors[4*i+j] = agrid->edge_cell[e];
332:     }
333:   }

335:   return(0);
336: }

340: PetscErrorCode AOData2dGridComputeVertexBoundary(AOData2dGrid agrid)
341: {
343:   PetscInt  i,j,*count,*cell_vertex = agrid->cell_vertex;

346:   /*
347:       allocate bitarray for boundary info
348:   */
349:   PetscBTCreate(agrid->vertex_n,agrid->vertex_boundary);

351:   /*
352:       count contains number of cell that contain the given vertex 
353:   */
354:   PetscMalloc(agrid->vertex_n*sizeof(PetscInt),&count);
355:   PetscMemzero(count,agrid->vertex_n*sizeof(PetscInt));

357:   for (i=0; i<agrid->cell_n; i++) {
358:     for (j=0; j<4; j++) {
359:       count[cell_vertex[4*i+j]]++;
360:     }
361:   }


364:   for (i=0; i<agrid->vertex_n; i++) {
365:     /* UGLY! Just for a quick solution: I want Dirichlet b.c. only at left edge! */
366:     PetscTruth neumann_bc;
367:     PetscOptionsHasName(PETSC_NULL,"-dirichlet_on_left",&neumann_bc);
368:     if (neumann_bc) {
369:       if ((count[i] < 4) && (agrid->vertex[2*i] == agrid->xmin)) {
370:         PetscBTSet(agrid->vertex_boundary,i);
371:       }
372:     } else {
373:       if (count[i] < 4) {
374:         PetscBTSet(agrid->vertex_boundary,i);
375:       }
376:     }
377:   }

379:   PetscFree(count);

381:   return(0);
382: }

386: /*
387:      Show the numbering of the vertex, cell and edge
388: */
389: PetscErrorCode AOData2dGridDraw(AOData2dGrid agrid,PetscDraw draw)
390: {
392:   PetscInt       i, *cell = agrid->cell_vertex, *edge = agrid->edge_vertex;
393:   char      str[5];
394:   PetscReal *vertex = agrid->vertex,xx,yy,xmin,xmax,ymin,ymax,h,w;

397:   w = agrid->xmax - agrid->xmin;
398:   h = agrid->ymax - agrid->ymin;
399:   xmin = agrid->xmin - .1*w;
400:   xmax = agrid->xmax + .1*w;
401:   ymin = agrid->ymin - .1*h;
402:   ymax = agrid->ymax + .1*h;
403:   PetscDrawSetCoordinates(draw,xmin,ymin,xmax,ymax);

405:   /*
406:      Number the vertex
407:   */
408:   for (i=0; i<agrid->vertex_n; i++) {
409:     sprintf(str,"%d",(int)i);
410:     PetscDrawString(draw,vertex[2*i],vertex[1+2*i],PETSC_DRAW_BLUE,str);
411:   }

413:   /*
414:      Number the cell
415:   */
416:   for (i=0; i<agrid->cell_n; i++) {
417:     sprintf(str,"%d",(int)i);
418:     xx = .25*(vertex[2*cell[4*i]] + vertex[2*cell[4*i+1]] + vertex[2*cell[4*i+2]] + vertex[2*cell[4*i+3]]);
419:     yy = .25*(vertex[1+2*cell[4*i]] + vertex[1+2*cell[4*i+1]] + vertex[1+2*cell[4*i+2]] + vertex[1+2*cell[4*i+3]]);
420:     PetscDrawString(draw,xx,yy,PETSC_DRAW_GREEN,str);
421:   }

423:   /*
424:      Number the edge
425:   */
426:   for (i=0; i<agrid->edge_n; i++) {
427:     sprintf(str,"%d",(int)i);
428:     xx = .5*(vertex[2*edge[2*i]] + vertex[2*edge[2*i+1]]);
429:     yy = .5*(vertex[1+2*edge[2*i]] + vertex[1+2*edge[2*i+1]]);
430:     PetscDrawLine(draw,vertex[2*edge[2*i]],vertex[1+2*edge[2*i]],vertex[2*edge[2*i+1]],vertex[1+2*edge[2*i+1]],PETSC_DRAW_BLACK);
431:     PetscDrawString(draw,xx,yy,PETSC_DRAW_VIOLET,str);
432:   }

434:   return(0);
435: }

439: /*
440:     Frees all the memory space allocated in AGrid
441: */
442: PetscErrorCode AOData2dGridDestroy(AOData2dGrid agrid)
443: {

447:    PetscFree(agrid->vertex);
448:    PetscFree(agrid->cell_vertex);
449:    PetscFree(agrid->cell_edge);
450:    PetscFree(agrid->edge_vertex);
451:    PetscFree(agrid->edge_cell);
452:    PetscFree(agrid->cell_cell);
453:    PetscFree(agrid->vertex_boundary);
454:    PetscFree(agrid);
455:    return(0);
456: }

460: /*
461:     
462: */
463: PetscErrorCode AOData2dGridCreate(AOData2dGrid *agrid)
464: {
467:   PetscNew(struct _p_AOData2dGrid,agrid);
468:   return(0);
469: }