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 petsc.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:    Contributed by: Matthew Knepley

 49:    Concepts: histogram^creating

 51: .seealso: PetscDrawHGDestroy()

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

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

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

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

101:    Input Parameter:
102: +  hist - The histogram context.
103: -  dim  - The number of curves.

105:    Level: intermediate

107:   Contributed by: Matthew Knepley

109:    Concepts: histogram^setting number of bins

111: @*/
112: PetscErrorCode  PetscDrawHGSetNumberBins(PetscDrawHG hist, int bins)
113: {

118:   if (hist->maxBins < bins) {
119:     PetscFree(hist->bins);
120:     PetscMalloc(bins * sizeof(PetscReal), &hist->bins);
121:     PetscLogObjectMemory(hist, (bins - hist->maxBins) * sizeof(PetscReal));
122:     hist->maxBins = bins;
123:   }
124:   hist->numBins = bins;
125:   return(0);
126: }

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

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

135:   Input Parameter:
136: . hist - The histogram context.

138:   Level: intermediate

140:   Contributed by: Matthew Knepley

142:   Concepts: histogram^resetting
143: @*/
144: PetscErrorCode  PetscDrawHGReset(PetscDrawHG hist)
145: {
148:   hist->xmin      = PETSC_MAX;
149:   hist->xmax      = PETSC_MIN;
150:   hist->ymin      = 0;
151:   hist->ymax      = 0;
152:   hist->numValues = 0;
153:   return(0);
154: }

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

161:   Collective over PetscDrawHG

163:   Input Parameter:
164: . hist - The histogram context

166:   Level: intermediate

168:   Contributed by: Matthew Knepley

170: .seealso:  PetscDrawHGCreate()
171: @*/
172: PetscErrorCode  PetscDrawHGDestroy(PetscDrawHG hist)
173: {


179:   if (--hist->refct > 0) return(0);
180:   if (hist->axis) {
181:     PetscDrawAxisDestroy(hist->axis);
182:   }
183:   PetscDrawDestroy(hist->win);
184:   PetscFree(hist->bins);
185:   PetscFree(hist->values);
186:   PetscHeaderDestroy(hist);
187:   return(0);
188: }

192: /*@
193:   PetscDrawHGAddValue - Adds another value to the histogram.

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

197:   Input Parameters:
198: + hist  - The histogram
199: - value - The value 

201:   Level: intermediate

203:   Contributed by: Matthew Knepley

205:   Concepts: histogram^adding values

207: .seealso: PetscDrawHGAddValues()
208: @*/
209: PetscErrorCode  PetscDrawHGAddValue(PetscDrawHG hist, PetscReal value)
210: {
213:   /* Allocate more memory if necessary */
214:   if (hist->numValues >= hist->maxValues) {
215:     PetscReal *tmp;

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

258:   hist->values[hist->numValues++] = value;
259:   return(0);
260: }

264: /*@
265:   PetscDrawHGDraw - Redraws a histogram.

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

269:   Input Parameter:
270: . hist - The histogram context

272:   Level: intermediate

274:   Contributed by: Matthew Knepley
275: @*/
276: PetscErrorCode  PetscDrawHGDraw(PetscDrawHG hist)
277: {
278:   PetscDraw      draw = hist->win;
279:   PetscTruth     isnull;
280:   PetscReal      xmin,xmax,ymin,ymax,*bins,*values,binSize,binLeft,binRight,maxHeight,mean,var;
281:   char           title[256];
282:   char           xlabel[256];
283:   int            numBins,numBinsOld,numValues,initSize,i,p,bcolor,color;

288:   PetscTypeCompare((PetscObject) draw, PETSC_DRAW_NULL, &isnull);
289:   if (isnull) return(0);
290:   if ((hist->xmin >= hist->xmax) || (hist->ymin >= hist->ymax)) return(0);
291:   if (hist->numValues < 1) return(0);

293: #if 0
294:   MPI_Comm_rank(hist->comm,&rank);
295:   if (rank) return(0);
296: #endif

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

357:     PetscMemzero(bins, numBins * sizeof(PetscReal));
358:     maxHeight = 0;
359:     for (i = 0; i < numBins; i++) {
360:       binLeft   = xmin + binSize*i;
361:       binRight  = xmin + binSize*(i+1);
362:       for(p = 0; p < numValues; p++) {
363:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
364:         /* Handle last bin separately */
365:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
366:         if (!i) {
367:           mean += values[p];
368:           var  += values[p]*values[p];
369:         }
370:       }
371:       maxHeight = PetscMax(maxHeight, bins[i]);
372:     }
373:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;

375:     PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax);
376:     if (hist->calcStats) {
377:       mean /= numValues;
378:       if (numValues > 1) {
379:         var = (var - numValues*mean*mean) / (numValues-1);
380:       } else {
381:         var = 0.0;
382:       }
383:       sprintf(title, "Mean: %g  Var: %g", (double)mean, (double)var);
384:       sprintf(xlabel, "Total: %d", numValues);
385:       PetscDrawAxisSetLabels(hist->axis, title, xlabel, PETSC_NULL);
386:     }
387:     PetscDrawAxisDraw(hist->axis);
388:     /* Draw bins */
389:     for (i = 0; i < numBins; i++) {
390:       binLeft   = xmin + binSize*i;
391:       binRight  = xmin + binSize*(i+1);
392:       PetscDrawRectangle(draw,binLeft,ymin,binRight,bins[i],bcolor,bcolor,bcolor,bcolor);
393:       if (color == PETSC_DRAW_ROTATE && bins[i]) bcolor++; if (bcolor > 31) bcolor = 2;
394:       PetscDrawLine(draw,binLeft,ymin,binLeft,bins[i],PETSC_DRAW_BLACK);
395:       PetscDrawLine(draw,binRight,ymin,binRight,bins[i],PETSC_DRAW_BLACK);
396:       PetscDrawLine(draw,binLeft,bins[i],binRight,bins[i],PETSC_DRAW_BLACK);
397:     }
398:     PetscDrawHGSetNumberBins(hist, numBinsOld);
399:   }
400:   PetscDrawSynchronizedFlush(draw);
401:   PetscDrawPause(draw);
402:   return(0);
403: }

407: /*@
408:   PetscDrawHGPrint - Prints the histogram information.

410:   Not collective

412:   Input Parameter:
413: . hist - The histogram context

415:   Level: beginner

417:   Contributed by: Matthew Knepley

419: .keywords:  draw, histogram
420: @*/
421: PetscErrorCode  PetscDrawHGPrint(PetscDrawHG hist)
422: {
423:   PetscReal      xmax,xmin,*bins,*values,binSize,binLeft,binRight,mean,var;
425:   int            numBins,numBinsOld,numValues,initSize,i,p;

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

432:   xmax      = hist->xmax;
433:   xmin      = hist->xmin;
434:   numValues = hist->numValues;
435:   values    = hist->values;
436:   mean      = 0.0;
437:   var       = 0.0;
438:   if (xmax == xmin) {
439:     /* Calculate number of points in the bin */
440:     bins    = hist->bins;
441:     bins[0] = 0;
442:     for(p = 0; p < numValues; p++) {
443:       if (values[p] == xmin) bins[0]++;
444:       mean += values[p];
445:       var  += values[p]*values[p];
446:     }
447:     /* Draw bins */
448:     PetscPrintf(hist->comm, "Bin %2d (%6.2g - %6.2g): %.0g\n", 0, xmin, xmax, bins[0]);
449:   } else {
450:     numBins    = hist->numBins;
451:     numBinsOld = hist->numBins;
452:     if (hist->integerBins && (((int) xmax - xmin) + 1.0e-05 > xmax - xmin)) {
453:       initSize = (int) ((int) xmax - xmin)/numBins;
454:       while (initSize*numBins != (int) xmax - xmin) {
455:         initSize = PetscMax(initSize - 1, 1);
456:         numBins  = (int) ((int) xmax - xmin)/initSize;
457:         PetscDrawHGSetNumberBins(hist, numBins);
458:       }
459:     }
460:     binSize = (xmax - xmin)/numBins;
461:     bins    = hist->bins;

463:     /* Calculate number of points in each bin */
464:     PetscMemzero(bins, numBins * sizeof(PetscReal));
465:     for (i = 0; i < numBins; i++) {
466:       binLeft   = xmin + binSize*i;
467:       binRight  = xmin + binSize*(i+1);
468:       for(p = 0; p < numValues; p++) {
469:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
470:         /* Handle last bin separately */
471:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
472:         if (!i) {
473:           mean += values[p];
474:           var  += values[p]*values[p];
475:         }
476:       }
477:     }
478:     /* Draw bins */
479:     for (i = 0; i < numBins; i++) {
480:       binLeft   = xmin + binSize*i;
481:       binRight  = xmin + binSize*(i+1);
482:       PetscPrintf(hist->comm, "Bin %2d (%6.2g - %6.2g): %.0g\n", i, binLeft, binRight, bins[i]);
483:     }
484:     PetscDrawHGSetNumberBins(hist, numBinsOld);
485:   }

487:   if (hist->calcStats) {
488:     mean /= numValues;
489:     if (numValues > 1) {
490:       var = (var - numValues*mean*mean) / (numValues-1);
491:     } else {
492:       var = 0.0;
493:     }
494:     PetscPrintf(hist->comm, "Mean: %G  Var: %G\n", mean, var);
495:     PetscPrintf(hist->comm, "Total: %d\n", numValues);
496:   }
497:   return(0);
498: }
499: 
502: /*@
503:   PetscDrawHGSetColor - Sets the color the bars will be drawn with.

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

507:   Input Parameters:
508: + hist - The histogram context
509: - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a 
510:           different color

512:   Level: intermediate

514: @*/
515: PetscErrorCode  PetscDrawHGSetColor(PetscDrawHG hist, int color)
516: {
519:   hist->color = color;
520:   return(0);
521: }

525: /*@
526:   PetscDrawHGSetLimits - Sets the axis limits for a histogram. If more
527:   points are added after this call, the limits will be adjusted to
528:   include those additional points.

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

532:   Input Parameters:
533: + hist - The histogram context
534: - x_min,x_max,y_min,y_max - The limits

536:   Level: intermediate

538:   Contributed by: Matthew Knepley

540:   Concepts: histogram^setting axis
541: @*/
542: PetscErrorCode  PetscDrawHGSetLimits(PetscDrawHG hist, PetscReal x_min, PetscReal x_max, int y_min, int y_max)
543: {
546:   hist->xmin = x_min;
547:   hist->xmax = x_max;
548:   hist->ymin = y_min;
549:   hist->ymax = y_max;
550:   return(0);
551: }

555: /*@
556:   PetscDrawHGCalcStats - Turns on calculation of descriptive statistics

558:   Not collective

560:   Input Parameters:
561: + hist - The histogram context
562: - calc - Flag for calculation

564:   Level: intermediate

566:   Contributed by: Matthew Knepley

568: .keywords:  draw, histogram, statistics

570: @*/
571: PetscErrorCode  PetscDrawHGCalcStats(PetscDrawHG hist, PetscTruth calc)
572: {
575:   hist->calcStats = calc;
576:   return(0);
577: }

581: /*@
582:   PetscDrawHGIntegerBins - Turns on integer width bins

584:   Not collective

586:   Input Parameters:
587: + hist - The histogram context
588: - ints - Flag for integer width bins

590:   Level: intermediate

592:   Contributed by: Matthew Knepley

594: .keywords:  draw, histogram, statistics
595: @*/
596: PetscErrorCode  PetscDrawHGIntegerBins(PetscDrawHG hist, PetscTruth ints)
597: {
600:   hist->integerBins = ints;
601:   return(0);
602: }

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

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

614:   Input Parameter:
615: . hist - The histogram context

617:   Output Parameter:
618: . axis - The axis context

620:   Level: intermediate

622:   Contributed by: Matthew Knepley
623: @*/
624: PetscErrorCode  PetscDrawHGGetAxis(PetscDrawHG hist, PetscDrawAxis *axis)
625: {
629:   *axis = hist->axis;
630:   return(0);
631: }

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

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

640:   Input Parameter:
641: . hist - The histogram context

643:   Output Parameter:
644: . win  - The draw context

646:   Level: intermediate

648:   Contributed by: Matthew Knepley
649: @*/
650: PetscErrorCode  PetscDrawHGGetDraw(PetscDrawHG hist, PetscDraw *win)
651: {
655:   *win = hist->win;
656:   return(0);
657: }