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: }