Actual source code: hists.c

  1: #define PETSC_DLL
  2: /*
  3:   Contains the data structure for plotting a histogram in a window with an axis.
  4: */

 6:  #include petscsys.h

  8: PetscCookie DRAWHG_COOKIE = 0;

 10: struct _p_DrawHG {
 11:   PETSCHEADER(int);
 12:   PetscErrorCode (*destroy)(PetscDrawSP);
 13:   PetscErrorCode (*view)(PetscDrawSP,PetscViewer);
 14:   PetscDraw     win;
 15:   PetscDrawAxis axis;
 16:   PetscReal     xmin,xmax;
 17:   PetscReal     ymin,ymax;
 18:   int           numBins;
 19:   int           maxBins;
 20:   PetscReal     *bins;
 21:   int           numValues;
 22:   int           maxValues;
 23:   PetscReal     *values;
 24:   int           color;
 25:   PetscTruth    calcStats;
 26:   PetscTruth    integerBins;
 27: };

 29: #define CHUNKSIZE 100

 33: /*@C
 34:    PetscDrawHGCreate - Creates a histogram data structure.

 36:    Collective over PetscDraw

 38:    Input Parameters:
 39: +  draw  - The window where the graph will be made
 40: -  bins - The number of bins to use

 42:    Output Parameters:
 43: .  hist - The histogram context

 45:    Level: intermediate

 47:    Concepts: histogram^creating

 49: .seealso: PetscDrawHGDestroy()

 51: @*/
 52: PetscErrorCode  PetscDrawHGCreate(PetscDraw draw, int bins, PetscDrawHG *hist) {
 53:   PetscDrawHG    h;
 54:   MPI_Comm       comm;
 55:   PetscTruth     isnull;

 61:   PetscObjectGetComm((PetscObject) draw, &comm);
 62:   PetscHeaderCreate(h, _p_DrawHG, int, DRAWHG_COOKIE, 0, "PetscDrawHG", comm, PetscDrawHGDestroy, PETSC_NULL);
 63:   h->view        = PETSC_NULL;
 64:   h->destroy     = PETSC_NULL;
 65:   h->win         = draw;
 66:   PetscObjectReference((PetscObject) draw);
 67:   h->color       = PETSC_DRAW_GREEN;
 68:   h->xmin        = PETSC_MAX;
 69:   h->xmax        = PETSC_MIN;
 70:   h->ymin        = 0.;
 71:   h->ymax        = 1.;
 72:   h->numBins     = bins;
 73:   h->maxBins     = bins;
 74:   PetscMalloc(h->maxBins * sizeof(PetscReal), &h->bins);
 75:   h->numValues   = 0;
 76:   h->maxValues   = CHUNKSIZE;
 77:   h->calcStats   = PETSC_FALSE;
 78:   h->integerBins = PETSC_FALSE;
 79:   PetscMalloc(h->maxValues * sizeof(PetscReal), &h->values);
 80:   PetscLogObjectMemory(h, (h->maxBins + h->maxValues)*sizeof(PetscReal));
 81:   PetscTypeCompare((PetscObject) draw, PETSC_DRAW_NULL, &isnull);
 82:   if (!isnull) {
 83:     PetscDrawAxisCreate(draw, &h->axis);
 84:     PetscLogObjectParent(h, h->axis);
 85:   } else {
 86:     h->axis = PETSC_NULL;
 87:   }
 88:   *hist = h;
 89:   return(0);
 90: }

 94: /*@
 95:    PetscDrawHGSetNumberBins - Change the number of bins that are to be drawn.

 97:    Not Collective (ignored except on processor 0 of PetscDrawHG)

 99:    Input Parameter:
100: +  hist - The histogram context.
101: -  dim  - The number of curves.

103:    Level: intermediate

105:    Concepts: histogram^setting number of bins

107: @*/
108: PetscErrorCode  PetscDrawHGSetNumberBins(PetscDrawHG hist, int bins)
109: {

114:   if (hist->maxBins < bins) {
115:     PetscFree(hist->bins);
116:     PetscMalloc(bins * sizeof(PetscReal), &hist->bins);
117:     PetscLogObjectMemory(hist, (bins - hist->maxBins) * sizeof(PetscReal));
118:     hist->maxBins = bins;
119:   }
120:   hist->numBins = bins;
121:   return(0);
122: }

126: /*@
127:   PetscDrawHGReset - Clears histogram to allow for reuse with new data.

129:   Not Collective (ignored except on processor 0 of PetscDrawHG)

131:   Input Parameter:
132: . hist - The histogram context.

134:   Level: intermediate

136:   Concepts: histogram^resetting
137: @*/
138: PetscErrorCode  PetscDrawHGReset(PetscDrawHG hist)
139: {
142:   hist->xmin      = PETSC_MAX;
143:   hist->xmax      = PETSC_MIN;
144:   hist->ymin      = 0.0;
145:   hist->ymax      = 0.0;
146:   hist->numValues = 0;
147:   return(0);
148: }

152: /*@C
153:   PetscDrawHGDestroy - Frees all space taken up by histogram data structure.

155:   Collective over PetscDrawHG

157:   Input Parameter:
158: . hist - The histogram context

160:   Level: intermediate

162: .seealso:  PetscDrawHGCreate()
163: @*/
164: PetscErrorCode  PetscDrawHGDestroy(PetscDrawHG hist)
165: {


171:   if (--((PetscObject)hist)->refct > 0) return(0);
172:   if (hist->axis) {
173:     PetscDrawAxisDestroy(hist->axis);
174:   }
175:   PetscDrawDestroy(hist->win);
176:   PetscFree(hist->bins);
177:   PetscFree(hist->values);
178:   PetscHeaderDestroy(hist);
179:   return(0);
180: }

184: /*@
185:   PetscDrawHGAddValue - Adds another value to the histogram.

187:   Not Collective (ignored except on processor 0 of PetscDrawHG)

189:   Input Parameters:
190: + hist  - The histogram
191: - value - The value 

193:   Level: intermediate

195:   Concepts: histogram^adding values

197: .seealso: PetscDrawHGAddValues()
198: @*/
199: PetscErrorCode  PetscDrawHGAddValue(PetscDrawHG hist, PetscReal value)
200: {
203:   /* Allocate more memory if necessary */
204:   if (hist->numValues >= hist->maxValues) {
205:     PetscReal      *tmp;

208:     PetscMalloc((hist->maxValues+CHUNKSIZE) * sizeof(PetscReal), &tmp);
209:     PetscLogObjectMemory(hist, CHUNKSIZE * sizeof(PetscReal));
210:     PetscMemcpy(tmp, hist->values, hist->maxValues * sizeof(PetscReal));
211:     PetscFree(hist->values);
212:     hist->values     = tmp;
213:     hist->maxValues += CHUNKSIZE;
214:   }
215:   /* I disagree with the original Petsc implementation here. There should be no overshoot, but rather the
216:      stated convention of using half-open intervals (always the way to go) */
217:   if (!hist->numValues) {
218:     hist->xmin = value;
219:     hist->xmax = value;
220: #if 1
221:   } else {
222:     /* Update limits */
223:     if (value > hist->xmax)
224:       hist->xmax = value;
225:     if (value < hist->xmin)
226:       hist->xmin = value;
227: #else
228:   } else if (hist->numValues == 1) {
229:     /* Update limits -- We need to overshoot the largest value somewhat */
230:     if (value > hist->xmax) {
231:       hist->xmax = value + 0.001*(value - hist->xmin)/hist->numBins;
232:     }
233:     if (value < hist->xmin) {
234:       hist->xmin = value;
235:       hist->xmax = hist->xmax + 0.001*(hist->xmax - hist->xmin)/hist->numBins;
236:     }
237:   } else {
238:     /* Update limits -- We need to overshoot the largest value somewhat */
239:     if (value > hist->xmax) {
240:       hist->xmax = value + 0.001*(hist->xmax - hist->xmin)/hist->numBins;
241:     }
242:     if (value < hist->xmin) {
243:       hist->xmin = value;
244:     }
245: #endif
246:   }

248:   hist->values[hist->numValues++] = value;
249:   return(0);
250: }

254: /*@
255:   PetscDrawHGDraw - Redraws a histogram.

257:   Not Collective (ignored except on processor 0 of PetscDrawHG)

259:   Input Parameter:
260: . hist - The histogram context

262:   Level: intermediate

264: @*/
265: PetscErrorCode  PetscDrawHGDraw(PetscDrawHG hist)
266: {
267:   PetscDraw      draw = hist->win;
268:   PetscTruth     isnull;
269:   PetscReal      xmin,xmax,ymin,ymax,*bins,*values,binSize,binLeft,binRight,maxHeight,mean,var;
270:   char           title[256];
271:   char           xlabel[256];
272:   PetscInt       numBins,numBinsOld,numValues,initSize,i,p,bcolor,color;

277:   PetscTypeCompare((PetscObject) draw, PETSC_DRAW_NULL, &isnull);
278:   if (isnull) return(0);
279:   if ((hist->xmin >= hist->xmax) || (hist->ymin >= hist->ymax)) return(0);
280:   if (hist->numValues < 1) return(0);

282: #if 0
283:   MPI_Comm_rank(((PetscObject)hist)->comm,&rank);
284:   if (rank) return(0);
285: #endif

287:   color     = hist->color;
288:   if (color == PETSC_DRAW_ROTATE) {bcolor = 2;} else {bcolor = color;}
289:   xmin      = hist->xmin;
290:   xmax      = hist->xmax;
291:   ymin      = hist->ymin;
292:   ymax      = hist->ymax;
293:   numValues = hist->numValues;
294:   values    = hist->values;
295:   mean      = 0.0;
296:   var       = 0.0;
297: 
298:   PetscDrawClear(draw);
299:   if (xmin == xmax) {
300:     /* Calculate number of points in each bin */
301:     bins    = hist->bins;
302:     bins[0] = 0.;
303:     for(p = 0; p < numValues; p++) {
304:       if (values[p] == xmin) bins[0]++;
305:       mean += values[p];
306:       var  += values[p]*values[p];
307:     }
308:     maxHeight = bins[0];
309:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;
310:     xmax = xmin + 1;
311:     PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax);
312:     if (hist->calcStats) {
313:       mean /= numValues;
314:       if (numValues > 1) {
315:         var = (var - numValues*mean*mean) / (numValues-1);
316:       } else {
317:         var = 0.0;
318:       }
319:       PetscSNPrintf(title, 256, "Mean: %g  Var: %g", (double)mean, (double)var);
320:       PetscSNPrintf(xlabel,256, "Total: %D", numValues);
321:       PetscDrawAxisSetLabels(hist->axis, title, xlabel, PETSC_NULL);
322:     }
323:     PetscDrawAxisDraw(hist->axis);
324:     /* Draw bins */
325:     binLeft   = xmin;
326:     binRight  = xmax;
327:     PetscDrawRectangle(draw,binLeft,ymin,binRight,bins[0],bcolor,bcolor,bcolor,bcolor);
328:     if (color == PETSC_DRAW_ROTATE && bins[0] != 0.0) bcolor++; if (bcolor > 31) bcolor = 2;
329:     PetscDrawLine(draw,binLeft,ymin,binLeft,bins[0],PETSC_DRAW_BLACK);
330:     PetscDrawLine(draw,binRight,ymin,binRight,bins[0],PETSC_DRAW_BLACK);
331:     PetscDrawLine(draw,binLeft,bins[0],binRight,bins[0],PETSC_DRAW_BLACK);
332:   } else {
333:     numBins    = hist->numBins;
334:     numBinsOld = hist->numBins;
335:     if (hist->integerBins && (((int) xmax - xmin) + 1.0e-05 > xmax - xmin)) {
336:       initSize = (int) ((int) xmax - xmin)/numBins;
337:       while (initSize*numBins != (int) xmax - xmin) {
338:         initSize = PetscMax(initSize - 1, 1);
339:         numBins  = (int) ((int) xmax - xmin)/initSize;
340:         PetscDrawHGSetNumberBins(hist, numBins);
341:       }
342:     }
343:     binSize = (xmax - xmin)/numBins;
344:     bins    = hist->bins;

346:     PetscMemzero(bins, numBins * sizeof(PetscReal));
347:     maxHeight = 0.0;
348:     for (i = 0; i < numBins; i++) {
349:       binLeft   = xmin + binSize*i;
350:       binRight  = xmin + binSize*(i+1);
351:       for(p = 0; p < numValues; p++) {
352:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
353:         /* Handle last bin separately */
354:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
355:         if (!i) {
356:           mean += values[p];
357:           var  += values[p]*values[p];
358:         }
359:       }
360:       maxHeight = PetscMax(maxHeight, bins[i]);
361:     }
362:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;

364:     PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax);
365:     if (hist->calcStats) {
366:       mean /= numValues;
367:       if (numValues > 1) {
368:         var = (var - numValues*mean*mean) / (numValues-1);
369:       } else {
370:         var = 0.0;
371:       }
372:       PetscSNPrintf(title, 256,"Mean: %g  Var: %g", (double)mean, (double)var);
373:       PetscSNPrintf(xlabel,256, "Total: %D", numValues);
374:       PetscDrawAxisSetLabels(hist->axis, title, xlabel, PETSC_NULL);
375:     }
376:     PetscDrawAxisDraw(hist->axis);
377:     /* Draw bins */
378:     for (i = 0; i < numBins; i++) {
379:       binLeft   = xmin + binSize*i;
380:       binRight  = xmin + binSize*(i+1);
381:       PetscDrawRectangle(draw,binLeft,ymin,binRight,bins[i],bcolor,bcolor,bcolor,bcolor);
382:       if (color == PETSC_DRAW_ROTATE && bins[i]) bcolor++; if (bcolor > 31) bcolor = 2;
383:       PetscDrawLine(draw,binLeft,ymin,binLeft,bins[i],PETSC_DRAW_BLACK);
384:       PetscDrawLine(draw,binRight,ymin,binRight,bins[i],PETSC_DRAW_BLACK);
385:       PetscDrawLine(draw,binLeft,bins[i],binRight,bins[i],PETSC_DRAW_BLACK);
386:     }
387:     PetscDrawHGSetNumberBins(hist, numBinsOld);
388:   }
389:   PetscDrawSynchronizedFlush(draw);
390:   PetscDrawPause(draw);
391:   return(0);
392: }

396: /*@
397:   PetscDrawHGPrint - Prints the histogram information.

399:   Not collective

401:   Input Parameter:
402: . hist - The histogram context

404:   Level: beginner

406: .keywords:  draw, histogram
407: @*/
408: PetscErrorCode  PetscDrawHGPrint(PetscDrawHG hist)
409: {
410:   PetscReal      xmax,xmin,*bins,*values,binSize,binLeft,binRight,mean,var;
412:   PetscInt       numBins,numBinsOld,numValues,initSize,i,p;

416:   if ((hist->xmin > hist->xmax) || (hist->ymin >= hist->ymax)) return(0);
417:   if (hist->numValues < 1) return(0);

419:   xmax      = hist->xmax;
420:   xmin      = hist->xmin;
421:   numValues = hist->numValues;
422:   values    = hist->values;
423:   mean      = 0.0;
424:   var       = 0.0;
425:   if (xmax == xmin) {
426:     /* Calculate number of points in the bin */
427:     bins    = hist->bins;
428:     bins[0] = 0.;
429:     for(p = 0; p < numValues; p++) {
430:       if (values[p] == xmin) bins[0]++;
431:       mean += values[p];
432:       var  += values[p]*values[p];
433:     }
434:     /* Draw bins */
435:     PetscPrintf(((PetscObject)hist)->comm, "Bin %2d (%6.2g - %6.2g): %.0g\n", 0, xmin, xmax, bins[0]);
436:   } else {
437:     numBins    = hist->numBins;
438:     numBinsOld = hist->numBins;
439:     if (hist->integerBins && (((int) xmax - xmin) + 1.0e-05 > xmax - xmin)) {
440:       initSize = (int) ((int) xmax - xmin)/numBins;
441:       while (initSize*numBins != (int) xmax - xmin) {
442:         initSize = PetscMax(initSize - 1, 1);
443:         numBins  = (int) ((int) xmax - xmin)/initSize;
444:         PetscDrawHGSetNumberBins(hist, numBins);
445:       }
446:     }
447:     binSize = (xmax - xmin)/numBins;
448:     bins    = hist->bins;

450:     /* Calculate number of points in each bin */
451:     PetscMemzero(bins, numBins * sizeof(PetscReal));
452:     for (i = 0; i < numBins; i++) {
453:       binLeft   = xmin + binSize*i;
454:       binRight  = xmin + binSize*(i+1);
455:       for(p = 0; p < numValues; p++) {
456:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
457:         /* Handle last bin separately */
458:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
459:         if (!i) {
460:           mean += values[p];
461:           var  += values[p]*values[p];
462:         }
463:       }
464:     }
465:     /* Draw bins */
466:     for (i = 0; i < numBins; i++) {
467:       binLeft   = xmin + binSize*i;
468:       binRight  = xmin + binSize*(i+1);
469:       PetscPrintf(((PetscObject)hist)->comm, "Bin %2d (%6.2g - %6.2g): %.0g\n", i, binLeft, binRight, bins[i]);
470:     }
471:     PetscDrawHGSetNumberBins(hist, numBinsOld);
472:   }

474:   if (hist->calcStats) {
475:     mean /= numValues;
476:     if (numValues > 1) {
477:       var = (var - numValues*mean*mean) / (numValues-1);
478:     } else {
479:       var = 0.0;
480:     }
481:     PetscPrintf(((PetscObject)hist)->comm, "Mean: %G  Var: %G\n", mean, var);
482:     PetscPrintf(((PetscObject)hist)->comm, "Total: %d\n", numValues);
483:   }
484:   return(0);
485: }
486: 
489: /*@
490:   PetscDrawHGSetColor - Sets the color the bars will be drawn with.

492:   Not Collective (ignored except on processor 0 of PetscDrawHG)

494:   Input Parameters:
495: + hist - The histogram context
496: - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a 
497:           different color

499:   Level: intermediate

501: @*/
502: PetscErrorCode  PetscDrawHGSetColor(PetscDrawHG hist, int color)
503: {
506:   hist->color = color;
507:   return(0);
508: }

512: /*@
513:   PetscDrawHGSetLimits - Sets the axis limits for a histogram. If more
514:   points are added after this call, the limits will be adjusted to
515:   include those additional points.

517:   Not Collective (ignored except on processor 0 of PetscDrawHG)

519:   Input Parameters:
520: + hist - The histogram context
521: - x_min,x_max,y_min,y_max - The limits

523:   Level: intermediate

525:   Concepts: histogram^setting axis
526: @*/
527: PetscErrorCode  PetscDrawHGSetLimits(PetscDrawHG hist, PetscReal x_min, PetscReal x_max, int y_min, int y_max)
528: {
531:   hist->xmin = x_min;
532:   hist->xmax = x_max;
533:   hist->ymin = y_min;
534:   hist->ymax = y_max;
535:   return(0);
536: }

540: /*@
541:   PetscDrawHGCalcStats - Turns on calculation of descriptive statistics

543:   Not collective

545:   Input Parameters:
546: + hist - The histogram context
547: - calc - Flag for calculation

549:   Level: intermediate

551: .keywords:  draw, histogram, statistics

553: @*/
554: PetscErrorCode  PetscDrawHGCalcStats(PetscDrawHG hist, PetscTruth calc)
555: {
558:   hist->calcStats = calc;
559:   return(0);
560: }

564: /*@
565:   PetscDrawHGIntegerBins - Turns on integer width bins

567:   Not collective

569:   Input Parameters:
570: + hist - The histogram context
571: - ints - Flag for integer width bins

573:   Level: intermediate

575: .keywords:  draw, histogram, statistics
576: @*/
577: PetscErrorCode  PetscDrawHGIntegerBins(PetscDrawHG hist, PetscTruth ints)
578: {
581:   hist->integerBins = ints;
582:   return(0);
583: }

587: /*@C
588:   PetscDrawHGGetAxis - Gets the axis context associated with a histogram.
589:   This is useful if one wants to change some axis property, such as
590:   labels, color, etc. The axis context should not be destroyed by the
591:   application code.

593:   Not Collective (ignored except on processor 0 of PetscDrawHG)

595:   Input Parameter:
596: . hist - The histogram context

598:   Output Parameter:
599: . axis - The axis context

601:   Level: intermediate

603: @*/
604: PetscErrorCode  PetscDrawHGGetAxis(PetscDrawHG hist, PetscDrawAxis *axis)
605: {
609:   *axis = hist->axis;
610:   return(0);
611: }

615: /*@C
616:   PetscDrawHGGetDraw - Gets the draw context associated with a histogram.

618:   Not Collective, PetscDraw is parallel if PetscDrawHG is parallel

620:   Input Parameter:
621: . hist - The histogram context

623:   Output Parameter:
624: . win  - The draw context

626:   Level: intermediate

628: @*/
629: PetscErrorCode  PetscDrawHGGetDraw(PetscDrawHG hist, PetscDraw *win)
630: {
634:   *win = hist->win;
635:   return(0);
636: }