DEAL_II_NAMESPACE_OPEN
+class TableHandler;
namespace internal
{
* A <tt>TableEntry</tt> stores the value of a table entry.
* It can either be of type int, unsigned int, double or std::string.
* In essence, this structure is the same as
- * <code>boost::variant<int,unsigned int,double,std::string></code>
+ * <code>boost::variant@<int,unsigned int,double,std::string@></code>
* but we wrap this object in a structure for which we can write
* a function that can serialize it. This is also why the function
* is not in fact of type boost::any.
*/
struct TableEntry
{
+ public:
/**
- * Abbreviation for the data type stored by this object.
- */
- typedef boost::variant<int,unsigned int,double,std::string> value_type;
-
- /**
- * Stored value.
+ * Constructor. Initialize this table element with the value <code>t</code>.
*/
- value_type value;
-
+ template <typename T>
+ TableEntry (const T &t);
+
/**
* Return the value stored by this object. The template type
* T must be one of <code>int,unsigned int,double,std::string</code>
void load (Archive & ar, const unsigned int version);
BOOST_SERIALIZATION_SPLIT_MEMBER()
+
+ private:
+ /**
+ * Abbreviation for the data type stored by this object.
+ */
+ typedef boost::variant<int,unsigned int,double,std::string> value_type;
+
+ /**
+ * Stored value.
+ */
+ value_type value;
+
+ friend class dealii::TableHandler;
};
}
* out_file.close();
* @endcode
*
+ *
+ * <h3>Dealing with sparse data</h3>
+ *
+ * When generating output, TableHandler expects that all columns have the exact
+ * same number of elements in it so that the result is in fact a table. This
+ * assumes that in each of the iterations (time steps, nonlinear iterations, etc)
+ * you fill every single column. On the other hand, this may not always be what
+ * you want to do. For example, it could be that the function that computes the
+ * nonlinear residual is only called every few time steps; or, a function computing
+ * statistics of the mesh is only called whenever the mesh is in fact refined.
+ *
+ * In these cases, the add_value() function will be called less often for some
+ * columns and the column would therefore have fewer elements; furthermore, these
+ * elements would not be aligned with the rows that contain the other data elements
+ * that were produced during this iteration.
+ *
+ * To avoid this problem, we use the following algorithm:
+ * - When calling <code>add_value(key, value)</code>, we count the number of elements
+ * in the column corresponding to <code>key</code>. Let's call this number $m$.
+ * - We also determine the maximal number of elements in the other columns; call
+ * it $n$.
+ * - If $m < n-1$ then we add $n-m-1$ copies of the object <code>T()</code>
+ * to this column. Here, <code>T</code> is the data type of the given <code>value</code>.
+ * For example, if <code>T</code> is a numeric type, then <code>T()</code> is
+ * the number zero; if <code>T</code> is <code>std::string</code>, then
+ * <code>T()</code> is the empty string <code>""</code>.
+ * - Add the given value to this column.
+ *
+ * Padding the column with default elements makes sure that after the addition the
+ * column has as many entries as the longest other column. In other words, if
+ * we have skipped previous invokations of add_value() for a given key, then the
+ * padding will enter default values into this column.
+ *
+ * The algorithm as described will fail if you try to skip adding values for a key
+ * if adding an element for this key is the first thing you want to do for a given
+ * iteration or time step, since we would then pad to the length of the longest
+ * column of the <i>previous</i> iteration or time step. You may have to re-order
+ * adding to this column to a different spot in your program, after adding to
+ * a column that will always be added to; or, you may want to start every iteration
+ * by adding the number of the iteration to the table, for example in column 1.
+ *
+ *
* @ingroup textoutput
* @author Ralf Hartmann, 1999; Wolfgang Bangerth, 2011
*/
// inline and template functions
namespace internal
{
+ template <typename T>
+ TableEntry::TableEntry (const T &t)
+ :
+ value (t)
+ {}
+
template <typename T>
inline
T TableEntry::get () const
void TableHandler::add_value (const std::string &key,
const T value)
{
+ // see if the column already exists
if (columns.find(key) == columns.end())
{
std::pair<std::string, Column> new_column(key, Column(key));
column_order.push_back(key);
}
- const internal::TableEntry entry = { value };
- columns[key].entries.push_back (entry);
+ // follow the algorithm given in the introduction to this class
+ // of padding columns as necessary
+ unsigned int n = 0;
+ for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
+ n = (n >= p->second.entries.size() ? n : p->second.entries.size());
+
+ while (columns[key].entries.size()+1 < n)
+ columns[key].entries.push_back (internal::TableEntry(T()));
+
+ // now push the value given to this function
+ columns[key].entries.push_back (internal::TableEntry(value));
}
--- /dev/null
+//-----------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2010, 2011 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//-----------------------------------------------------------------------------
+
+// pad columns if we don't fill them in each iteration
+
+
+#include "../tests.h"
+#include <deal.II/base/data_out_base.h>
+#include <deal.II/base/table_handler.h>
+#include <deal.II/base/logstream.h>
+
+#include <vector>
+#include <iomanip>
+#include <fstream>
+#include <string>
+
+
+int main ()
+{
+ std::ofstream logfile("table_handler_04/output");
+ deallog.attach(logfile);
+ deallog.depth_console(0);
+ deallog.threshold_double(1.e-10);
+
+ TableHandler table;
+
+ std::string keys[3] = { "key1", "key2", "key3" };
+
+ table.add_value(keys[0], 0);
+ table.add_value(keys[0], 1);
+ table.add_value(keys[0], 2);
+ table.add_value(keys[1], 13);
+ table.add_value(keys[2], std::string("a"));
+
+ table.write_text(deallog.get_file_stream());
+}