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 (--((PetscObject)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(((PetscObject)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(((PetscObject)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(((PetscObject)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(((PetscObject)hist)->comm, "Mean: %G Var: %G\n", mean, var);
495: PetscPrintf(((PetscObject)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: }