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