1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2019 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 
16 #ifndef dealii_data_out_stack_h
17 #define dealii_data_out_stack_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/data_out_base.h>
23 #include <deal.II/base/smartpointer.h>
24 
25 #include <deal.II/lac/vector.h>
26 
27 #include <deal.II/numerics/data_out_dof_data.h>
28 
29 #include <string>
30 #include <vector>
31 
32 DEAL_II_NAMESPACE_OPEN
33 
34 // Forward declaration
35 #ifndef DOXYGEN
36 template <int dim, int spacedim>
37 class DoFHandler;
38 #endif
39 
40 /**
41  * This class is used to stack the output from several computations into one
42  * output file by stacking the data sets in another co-ordinate direction
43  * orthogonal to the space directions. The most common use is to stack the
44  * results of several time steps into one space-time output file, or for
45  * example to connect the results of solutions of a parameter dependent
46  * equation for several parameter value together into one. The interface is
47  * mostly modelled after the DataOut class, see there for some more
48  * documentation.
49  *
50  * We will explain the concept for a time dependent problem, but instead of
51  * the time any parameter can be substituted. In our example, a solution of an
52  * equation is computed for each discrete time level. This is then added to an
53  * object of the present class and after all time levels are added, a space-
54  * time plot will be written in any of the output formats supported by the
55  * base class. Upon output, the (spatial) solution on each time level is
56  * extended into the time direction by writing it twice, once for the time
57  * level itself and once for a time equal to the time level minus a given time
58  * step. These two copies are connected, to form a space-time slab, with
59  * constant values in time.
60  *
61  * Due to the piecewise constant output in time, the written solution will in
62  * general be discontinuous at discrete time levels, but the output is still
63  * sufficient in most cases. More sophisticated interpolations in time may be
64  * added in the future.
65  *
66  *
67  * <h3>Example of Use</h3>
68  *
69  * The following little example shall illustrate the different steps of use of
70  * this class. It is assumed that the finite element used is composed of two
71  * components, @p u and @p v, that the solution vector is named @p solution
72  * and that a vector @p error is computed which contains an error indicator
73  * for each spatial cell.
74  *
75  * Note that unlike for the DataOut class it is necessary to first declare
76  * data vectors and the names of the components before first use. This is
77  * because on all time levels the same data should be present to produce
78  * reasonable time-space output. The output is generated with two subdivisions
79  * in each space and time direction, which is suitable for quadratic finite
80  * elements in space, for example.
81  *
82  * @code
83  *   DataOutStack<dim> data_out_stack;
84  *
85  *                                  // first declare the vectors
86  *                                  // to be used later
87  *   std::vector<std::string> solution_names;
88  *   solution_names.emplace_back ("u");
89  *   solution_names.emplace_back ("v");
90  *   data_out_stack.declare_data_vector (solution_names,
91  *                                       DataOutStack<dim>::dof_vector);
92  *   data_out_stack.declare_data_vector ("error",
93  *                                       DataOutStack<dim>::cell_vector);
94  *
95  *                                  // now do computations
96  *   for (double parameter=0; ...)
97  *     {
98  *       DoFHandler<dim,spacedim> dof_handler;
99  *       ...                        // compute something
100  *
101  *                                  // now for output
102  *       data_out_stack.new_parameter_value (parameter,
103  *                                           delta_parameter);
104  *       data_out_stack.attach_dof_handler (dof_handler);
105  *       data_out_stack.add_data_vector (solution, solution_names);
106  *       data_out_stack.add_data_vector (error, "error");
107  *       data_out_stack.build_patches (2);
108  *       data_out_stack.finish_parameter_value ();
109  *     };
110  * @endcode
111  *
112  * @ingroup output
113  */
114 template <int dim,
115           int spacedim            = dim,
116           typename DoFHandlerType = DoFHandler<dim, spacedim>>
117 class DataOutStack : public DataOutInterface<dim + 1>
118 {
119 public:
120   /**
121    * Data type declaring the two types of vectors which are used in this
122    * class.
123    */
124   enum VectorType
125   {
126     /**
127      * The data describes one value for each cell.
128      */
129     cell_vector,
130     /**
131      * The data describes one value for each DoF.
132      */
133     dof_vector
134   };
135 
136   /**
137    * Destructor. Only declared to make it @p virtual.
138    */
139   virtual ~DataOutStack() override = default;
140 
141   /**
142    * Start the next set of data for a specific parameter value. The argument
143    * @p parameter_step denotes the interval (in backward direction, counted
144    * from @p parameter_value) with which the output will be extended in
145    * parameter direction, i.e. orthogonal to the space directions.
146    */
147   void
148   new_parameter_value(const double parameter_value,
149                       const double parameter_step);
150 
151   /**
152    * Attach the DoF handler for the grid and data associated with the
153    * parameter previously set by @p new_parameter_value.
154    *
155    * This has to happen before adding data vectors for the present parameter
156    * value.
157    */
158   void
159   attach_dof_handler(const DoFHandlerType &dof_handler);
160 
161   /**
162    * Declare a data vector. The @p vector_type argument determines whether the
163    * data vector will be considered as DoF or cell data.
164    *
165    * This version may be called if the finite element presently used by the
166    * DoFHandler (and previously attached to this object) has only one
167    * component and therefore only one name needs to be given.
168    */
169   void
170   declare_data_vector(const std::string &name, const VectorType vector_type);
171 
172   /**
173    * Declare a data vector. The @p vector_type argument determines whether the
174    * data vector will be considered as DoF or cell data.
175    *
176    * This version must be called if the finite element presently used by the
177    * DoFHandler (and previously attached to this object) has more than one
178    * component and therefore more than one name needs to be given. However,
179    * you can also call this function with a
180    * <tt>std::vector@<std::string@></tt> containing only one element if the
181    * finite element has only one component.
182    */
183   void
184   declare_data_vector(const std::vector<std::string> &name,
185                       const VectorType                vector_type);
186 
187 
188   /**
189    * Add a data vector for the presently set value of the parameter.
190    *
191    * This version may be called if the finite element presently used by the
192    * DoFHandler (and previously attached to this object) has only one
193    * component and therefore only one name needs to be given.
194    *
195    * If @p vec is a vector with multiple components this function will
196    * generate distinct names for all components by appending an underscore and
197    * the number of each component to @p name
198    *
199    * The data vector must have been registered using the @p
200    * declare_data_vector function before actually using it the first time.
201    *
202    * Note that a copy of this vector is stored until @p finish_parameter_value
203    * is called the next time, so if you are short of memory you may want to
204    * call this function only after all computations involving large matrices
205    * are already done.
206    */
207   template <typename number>
208   void
209   add_data_vector(const Vector<number> &vec, const std::string &name);
210 
211   /**
212    * Add a data vector for the presently set value of the parameter.
213    *
214    * This version must be called if the finite element presently used by the
215    * DoFHandler (and previously attached to this object) has more than one
216    * component and therefore more than one name needs to be given. However,
217    * you can also call this function with a
218    * <tt>std::vector@<std::string@></tt> containing only one element if the
219    * finite element has only one component.
220    *
221    * The data vector must have been registered using the @p
222    * declare_data_vector function before actually using it the first time.
223    *
224    * Note that a copy of this vector is stored until @p finish_parameter_value
225    * is called the next time, so if you are short of memory you may want to
226    * call this function only after all computations involving large matrices
227    * are already done.
228    */
229   template <typename number>
230   void
231   add_data_vector(const Vector<number> &          vec,
232                   const std::vector<std::string> &names);
233 
234   /**
235    * This is the central function of this class since it builds the list of
236    * patches to be written by the low-level functions of the base class. A
237    * patch is, in essence, some intermediate representation of the data on
238    * each cell of a triangulation and DoFHandler object that can then be used
239    * to write files in some format that is readable by visualization programs.
240    *
241    * You can find an overview of the use of this function in the general
242    * documentation of this class. An example is also provided in the
243    * documentation of this class's base class DataOut_DoFData.
244    *
245    * @param n_subdivisions See DataOut::build_patches() for an extensive
246    * description of this parameter. The number of subdivisions is always one
247    * in the direction of the time-like parameter used by this class.
248    */
249   void
250   build_patches(const unsigned int n_subdivisions = 0);
251 
252   /**
253    * Release all data that is no more needed once @p build_patches was called
254    * and all other transactions for a given parameter value are done.
255    *
256    * Counterpart of @p new_parameter_value.
257    */
258   void
259   finish_parameter_value();
260 
261   /**
262    * Determine an estimate for the memory consumption (in bytes) of this
263    * object.
264    */
265   std::size_t
266   memory_consumption() const;
267 
268   /**
269    * Exception
270    */
271   DeclException1(
272     ExcVectorNotDeclared,
273     std::string,
274     << "The data vector for which the first component has the name " << arg1
275     << " has not been added before.");
276   /**
277    * Exception
278    */
279   DeclExceptionMsg(ExcDataNotCleared,
280                    "You cannot start a new time/parameter step before calling "
281                    "finish_parameter_value() on the previous step.");
282   /**
283    * Exception
284    */
285   DeclExceptionMsg(
286     ExcDataAlreadyAdded,
287     "You cannot declare additional vectors after already calling "
288     "build_patches(). All data vectors need to be declared "
289     "before you call this function the first time.");
290   /**
291    * Exception
292    */
293   DeclException1(ExcNameAlreadyUsed,
294                  std::string,
295                  << "You tried to declare a component of a data vector with "
296                  << "the name <" << arg1
297                  << ">, but that name is already used.");
298 
299 private:
300   /**
301    * Present parameter value.
302    */
303   double parameter;
304 
305   /**
306    * Present parameter step, i.e. length of the parameter interval to be
307    * written next.
308    */
309   double parameter_step;
310 
311   /**
312    * DoF handler to be used for the data corresponding to the present
313    * parameter value.
314    */
315   SmartPointer<const DoFHandlerType,
316                DataOutStack<dim, spacedim, DoFHandlerType>>
317     dof_handler;
318 
319   /**
320    * List of patches of all past and present parameter value data sets.
321    */
322   std::vector<dealii::DataOutBase::Patch<dim + 1, dim + 1>> patches;
323 
324   /**
325    * Structure holding data vectors (cell and dof data) for the present
326    * parameter value.
327    */
328   struct DataVector
329   {
330     /**
331      * Data vector.
332      */
333     Vector<double> data;
334 
335     /**
336      * Names of the different components within each such data set.
337      */
338     std::vector<std::string> names;
339 
340     /**
341      * Determine an estimate for the memory consumption (in bytes) of this
342      * object.
343      */
344     std::size_t
345     memory_consumption() const;
346   };
347 
348   /**
349    * List of DoF data vectors.
350    */
351   std::vector<DataVector> dof_data;
352 
353   /**
354    * List of cell data vectors.
355    */
356   std::vector<DataVector> cell_data;
357 
358   /**
359    * This is the function through which derived classes propagate preprocessed
360    * data in the form of Patch structures (declared in the base class
361    * DataOutBase) to the actual output function.
362    */
363   virtual const std::vector<dealii::DataOutBase::Patch<dim + 1, dim + 1>> &
364   get_patches() const override;
365 
366 
367   /**
368    * Virtual function through which the names of data sets are obtained by the
369    * output functions of the base class.
370    */
371   virtual std::vector<std::string>
372   get_dataset_names() const override;
373 };
374 
375 
376 DEAL_II_NAMESPACE_CLOSE
377 
378 #endif
379