Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QualityAssessor/QualityAssessor.cpp
Go to the documentation of this file.
1 /* *****************************************************************
2  MESQUITE -- The Mesh Quality Improvement Toolkit
3 
4  Copyright 2004 Sandia Corporation and Argonne National
5  Laboratory. Under the terms of Contract DE-AC04-94AL85000
6  with Sandia Corporation, the U.S. Government retains certain
7  rights in this software.
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  (lgpl.txt) along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 
23  diachin2@llnl.gov, djmelan@sandia.gov, mbrewer@sandia.gov,
24  pknupp@sandia.gov, tleurent@mcs.anl.gov, tmunson@mcs.anl.gov
25 
26  ***************************************************************** */
35 #include "QualityAssessor.hpp"
36 #include "PatchData.hpp"
37 #include "MsqMeshEntity.hpp"
38 #include "MsqVertex.hpp"
39 #include "MsqDebug.hpp"
40 #include "MeshSet.hpp"
41 
42 #ifdef MSQ_USE_OLD_STD_HEADERS
43 # include <list.h>
44 # include <vector.h>
45 #else
46 # include <list>
47 # include <vector>
48  using namespace std;
49 #endif
50 
51 #ifdef MSQ_USE_OLD_IO_HEADERS
52 # include <iostream.h>
53 # include <iomanip.h>
54 #else
55 # include <iostream>
56 # include <iomanip>
57  using namespace std;
58 #endif
59 
60 namespace Mesquite {
61 
63 
64 QualityAssessor::QualityAssessor(string name) :
65  qualityAssessorName(name),
66  outputStream( cout ),
67  printSummary( true ),
68  stoppingMetric( assessList.end() ),
69  stoppingFunction( NO_FUNCTION )
70 {
71  MsqError err;
72  set_patch_type( PatchData::GLOBAL_PATCH, err, 0 );
73 }
74 
75 QualityAssessor::QualityAssessor(ostream& stream, string name) :
76  qualityAssessorName(name),
77  outputStream( stream ),
78  printSummary( true ),
79  stoppingMetric( assessList.end() ),
80  stoppingFunction( NO_FUNCTION )
81 {
82  MsqError err;
83  set_patch_type( PatchData::GLOBAL_PATCH, err, 0 );
84 }
85 
86 QualityAssessor::QualityAssessor( QualityMetric* metric,
87  QAFunction function,
88  MsqError& err,
89  string name ) :
90  qualityAssessorName(name),
91  outputStream( cout ),
92  printSummary( true ),
93  stoppingMetric( assessList.end() ),
94  stoppingFunction( (QAFunction)0 )
95 {
96  set_patch_type( PatchData::GLOBAL_PATCH, err, 0 );
97  add_quality_assessment( metric, function, err );
98  set_stopping_assessment( metric, function, err );
99 }
100 
101 QualityAssessor::QualityAssessor( QualityMetric* metric,
102  QAFunction function,
103  ostream& stream,
104  MsqError& err,
105  string name ) :
106  qualityAssessorName(name),
107  outputStream( stream ),
108  printSummary( true ),
109  stoppingMetric( assessList.end() ),
110  stoppingFunction( (QAFunction)0 )
111 {
112  set_patch_type( PatchData::GLOBAL_PATCH, err, 0 );
113  add_quality_assessment( metric, function, err );
114  set_stopping_assessment( metric, function, err );
115 }
116 
117 QualityAssessor::~QualityAssessor()
118  { }
119 
120 string QualityAssessor::get_QAFunction_name(
122 {
123  switch(fun){
124  case(AVERAGE):
125  return "Average ";
126  case(HISTOGRAM):
127  return "Histogram of metric values: ";
128  case(MAXIMUM):
129  return "Maximum ";
130  case(MINIMUM):
131  return "Minimum ";
132  case(RMS):
133  return "RMS ";
134  case(STDDEV):
135  return "Stan. Dev.";
136  default:
137  return "DEFAULT ";
138  };
139 }
140 
141 double QualityAssessor::Assessor::get_average() const
142 {
143  return count ? sum/count : 0;
144 }
145 
146 double QualityAssessor::Assessor::get_rms() const
147 {
148  return count ? sqrt(sqrSum/count) : 0;
149 }
150 
151 double QualityAssessor::Assessor::get_stddev() const
152 {
153  double sqr = sqrSum/count - sum*sum/((double)count*count);
154  return sqr < 0 ? 0 : sqrt(sqr);
155 }
156 
157 
167 void QualityAssessor::add_quality_assessment(QualityMetric* qm,
168  int func,
169  MsqError &/*err*/)
170 {
171  msq_std::list<Assessor>::iterator iter;
172 
173  iter = find_or_add( qm );
174  iter->funcFlags |= func;
175  if (func&HISTOGRAM)
176  iter->histogram.resize(DEFAULT_HISTOGRAM_INTERVALS+2);
177 }
178 
179 list<QualityAssessor::Assessor>::iterator QualityAssessor::find_or_add( QualityMetric* qm )
180 {
181  list<Assessor>::iterator iter;
182 
183  // If metric is already in list, find it
184  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
185  if (iter->qualMetric == qm )
186  break;
187 
188  // If metric not found in list, add it
189  if (iter == assessList.end())
190  {
191  if (qm->get_metric_type() == QualityMetric::VERTEX_BASED)
192  {
193  assessList.push_back( Assessor(qm) );
194  iter = --assessList.end();
195  }
196  else
197  {
198  assessList.push_front( Assessor(qm) );
199  iter = assessList.begin();
200  }
201  }
202 
203  return iter;
204 }
205 
206 
216 void QualityAssessor::set_stopping_assessment(QualityMetric* qm,
217  QAFunction func,
218  MsqError &err)
219 {
220  if(func==HISTOGRAM){
221  MSQ_SETERR(err)("HISTOGRAM DOES NOT GIVE A VALID RETURN VALUE", MsqError::INVALID_ARG);
222  return;
223  }
224  else if (func == NO_FUNCTION) {
225  MSQ_SETERR(err)("No function specified for stopping assessment", MsqError::INVALID_ARG);
226  return;
227  }
228 
229  stoppingMetric = find_or_add( qm );
230  stoppingFunction = func;
231 }
232 
233 
244 void QualityAssessor::add_histogram_assessment( QualityMetric* qm,
245  double min_val,
246  double max_val,
247  int intervals,
248  MsqError &err )
249 {
250  if (min_val >= max_val || intervals < 1) {
251  MSQ_SETERR(err)("Invalid histogram range.", MsqError::INVALID_ARG );
252  return;
253  }
254 
255  list<Assessor>::iterator assessor = find_or_add( qm );
256  assessor->funcFlags |= QualityAssessor::HISTOGRAM;
257  assessor->histMin = min_val;
258  assessor->histMax = max_val;
259  assessor->histogram.resize( intervals + 2 );
260 }
261 
262 
263 
275 double QualityAssessor::loop_over_mesh(MeshSet &ms, MsqError& err)
276 {
277  // Clear out any previous data
278  reset_data();
279 
280  // Check for any metrics for which a histogram is to be
281  // calculated and for which the user has not specified
282  // minimum and maximum values.
283  // Element-based metrics are first in list, followed
284  // by vertex-based metrics. Find first vertex-based
285  // metric also such that element metrics go from
286  // assessList.begin() to elem_end and vertex metrics
287  // go from elem_end to assessList.end()
288  list<Assessor>::iterator elem_end = assessList.end();
289  bool need_second_pass_for_elements = false;
290  bool need_second_pass_for_vertices = false;
291  list<Assessor>::iterator iter;
292  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
293  {
294  if (iter->get_metric()->get_metric_type() == QualityMetric::VERTEX_BASED)
295  break;
296 
297  if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
298  need_second_pass_for_elements = true;
299  }
300  elem_end = iter;
301  for ( ; iter != assessList.end(); ++iter)
302  {
303  if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
304  need_second_pass_for_vertices = true;
305  }
306 
307  list<Assessor> histogramList;
308 
309  // Do element-based metrics
310  if (assessList.begin() != elem_end)
311  {
312  bool first_pass = false;
313  do { // might need to loop twice to calculate histograms
314  first_pass = !first_pass;
315 
316  PatchData* pd;
317  PatchData local_patch;
318  no_culling_method();
319  bool more_mesh = true;
320  if (get_global_patch() == 0) {
321  pd = &local_patch;
322  more_mesh=ms.get_next_patch(*pd, this, err); MSQ_ERRZERO(err);
323  }
324  else {
325  pd = get_global_patch();
326  }
327 
328  //until there are no more patches
329  //there is another get_next_patch at
330  //the end of this loop
331  while (more_mesh)
332  {
333  for (unsigned i = 0; i < pd->num_elements(); ++i)
334  {
335  for (iter = assessList.begin(); iter != elem_end; ++iter)
336  {
337  // If first pass, get values for all metrics
338  if (first_pass)
339  {
340  double value;
341  bool valid = iter->get_metric()->evaluate_element( *pd,
342  &pd->element_by_index(i),
343  value, err );
344  MSQ_ERRZERO(err);
345 
346  iter->add_value(value);
347  if (!valid)
348  iter->add_invalid_value();
349  }
350  // If second pass, only do metrics for which the
351  // histogram hasn't been calculated yet.
352  else if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
353  {
354  double value;
355  iter->get_metric()->evaluate_element( *pd,
356  &pd->element_by_index(i),
357  value, err );
358  MSQ_ERRZERO(err);
359 
360  iter->add_hist_value(value);
361  }
362  }
363  }
364 
365  // If dealing with local patches, get next element group (PatchData object)
366  if (get_patch_type() != PatchData::GLOBAL_PATCH)
367  more_mesh = ms.get_next_patch(*pd,this, err); MSQ_ERRZERO(err);
368  //Michael:: Since we are doing global right now:
369  //Remove this when no longer doing global
370  more_mesh=false;
371  }
372 
373  // Fix up any histogram ranges which were calculated
374  for (iter = assessList.begin(); iter != elem_end; ++iter)
375  if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
376  if (first_pass)
377  iter->calculate_histogram_range();
378 // Uncomment the following to have the QA keep the first
379 // calculated histogram range for all subsequent iterations.
380 // else
381 // iter->haveHistRange = true;
382 
383  } while (first_pass && need_second_pass_for_elements);
384  }
385 
386 
387  // Do vertex-based metrics
388  if (assessList.end() != elem_end)
389  {
390  bool first_pass = false;
391  do { // might need to loop twice to calculate histograms
392  first_pass = !first_pass;
393 
394  //construct the patch we will send to get_next_patch
395  PatchData* pd;
396  PatchData local_patch;
397  no_culling_method();
398  bool more_mesh = true;
399  if (get_global_patch() == 0) {
400  pd = &local_patch;
401  more_mesh=ms.get_next_patch(*pd, this, err); MSQ_ERRZERO(err);
402  }
403  else {
404  pd = get_global_patch();
405  }
406 
407  //until there are no more patches
408  //there is another get_next_patch at
409  //the end of this loop
410  while (more_mesh)
411  {
412  for (unsigned i = 0; i < pd->num_vertices(); ++i)
413  {
414  for (iter = elem_end; iter != assessList.end(); ++iter)
415  {
416  // If first pass, get values for all metrics
417  if (first_pass)
418  {
419  double value;
420  bool valid = iter->get_metric()->evaluate_vertex( *pd,
421  &pd->vertex_by_index(i),
422  value, err );
423  MSQ_ERRZERO(err);
424 
425  iter->add_value(value);
426  if (!valid)
427  iter->add_invalid_value();
428  }
429  // If second pass, only do metrics for which the
430  // histogram hasn't been calculated yet.
431  else if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
432  {
433  double value;
434  iter->get_metric()->evaluate_vertex( *pd,
435  &pd->vertex_by_index(i),
436  value, err );
437  MSQ_ERRZERO(err);
438 
439  iter->add_hist_value(value);
440  }
441  }
442  }
443 
444  if (get_patch_type() != PatchData::GLOBAL_PATCH)
445  more_mesh = ms.get_next_patch(*pd,this, err); MSQ_ERRZERO(err);
446  //Michael:: Since we are doing global right now:
447  //Remove this when no longer doing global
448  more_mesh=false;
449  }
450 
451  // Fix up any histogram ranges which were calculated
452  for (iter = elem_end; iter != assessList.end(); ++iter)
453  if (iter->funcFlags&HISTOGRAM && !iter->haveHistRange)
454  if (first_pass)
455  iter->calculate_histogram_range();
456 // Uncomment the following to have the QA keep the first
457 // calculated histogram range for all subsequent iterations.
458 // else
459 // iter->haveHistRange = true;
460 
461  } while (first_pass && need_second_pass_for_vertices);
462  }
463 
464 
465  // Print results, if requested
466  if (printSummary)
467  print_summary( this->outputStream );
468 
469  // If no stopping function, just return zero
470  if (!stoppingFunction)
471  return 0.0;
472 
473  // Otherwise return requested value
474  if (stoppingFunction & STDDEV)
475  return stoppingMetric->get_stddev();
476  else if (stoppingFunction & AVERAGE)
477  return stoppingMetric->get_average();
478  else if (stoppingFunction & MAXIMUM)
479  return stoppingMetric->get_maximum();
480  else if (stoppingFunction & MINIMUM)
481  return stoppingMetric->get_minimum();
482  else if (stoppingFunction & RMS)
483  return stoppingMetric->get_rms();
484  else
485  MSQ_SETERR(err)("Invalid stopping function for QualityAssessor",
486  MsqError::INVALID_STATE);
487 
488  return 0.0;
489 }
490 
491 bool QualityAssessor::invalid_elements( ) const
492 {
493  bool result = false;
494  msq_std::list<Assessor>::const_iterator iter;
495  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
496  if (iter->get_invalid_element_count())
497  result = true;
498  return result;
499 }
500 
501 void QualityAssessor::reset_data()
502 {
503  msq_std::list<Assessor>::iterator iter;
504  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
505  iter->reset_data();
506 }
507 
508 QualityAssessor::Assessor::Assessor( QualityMetric* metric )
509  : qualMetric(metric),
510  funcFlags(0),
511  haveHistRange(false),
512  histMin(1.0),
513  histMax(0.0)
514 {
515  reset_data();
516 }
517 
519 {
520  msq_std::list<Assessor>::const_iterator iter;
521  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
522  if (iter->get_metric() == metric)
523  return &*iter;
524  return 0;
525 }
526 
527 
528 void QualityAssessor::Assessor:: get_histogram( double& lower_bound_out,
529  double& upper_bound_out,
530  msq_std::vector<int>& counts_out,
531  MsqError& err ) const
532 {
533  if ( !(funcFlags & QualityAssessor::HISTOGRAM) )
534  {
535  MSQ_SETERR(err)("No histogram calculated.", MsqError::INVALID_STATE);
536  return;
537  }
538 
539  if (haveHistRange) {
540  lower_bound_out = histMin;
541  upper_bound_out = histMax;
542  }
543  else {
544  lower_bound_out = minimum;
545  upper_bound_out = maximum;
546  }
547 
548  counts_out = histogram;
549 }
550 
552 {
553  count = 0;
554  sum = 0;
555  maximum = -HUGE_VAL;
556  minimum = HUGE_VAL;
557  sqrSum = 0;
558  numInvalid = 0;
559  memset( &histogram[0], 0, sizeof(int)*histogram.size() );
560 }
561 
562 void QualityAssessor::Assessor::add_value( double metric_value )
563 {
564  sum += metric_value;
565  sqrSum += metric_value*metric_value;
566  if (metric_value > maximum)
567  maximum = metric_value;
568  if (metric_value < minimum)
569  minimum = metric_value;
570  // Only add value to histogram data from this function if
571  // the user has specified the range. If user has not
572  // specified the range, QualityAssessor will call add_hist_value()
573  // directly once the range has been calculated.
574  if (funcFlags & QualityAssessor::HISTOGRAM && haveHistRange)
575  add_hist_value( metric_value );
576 
577  ++count;
578 }
579 
581 {
582  ++numInvalid;
583 }
584 
585 void QualityAssessor::Assessor::add_hist_value( double metric_value )
586 {
587  // Width of one interval in histogram
588  double step = (histMax - histMin) / (histogram.size()-2);
589 
590  // First and last values in array are counts of values
591  // outside the user-specified range of the histogram
592  // (below and above, respectively.)
593  if (metric_value < histMin)
594  ++histogram[0];
595  else if (metric_value > histMax)
596  ++histogram[histogram.size()-1];
597  else
598  {
599  // Calculate which interval the value is in. Add one
600  // because first entry is for values below user-specifed
601  // minimum value for histogram.
602  unsigned cell;
603  if (step > DBL_EPSILON)
604  cell = 1+(unsigned)((metric_value - histMin) / step);
605  else
606  cell = 1;
607 
608  // If value exactly equals maximum value, put in last
609  // valid interval, not the count of values above the
610  // maximum.
611  if (cell + 1 == histogram.size())
612  --cell;
613  // Add value to interval.
614  ++histogram[cell];
615  }
616 }
617 
619 {
620  double step = (maximum - minimum) / (histogram.size() - 2);
621  double size = pow( 10, ceil(log10(step)) );
622  histMin = size * floor( minimum / size );
623  histMax = size * ceil( maximum / size );
624 }
625 
626 void QualityAssessor::print_summary( msq_stdio::ostream& stream ) const
627 {
628  const int NAMEW = 19; // Width of name column in table output
629  const int NUMW = 12; // Width of value columns in table output
630 
631  // Print title
632  stream << msq_stdio::endl
633  << "************** "
635  << " Summary **************"
636  << msq_stdio::endl
637  << msq_stdio::endl;
638 
639  // Get union of function flags, and list any metrics with invalid values
640  msq_std::list<Assessor>::const_iterator iter;
641  unsigned flags = 0;
642  int invalid_count = 0;
643  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
644  {
645  flags |= (iter->funcFlags & ~HISTOGRAM);
646 
647  if (iter->get_invalid_element_count())
648  {
649  ++invalid_count;
650 
651  stream << " " << iter->get_invalid_element_count()
652  << " OF " << iter->get_count()
653  << " VALUES ARE INVALID FOR "
654  << iter->get_metric()->get_name()
655  << msq_stdio::endl << msq_stdio::endl;
656  }
657  }
658 
659  if (0 == invalid_count) {
660  stream << " No invalid values for any metric."
661  << msq_stdio::endl << msq_stdio::endl;
662  }
663 
664  // If printing any values
665  if (flags)
666  {
667  // Print table header line
668  stream << msq_stdio::setw(NAMEW) << "metric";
669  if (flags & MINIMUM)
670  stream << msq_stdio::setw(NUMW) << "minimum";
671  if (flags & AVERAGE)
672  stream << msq_stdio::setw(NUMW) << "average";
673  if (flags & RMS)
674  stream << msq_stdio::setw(NUMW) << "rms";
675  if (flags & MAXIMUM)
676  stream << msq_stdio::setw(NUMW) << "maximum";
677  if (flags & STDDEV)
678  stream << msq_stdio::setw(NUMW) << "std.dev.";
679  stream << msq_stdio::endl;
680 
681  // Print out values for each assessor
682  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
683  {
684  // If no output (other than histogram) for this metric, skip it
685  if (!(iter->funcFlags & ~HISTOGRAM))
686  continue;
687 
688  // Name column
689  stream << msq_stdio::setw(NAMEW) << iter->get_metric()->get_name();
690 
691  // Value columns
692  if (flags & MINIMUM)
693  {
694  if (iter->funcFlags & MINIMUM)
695  stream << msq_stdio::setw(NUMW) << iter->get_minimum();
696  else
697  stream << msq_stdio::setw(NUMW) << " ";
698  }
699  if (flags & AVERAGE)
700  {
701  if (iter->funcFlags & AVERAGE)
702  stream << msq_stdio::setw(NUMW) << iter->get_average();
703  else
704  stream << msq_stdio::setw(NUMW) << " ";
705  }
706  if (flags & RMS)
707  {
708  if (iter->funcFlags & RMS)
709  stream << msq_stdio::setw(NUMW) << iter->get_rms();
710  else
711  stream << msq_stdio::setw(NUMW) << " ";
712  }
713  if (flags & MAXIMUM)
714  {
715  if (iter->funcFlags & MAXIMUM)
716  stream << msq_stdio::setw(NUMW) << iter->get_maximum();
717  else
718  stream << msq_stdio::setw(NUMW) << " ";
719  }
720  if (flags & STDDEV)
721  {
722  if (iter->funcFlags & STDDEV)
723  stream << msq_stdio::setw(NUMW) << iter->get_stddev();
724  else
725  stream << msq_stdio::setw(NUMW) << " ";
726  }
727  stream << msq_stdio::endl;
728  } // for (assessList)
729  } // if (flags)
730 
731  for (iter = assessList.begin(); iter != assessList.end(); ++iter)
732  if (iter->funcFlags & HISTOGRAM)
733  iter->print_histogram( stream );
734 }
735 
736 
737 void QualityAssessor::Assessor::print_histogram( msq_stdio::ostream& stream ) const
738 {
739  // Portability notes:
740  // Use log10 rather than log10f because the float variations require
741  // including platform-dependent headers on some platforms.
742  // Explicitly cast log10 argument to double because some platforms
743  // have overloaded float and double variations in C++ making an
744  // implicit cast from an integer ambiguous.
745 
746  const char GRAPH_CHAR = '='; // Character used to create bar graphs
747  const int FLOATW = 12; // Width of floating-point output
748  const int GRAPHW = 50; // Width of bar graph
749 
750  // range is either user-specified (histMin & histMax) or
751  // calculated (minimum & maximum)
752  double min, max;
753  //if (haveHistRange) {
754  min = histMin;
755  max = histMax;
756  //}
757  //else {
758  // min = minimum;
759  // max = maximum;
760  //}
761  // Witdh of one interval of histogram
762  double step = (max - min) / (histogram.size()-2);
763 
764  // Find maximum value for an interval of the histogram
765  unsigned i;
766  int max_interval = 1;
767  for (i = 0; i < histogram.size(); ++i)
768  if (histogram[i] > max_interval)
769  max_interval = histogram[i];
770 
771  if (0 == max_interval)
772  return; // no data
773 
774  // Calculate width of field containing counts for
775  // histogram intervals (log10(max_interval)).
776  int num_width = 1;
777  for (int temp = max_interval; temp > 0; temp /= 10)
778  ++num_width;
779 
780  // Create an array of bar graph characters for use in output
781  char graph_chars[GRAPHW+1];
782  memset( graph_chars, GRAPH_CHAR, sizeof(graph_chars) );
783 
784  // Check if bar-graph should be linear or log10 plot
785  // Do log plot if standard deviation is less that 1.5
786  // histogram intervals.
787  bool log_plot = false;
788  double stddev = get_stddev();
789  if (stddev > 0 && stddev < 2.0*step)
790  {
791  int new_interval = (int)(log10((double)(1+max_interval)));
792  if (new_interval > 0) {
793  log_plot = true;
794  max_interval = new_interval;
795  }
796  }
797 
798 
799  // Write title
800  stream << msq_stdio::endl << " " << get_metric()->get_name() << " histogram:";
801  if (log_plot)
802  stream << " (log10 plot)";
803  stream << msq_stdio::endl;
804 
805 
806  // For each interval of histogram
807  for (i = 0; i < histogram.size(); ++i)
808  {
809  // First value is the count of the number of values that
810  // were below the minimum value of the histogram.
811  if (0 == i)
812  {
813  if (0 == histogram[i])
814  continue;
815  stream << setw(FLOATW) << "under min";
816  }
817  // Last value is the count of the number of values that
818  // were above the maximum value of the histogram.
819  else if (i+1 == histogram.size())
820  {
821  if (0 == histogram[i])
822  continue;
823  stream << setw(FLOATW) << "over max";
824  }
825  // Anything else is a valid interval of the histogram.
826  // Print the lower bound for each interval.
827  else
828  {
829  stream << " " << setw(FLOATW) << min + (i-1)*step;
830  }
831 
832  // Print interval count.
833  stream << ": " << setw(num_width) << histogram[i] << ": ";
834 
835  // Print bar graph
836 
837  // First calculate the number of characters to output
838  int num_graph;
839  if (log_plot)
840  num_graph = GRAPHW * (int)log10((double)(1+histogram[i])) / max_interval;
841  else
842  num_graph = GRAPHW * histogram[i] / max_interval;
843 
844  // print num_graph characters using array of fill characters.
845  graph_chars[num_graph] = '\0';
846  stream << graph_chars << msq_stdio::endl;
847  graph_chars[num_graph] = GRAPH_CHAR;
848  }
849 
850  stream << msq_stdio::endl;
851 }
852 
853 
854 
855 } //namespace Mesquite
#define MSQ_ERRZERO(err)
Return zero/NULL on error.
MsqVertex & vertex_by_index(size_t index)
Returns the start of the vertex-&gt;element array.
Used to hold the error state and return it to the application.
Base class for concrete quality metrics.
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
void print_histogram(msq_stdio::ostream &) const
Print the histogram.
double sqrt(double d)
Definition: double.h:73
#define MAXIMUM
Definition: vinci_lass.c:25
void print_summary(msq_stdio::ostream &stream) const
Print accumulated summary data to specified stream.
size_t num_elements() const
number of elements in the Patch.
#define MSQ_SETERR(err)
Macro to set error - use err.clear() to clear.
blockLoc i
Definition: read.cpp:79
CImg< _cimg_Tfloat > log10(const CImg< T > &instance)
Definition: CImg.h:6026
size_t num_vertices() const
number of vertices in the patch.
MsqMeshEntity & element_by_index(size_t index)
Vector_n min(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:346
void get_histogram(double &lower_bound_out, double &upper_bound_out, msq_std::vector< int > &counts_out, MsqError &err) const
Get historgram of data, if calculated.
object is in an invalid state
msq_std::list< Assessor > assessList
List of quality metrics and corresponding data.
T sqr(const T val)
Return the square of a number.
Definition: CImg.h:4717
void add_hist_value(double metric_value)
Add a value to the hisogram data.
void add_value(double metric_value)
Add a value to the running counts.
Definition: metric.h:35
double pow(double value, const Exponent &exp)
The MeshSet class stores one or more Mesquite::Mesh pointers and manages access to the mesh informati...
void calculate_histogram_range()
If range of histogram has not yet been determined, calculate it from the min/max values.
const Assessor * get_results(QualityMetric *metric) const
Request summary data for a specific QualityMetric This method allows the application to request the s...
bool get_next_patch(PatchData &pd, PatchDataUser *pd_user, MsqError &err)
Gets the next PatchData.