Reference documentation for deal.II version 9.0.0
table_handler.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/table_handler.h>
17 #include <deal.II/base/table.h>
18 
19 #include <boost/io/ios_state.hpp>
20 
21 #include <sstream>
22 #include <iostream>
23 #include <iomanip>
24 
25 
26 DEAL_II_NAMESPACE_OPEN
27 
28 
29 /*---------------------------------------------------------------------*/
30 
31 // inline and template functions
32 namespace internal
33 {
35  {
36  // we don't quite know the data type in 'value', but
37  // it must be one of the ones in the type list of the
38  // boost::variant. Go through this list and return
39  // the value if this happens to be a number
40  //
41  // first try with int
42  try
43  {
44  return boost::get<int>(value);
45  }
46  catch (...)
47  {}
48 
49 
50  // ... then with unsigned int...
51  try
52  {
53  return boost::get<unsigned int>(value);
54  }
55  catch (...)
56  {}
57 
58  // ... then with unsigned long long int...
59  try
60  {
61  return boost::get<unsigned long long int>(value);
62  }
63  catch (...)
64  {}
65 
66  // ...and finally with double precision:
67  try
68  {
69  return boost::get<double>(value);
70  }
71  catch (...)
72  {
73  Assert (false, ExcMessage ("The number stored by this element of the "
74  "table is not a number."))
75  }
76 
77  return 0;
78  }
79 
80  void TableEntry::cache_string(bool scientific, unsigned int precision) const
81  {
82  std::ostringstream ss;
83 
84  ss << std::setprecision(precision);
85 
86  if (scientific)
87  ss.setf(std::ios::scientific, std::ios::floatfield);
88  else
89  ss.setf(std::ios::fixed, std::ios::floatfield);
90 
91  ss << value;
92 
93  cached_value = ss.str();
94  if (cached_value.size()==0)
95  cached_value = "\"\"";
96  }
97 
98  const std::string &TableEntry::get_cached_string() const
99  {
100  return cached_value;
101  }
102 
103 
104  namespace Local
105  {
106  // see which type we can cast to, then use this type to create
107  // a default constructed object
108  struct GetDefaultValue : public boost::static_visitor<>
109  {
110  template <typename T>
111  void operator()( T &operand ) const
112  {
113  operand = T();
114  }
115  };
116  }
117 
119  {
120  TableEntry new_entry = *this;
121  boost::apply_visitor(Local::GetDefaultValue(), new_entry.value);
122 
123  return new_entry;
124  }
125 
126 
127 }
128 
129 /* ------------------------------------------------ */
130 
131 TableHandler::Column::Column(const std::string &tex_caption)
132  :
133  tex_caption(tex_caption),
134  tex_format("c"),
135  precision(4),
136  scientific(false),
137  flag(0),
138  max_length(0)
139 {}
140 
141 
142 
144  :
145  tex_caption(),
146  tex_format("c"),
147  precision(4),
148  scientific(false),
149  flag(0),
150  max_length(0)
151 {}
152 
153 
154 
155 void
156 TableHandler::Column::pad_column_below (const unsigned int size)
157 {
158  // we should never have a column that is completely
159  // empty and that needs to be padded
160  Assert (entries.size() > 0, ExcInternalError());
161 
162  // add as many elements as necessary
163  while (entries.size() < size)
164  {
165  entries.push_back (entries.back().get_default_constructed_copy());
166  internal::TableEntry &entry = entries.back();
167  entry.cache_string(scientific, precision);
168  max_length = std::max(max_length, static_cast<unsigned int>(entry.get_cached_string().length()));
169  }
170 }
171 
172 
173 void
175 {
176  max_length = 0;
177 
178  for (std::vector<::internal::TableEntry>::iterator it=entries.begin(); it!=entries.end(); ++it)
179  {
180  it->cache_string(this->scientific, this->precision);
181  max_length = std::max(max_length, static_cast<unsigned int>(it->get_cached_string().length()));
182  }
183 }
184 
185 
186 /*---------------------------------------------------------------------*/
187 
188 
190  :
191  auto_fill_mode (false)
192 {}
193 
194 
195 
196 void TableHandler::declare_column (const std::string &key)
197 {
198  // see if the column already exists; insert it if not
199  Assert (columns.find(key) == columns.end(),
200  ExcMessage ("You are trying to declare a column with key <" + key +
201  "> but such a column already exists."));
202 
203  columns.insert(std::make_pair(key, Column(key)));
204  column_order.push_back(key);
205 }
206 
207 
208 
210 {
211  // figure out the longest current column
212  unsigned int max_col_length = 0;
213  for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
214  max_col_length = std::max(max_col_length,
215  static_cast<unsigned int>(p->second.entries.size()));
216 
217 
218  // then pad all columns to that length with empty strings
219  for (std::map<std::string,Column>::iterator col=columns.begin(); col!=columns.end(); ++col)
220  while (col->second.entries.size() < max_col_length)
221  {
222  col->second.entries.emplace_back("");
223  internal::TableEntry &entry = col->second.entries.back();
224  entry.cache_string(col->second.scientific, col->second.precision);
225  col->second.max_length = std::max(col->second.max_length,
226  static_cast<unsigned int>(entry.get_cached_string().length()));
227  }
228 }
229 
230 
231 
232 void
234 {
235  auto_fill_mode = state;
236 }
237 
238 
239 void TableHandler::add_column_to_supercolumn (const std::string &key,
240  const std::string &superkey)
241 {
242  Assert(columns.count(key), ExcColumnNotExistent(key));
243 
244  if (!supercolumns.count(superkey))
245  {
246  std::pair<std::string, std::vector<std::string> >
247  new_column(superkey, std::vector<std::string>());
248  supercolumns.insert(new_column);
249  // replace key in column_order
250  // by superkey
251  for (unsigned int j=0; j<column_order.size(); ++j)
252  if (column_order[j]==key)
253  {
254  column_order[j]=superkey;
255  break;
256  }
257  }
258  else
259  {
260  // remove key from column_order
261  // for erase we need an iterator
262  for (std::vector<std::string>::iterator order_iter=column_order.begin();
263  order_iter!=column_order.end(); ++order_iter)
264  if (*order_iter==key)
265  {
266  column_order.erase(order_iter);
267  break;
268  }
269  }
270 
271  if (supercolumns.count(superkey))
272  {
273  supercolumns[superkey].push_back(key);
274  // By default set the
275  // tex_supercaption to superkey
276  std::pair<std::string, std::string> new_tex_supercaption(superkey, superkey);
277  tex_supercaptions.insert(new_tex_supercaption);
278  }
279  else
280  Assert(false, ExcInternalError());
281 }
282 
283 
284 
285 void TableHandler::set_column_order (const std::vector<std::string> &new_order)
286 {
287  for (unsigned int j=0; j<new_order.size(); ++j)
288  Assert(supercolumns.count(new_order[j]) || columns.count(new_order[j]),
289  ExcColumnOrSuperColumnNotExistent(new_order[j]));
290 
291  column_order=new_order;
292 }
293 
294 
295 void TableHandler::set_tex_caption (const std::string &key,
296  const std::string &tex_caption)
297 {
298  Assert(columns.count(key), ExcColumnNotExistent(key));
299  columns[key].tex_caption=tex_caption;
300 }
301 
302 
303 
304 void TableHandler::set_tex_table_caption (const std::string &table_caption)
305 {
306  tex_table_caption=table_caption;
307 }
308 
309 
310 
311 void TableHandler::set_tex_table_label (const std::string &table_label)
312 {
313  tex_table_label=table_label;
314 }
315 
316 
317 
318 void TableHandler::set_tex_supercaption (const std::string &superkey,
319  const std::string &tex_supercaption)
320 {
321  Assert(supercolumns.count(superkey), ExcSuperColumnNotExistent(superkey));
322  Assert(tex_supercaptions.count(superkey), ExcInternalError());
323  tex_supercaptions[superkey]=tex_supercaption;
324 }
325 
326 
327 
328 void TableHandler::set_tex_format (const std::string &key,
329  const std::string &tex_format)
330 {
331  Assert(columns.count(key), ExcColumnNotExistent(key));
332  Assert(tex_format=="l" || tex_format=="c" || tex_format=="r",
333  ExcUndefinedTexFormat(tex_format));
334  columns[key].tex_format=tex_format;
335 }
336 
337 
338 
339 void TableHandler::set_precision (const std::string &key,
340  const unsigned int precision)
341 {
342  Assert(columns.count(key), ExcColumnNotExistent(key));
343  if (columns[key].precision!=precision)
344  {
345  columns[key].precision = precision;
346  columns[key].invalidate_cache();
347  }
348 }
349 
350 
351 void TableHandler::set_scientific (const std::string &key,
352  const bool scientific)
353 {
354  Assert(columns.count(key), ExcColumnNotExistent(key));
355  if (columns[key].scientific!=scientific)
356  {
357  columns[key].scientific = scientific;
358  columns[key].invalidate_cache();
359  }
360 }
361 
362 
363 void TableHandler::write_text(std::ostream &out,
364  const TextOutputFormat format) const
365 {
366  AssertThrow (out, ExcIO());
367  boost::io::ios_flags_saver restore_flags(out);
368 
369  // first pad the table from below if necessary
370  if (auto_fill_mode == true)
371  {
372  unsigned int max_rows = 0;
373  for (std::map<std::string, Column>::const_iterator p = columns.begin();
374  p != columns.end(); ++p)
375  max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
376 
377  for (std::map<std::string, Column>::iterator p = columns.begin();
378  p != columns.end(); ++p)
379  p->second.pad_column_below (max_rows);
380  }
381 
382  std::vector<std::string> sel_columns;
383  get_selected_columns(sel_columns);
384 
385  const unsigned int nrows = n_rows();
386  const unsigned int n_cols = sel_columns.size();
387 
388  // cache the columns and compute the widths of each column for alignment
389  std::vector<const Column *> cols;
390  std::vector<unsigned int> column_widths (n_cols, 0);
391  for (unsigned int j=0; j<n_cols; ++j)
392  {
393  std::string key=sel_columns[j];
394  const std::map<std::string, Column>::const_iterator
395  col_iter=columns.find(key);
396  Assert(col_iter!=columns.end(), ExcInternalError());
397  cols.push_back(&(col_iter->second));
398 
399  column_widths[j] = col_iter->second.max_length;
400  }
401 
402  switch (format)
403  {
404  case org_mode_table:
405  {
406  // write the captions
407  out << "| " << std::left;
408  for (unsigned int j=0; j<n_cols; ++j)
409  {
410  const std::string &key = sel_columns[j];
411  column_widths[j] = std::max(column_widths[j],
412  (unsigned int)key.length());
413  out << std::setw(column_widths[j]);
414  out << key << " | ";
415  }
416  out << std::endl;
417 
418  // write the body
419  for (unsigned int i=0; i<nrows; ++i)
420  {
421  out << "| ";
422  for (unsigned int j=0; j<n_cols; ++j)
423  {
424  const Column &column=*(cols[j]);
425 
426  out << std::setw(column_widths[j]);
427  out << column.entries[i].get_cached_string();
428  out << " | ";
429  }
430  out << '\n';
431  }
432 
433  out << std::flush;
434  return;
435  }
436 
438  {
439  // write the captions
440  for (unsigned int j=0; j<n_cols; ++j)
441  {
442  const std::string &key = sel_columns[j];
443  out << "# " << j+1 << ": " << key << '\n';
444  }
445 
446  // write the body
447  for (unsigned int i=0; i<nrows; ++i)
448  {
449  for (unsigned int j=0; j<n_cols; ++j)
450  {
451  const Column &column=*(cols[j]);
452 
453  out << column.entries[i].get_cached_string();
454  out << ' ';
455  }
456  out << '\n';
457  }
458 
459  out << std::flush;
460  return;
461  }
462 
464  {
465  // writing the captions for table_with_separate_column_description
466  // means that we ignore supercolumns and output the column
467  // header for each column. enumerate columns starting with 1
468  for (unsigned int j=0; j<n_cols; ++j)
469  {
470  std::string key=sel_columns[j];
471  out << "# " << j+1 << ": " << key << '\n';
472  }
473  break;
474  }
475 
476  case table_with_headers:
477  {
478  // This format output supercolumn headers and aligns them centered
479  // over all the columns that belong to it.
480  for (unsigned int j=0; j<column_order.size(); ++j)
481  {
482  const std::string &key = column_order[j];
483  unsigned int width=0;
484  {
485  // compute the width of this column or supercolumn
486  const std::map<std::string, std::vector<std::string> >::const_iterator
487  super_iter=supercolumns.find(key);
488  if (super_iter!=supercolumns.end())
489  {
490  const unsigned int n_subcolumns=super_iter->second.size();
491  for (unsigned int k=0; k<n_subcolumns; ++k)
492  {
493  const std::map<std::string, Column>::const_iterator
494  col_iter=columns.find(super_iter->second[k]);
495  Assert(col_iter!=columns.end(), ExcInternalError());
496 
497  width += col_iter->second.max_length;
498  }
499  width += n_subcolumns - 1; // separators between subcolumns
500  }
501  else
502  {
503  const std::map<std::string, Column>::const_iterator
504  col_iter=columns.find(key);
505 
506  width = col_iter->second.max_length;
507  }
508  }
509 
510  // header is longer than the column(s) under it
511  if (width<key.length())
512  {
513  // make the column or the last column in this
514  // supercolumn wide enough
515  std::string colname;
516 
517  const std::map<std::string, std::vector<std::string> >::const_iterator
518  super_iter=supercolumns.find(key);
519  if (super_iter!=supercolumns.end())
520  colname = super_iter->second.back();
521  else
522  colname = key;
523 
524  // find column and change output width
525  for (unsigned int i=0; i<n_cols; ++i)
526  {
527  if (sel_columns[i]==colname)
528  {
529  column_widths[i] += key.length() - width;
530  break;
531  }
532  }
533 
534  width=key.length();
535  }
536 
537  // now write key. try to center it somehow
538  const unsigned int front_padding = (width-key.length())/2,
539  rear_padding = (width-key.length()) -
540  front_padding;
541  for (unsigned int i=0; i<front_padding; ++i)
542  out << ' ';
543  out << key;
544  for (unsigned int i=0; i<rear_padding; ++i)
545  out << ' ';
546 
547  out << ' ';
548  }
549  out << '\n';
550  break;
551  }
552 
553  default:
554  Assert (false, ExcInternalError());
555  }
556 
557 
558  // finally output the data itself for
559  // table_with_headers or table_with_separate_column_description:
560  for (unsigned int i=0; i<nrows; ++i)
561  {
562  for (unsigned int j=0; j<n_cols; ++j)
563  {
564  const Column &column=*(cols[j]);
565  out << std::setw(column_widths[j]);
566  out << column.entries[i].get_cached_string();
567 
568  // pad after this column
569  out << ' ';
570  }
571  out << '\n';
572  }
573  out << std::flush;
574 }
575 
576 
577 void TableHandler::write_tex (std::ostream &out, const bool with_header) const
578 {
579  //TODO[TH]: update code similar to
580  //write_text() to use the cache
581  AssertThrow (out, ExcIO());
582  if (with_header)
583  out << "\\documentclass[10pt]{report}" << std::endl
584  << "\\usepackage{float}" << std::endl << std::endl << std::endl
585  << "\\begin{document}" << std::endl;
586 
587  out << "\\begin{table}[H]" << std::endl
588  << "\\begin{center}" << std::endl
589  << "\\begin{tabular}{|";
590 
591  // first pad the table from below if necessary
592  if (auto_fill_mode == true)
593  {
594  unsigned int max_rows = 0;
595  for (std::map<std::string, Column>::const_iterator p = columns.begin();
596  p != columns.end(); ++p)
597  max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
598 
599  for (std::map<std::string, Column>::iterator p = columns.begin();
600  p != columns.end(); ++p)
601  p->second.pad_column_below (max_rows);
602  }
603 
604  std::vector<std::string> sel_columns;
605  get_selected_columns(sel_columns);
606 
607  // write the column formats
608  for (unsigned int j=0; j<column_order.size(); ++j)
609  {
610  std::string key=column_order[j];
611  // avoid `supercolumns[key]'
612  const std::map<std::string, std::vector<std::string> >::const_iterator
613  super_iter=supercolumns.find(key);
614 
615  if (super_iter!=supercolumns.end())
616  {
617  const unsigned int n_subcolumns=super_iter->second.size();
618  for (unsigned int k=0; k<n_subcolumns; ++k)
619  {
620  // avoid `columns[supercolumns[key]]'
621  const std::map<std::string, Column>::const_iterator
622  col_iter=columns.find(super_iter->second[k]);
623  Assert(col_iter!=columns.end(), ExcInternalError());
624 
625  out << col_iter->second.tex_format << "|";
626  }
627  }
628  else
629  {
630  // avoid `columns[key]';
631  const std::map<std::string, Column>::const_iterator
632  col_iter=columns.find(key);
633  Assert(col_iter!=columns.end(), ExcInternalError());
634  out << col_iter->second.tex_format << "|";
635  }
636  }
637  out << "} \\hline" << std::endl;
638 
639  // write the caption line of the table
640 
641  for (unsigned int j=0; j<column_order.size(); ++j)
642  {
643  std::string key=column_order[j];
644  const std::map<std::string, std::vector<std::string> >::const_iterator
645  super_iter=supercolumns.find(key);
646 
647  if (super_iter!=supercolumns.end())
648  {
649  const unsigned int n_subcolumns=super_iter->second.size();
650  // avoid use of `tex_supercaptions[key]'
651  std::map<std::string,std::string>::const_iterator
652  tex_super_cap_iter=tex_supercaptions.find(key);
653  out << std::endl << "\\multicolumn{" << n_subcolumns << "}{|c|}{"
654  << tex_super_cap_iter->second << "}";
655  }
656  else
657  {
658  // col_iter->second=columns[col];
659  const std::map<std::string, Column>::const_iterator
660  col_iter=columns.find(key);
661  Assert(col_iter!=columns.end(), ExcInternalError());
662  out << col_iter->second.tex_caption;
663  }
664  if (j<column_order.size()-1)
665  out << " & ";
666  }
667  out << "\\\\ \\hline" << std::endl;
668 
669  // write the n rows
670  const unsigned int nrows=n_rows();
671  for (unsigned int i=0; i<nrows; ++i)
672  {
673  const unsigned int n_cols=sel_columns.size();
674 
675  for (unsigned int j=0; j<n_cols; ++j)
676  {
677  std::string key=sel_columns[j];
678  // avoid `column[key]'
679  const std::map<std::string, Column>::const_iterator
680  col_iter=columns.find(key);
681  Assert(col_iter!=columns.end(), ExcInternalError());
682 
683  const Column &column=col_iter->second;
684 
685  out << std::setprecision(column.precision);
686 
687  if (col_iter->second.scientific)
688  out.setf(std::ios::scientific, std::ios::floatfield);
689  else
690  out.setf(std::ios::fixed, std::ios::floatfield);
691 
692  out << column.entries[i].value;
693 
694  if (j<n_cols-1)
695  out << " & ";
696  }
697  out << "\\\\ \\hline" << std::endl;
698  }
699 
700  out << "\\end{tabular}" << std::endl
701  << "\\end{center}" << std::endl;
702  if (tex_table_caption!="")
703  out << "\\caption{" << tex_table_caption << "}" << std::endl;
704  if (tex_table_label!="")
705  out << "\\label{" << tex_table_label << "}" << std::endl;
706  out << "\\end{table}" << std::endl;
707  if (with_header)
708  out << "\\end{document}" << std::endl;
709 }
710 
711 
713 {
714 
715  columns.clear();
716  supercolumns.clear();
717  column_order.clear();
718  tex_supercaptions.clear();
719 
720  tex_table_label.clear();
721  tex_table_caption.clear();
722 
723 }
724 
725 
726 unsigned int TableHandler::n_rows() const
727 {
728  if (columns.size() == 0)
729  return 0;
730 
731  std::map<std::string, Column>::const_iterator col_iter = columns.begin();
732  unsigned int n = col_iter->second.entries.size();
733  std::string first_name=col_iter->first;
734 
735  for (++col_iter; col_iter!=columns.end(); ++col_iter)
736  Assert(col_iter->second.entries.size()==n,
737  ExcWrongNumberOfDataEntries(col_iter->first,
738  col_iter->second.entries.size(),
739  first_name, n));
740 
741  return n;
742 }
743 
744 
745 void TableHandler::get_selected_columns(std::vector<std::string> &sel_columns) const
746 {
747  sel_columns.clear();
748 
749  for (unsigned int j=0; j<column_order.size(); ++j)
750  {
751  std::string key=column_order[j];
752  const std::map<std::string, std::vector<std::string> >::const_iterator
753  super_iter=supercolumns.find(key);
754 
755  if (super_iter!=supercolumns.end())
756  {
757  // i.e. key is a supercolumn key
758  const unsigned int n_subcolumns=super_iter->second.size();
759  for (unsigned int k=0; k<n_subcolumns; ++k)
760  {
761  const std::string subkey=super_iter->second[k];
762  Assert(columns.count(subkey), ExcInternalError());
763  sel_columns.push_back(subkey);
764  }
765  }
766  else
767  {
768  Assert(columns.count(key), ExcInternalError());
769  // i.e. key is a column key
770  sel_columns.push_back(key);
771  }
772  }
773 }
774 
775 
777 {
778  // Figure out what is the currect (max) length of the columns
779  // so that we "shave" one off.
780  std::vector<internal::TableEntry>::size_type n = 0;
781  for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
782  n = std::max(n, p->second.entries.size());
783 
784  // shave the top most element
785  if (n != 0)
786  for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
787  if (p->second.entries.size() == n)
788  p->second.entries.pop_back();
789 }
790 
791 
792 DEAL_II_NAMESPACE_CLOSE
std::map< std::string, std::string > tex_supercaptions
void set_precision(const std::string &key, const unsigned int precision)
void declare_column(const std::string &key)
static ::ExceptionBase & ExcIO()
void set_tex_supercaption(const std::string &superkey, const std::string &tex_supercaption)
static ::ExceptionBase & ExcColumnOrSuperColumnNotExistent(std::string arg1)
const std::string & get_cached_string() const
void set_tex_caption(const std::string &key, const std::string &tex_caption)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
void cache_string(bool scientific, unsigned int precision) const
void add_column_to_supercolumn(const std::string &key, const std::string &superkey)
void set_tex_format(const std::string &key, const std::string &format="c")
void get_selected_columns(std::vector< std::string > &sel_columns) const
static ::ExceptionBase & ExcSuperColumnNotExistent(std::string arg1)
static ::ExceptionBase & ExcWrongNumberOfDataEntries(std::string arg1, int arg2, std::string arg3, int arg4)
std::vector< std::string > column_order
static ::ExceptionBase & ExcMessage(std::string arg1)
std::string tex_table_caption
double get_numeric_value() const
TableEntry get_default_constructed_copy() const
void write_text(std::ostream &out, const TextOutputFormat format=table_with_headers) const
std::string cached_value
#define Assert(cond, exc)
Definition: exceptions.h:1142
void set_tex_table_label(const std::string &table_label)
void write_tex(std::ostream &file, const bool with_header=true) const
void clear_current_row()
static ::ExceptionBase & ExcUndefinedTexFormat(std::string arg1)
void set_column_order(const std::vector< std::string > &new_order)
void set_scientific(const std::string &key, const bool scientific)
void pad_column_below(const unsigned int length)
static ::ExceptionBase & ExcColumnNotExistent(std::string arg1)
std::vector< internal::TableEntry > entries
std::map< std::string, Column > columns
unsigned int n_rows() const
void start_new_row()
void set_tex_table_caption(const std::string &table_caption)
std::map< std::string, std::vector< std::string > > supercolumns
std::string tex_table_label
static ::ExceptionBase & ExcInternalError()
void set_auto_fill_mode(const bool state)