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