Flow123d  release_1.8.2-1603-g0109a2b
output_time.impl.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file output.h
15  * @brief Header: The functions for all outputs.
16  * @todo
17  * - remove Output, keep OutputTime only (done)
18  * - remove parameter mesh from static method OutputTime::output_stream (done)
19  * - move initialization of streams from hc_expolicit_sequantial to
20  * Aplication::Aplication() constructor (done)
21  * - OutputTime::register_XXX_data - should accept iterator to output record of particular equation, ask for presence of the key
22  * that has same name as the name of the quantity to output, extract the string with stream name from this key, find the stream
23  * and perform output.
24  *
25  * on input:
26  *
27  * { // darcy flow
28  * output = {
29  * pressure_nodes="nodal_data",
30  * pressure_elements="el_data"
31  * }
32  * }
33  *
34  * output_streams=[
35  * {name="nodal_data", ... },
36  * {name="el_data", ... }
37  * ]
38  *
39  * in code:
40  *
41  * Input::Record out_rec = in_rec.val<Input::Record>("output");
42  * OutputTime::register_node_data(mesh_, "pressure_nodes", "L", out_rec, node_pressure);
43  * OutputTime::register_elem_data(mesh_, "pressure_elements", "L", out_rec, ele_pressure);
44  * ...
45  *
46  * - use exceptions instead of returning result, see declaration of exceptions through DECLARE_EXCEPTION macro
47  * - move write_data from equations into coupling, write all streams
48  *
49  * =======================
50  * - Is it still necessary to split output into registration and write the data?
51  * Could we perform it at once? ... No, it doesn't make any sense.
52  * - Support for output of corner data into GMSH format (ElementNodeData section)
53  *
54  */
55 
56 #ifndef OUTPUT_H
57 #define OUTPUT_H
58 
59 #include <vector>
60 #include <string>
61 #include <ostream>
62 
63 #include "system/system.hh"
64 #include "mesh/mesh.h"
65 
66 #include "fields/field.hh"
67 #include "fields/multi_field.hh"
68 #include "system/exceptions.hh"
69 #include "io/output_time.hh"
70 
71 #include "io/output_data_base.hh"
72 
73 
74 /**
75  * \brief This class is used for storing data that are copied from field.
76  *
77  *
78  */
79 template <class Value>
80 class OutputData : public OutputDataBase {
81 public:
82  typedef typename Value::element_type ElemType;
83 
84  /**
85  * \brief Constructor of templated OutputData
86  */
87  OutputData(const FieldCommon &field,
88  unsigned int size)
89  : val_aux(aux)
90  {
91  this->field_name = field.name();
92  this->field_units = field.units();
93  this->output_field_name = this->field_name;
94 
95  this->n_values = size;
96 
97  if (val_aux.NCols_ == 1) {
98  if (val_aux.NRows_ == 1) {
99  this->n_elem_ = N_SCALAR;
100  this->n_rows = 1;
101  this->n_cols = 1;
102  } else {
103  if (val_aux.NRows_ > 1) {
104  if (val_aux.NRows_ > 3) {
105  xprintf(PrgErr,
106  "Do not support output of vectors with fixed size >3. Field: %s\n",
107  this->field_name.c_str());
108  } else {
109  this->n_elem_ = N_VECTOR;
110  this->n_rows = 3;
111  this->n_cols = 1;
112  }
113  } else {
114  THROW(OutputTime::ExcOutputVariableVector() << OutputTime::EI_FieldName(this->field_name));
115  }
116  }
117  } else {
118  this->n_elem_ = N_TENSOR;
119  this->n_rows = 3;
120  this->n_cols = 3;
121  }
122 
123  data_ = new ElemType[this->n_values * this->n_elem_];
124  }
125 
126 
127  /**
128  * \brief Destructor of OutputData
129  */
131  {
132  delete[] this->data_;
133  }
134 
135 
136  /**
137  * Output data element on given index @p idx. Method for writing data
138  * to output stream.
139  *
140  * \note This method is used only by MSH file format.
141  */
142  void print(ostream &out_stream, unsigned int idx) override
143  {
144  OLD_ASSERT_LESS(idx, this->n_values);
145  ElemType *ptr_begin = this->data_ + n_elem_ * idx;
146  for(ElemType *ptr = ptr_begin; ptr < ptr_begin + n_elem_; ptr++ )
147  out_stream << *ptr << " ";
148  }
149 
150  /**
151  * \brief Print all data stored in output data
152  *
153  * TODO: indicate if the tensor data are output in column-first or raw-first order
154  * and possibly implement transposition. Set such property for individual file formats.
155  * Class OutputData stores always in raw-first order.
156  */
157  void print_all(ostream &out_stream) override
158  {
159  for(unsigned int idx = 0; idx < this->n_values; idx++) {
160  ElemType *ptr_begin = this->data_ + n_elem_ * idx;
161  for(ElemType *ptr = ptr_begin; ptr < ptr_begin + n_elem_; ptr++ )
162  out_stream << *ptr << " ";
163  }
164  }
165 
166  /**
167  * Store data element of given data value under given index.
168  */
169  void store_value(unsigned int idx, const Value& value) {
170  operate(idx, value, [](ElemType& raw, ElemType val) {raw = val;});
171  };
172 
173  /**
174  * Add value to given index
175  */
176  void add(unsigned int idx, const Value& value) {
177  operate(idx, value, [](ElemType& raw, ElemType val) {raw += val;});
178  };
179 
180  /**
181  * Reset values at given index
182  */
183  void zero(unsigned int idx) {
184  operate(idx, val_aux, [](ElemType& raw, ElemType val) {raw = 0;});
185  };
186 
187  /**
188  * Normalize values at given index
189  */
190  void normalize(unsigned int idx, unsigned int divisor) {
191  operate(idx, val_aux, [divisor](ElemType& raw, ElemType val) {raw /= divisor;});
192  };
193 
194 private:
195 
196  /**
197  * Perform given function at given index
198  */
199  template <class Func>
200  void operate(unsigned int idx, const Value &val, const Func& func) {
201  OLD_ASSERT_LESS(idx, this->n_values);
202  ElemType *ptr = this->data_ + idx*this->n_elem_;
203  for(unsigned int i_row = 0; i_row < this->n_rows; i_row++) {
204  for(unsigned int i_col = 0; i_col < this->n_cols; i_col++) {
205  if (i_row < val.n_rows() && i_col < val.n_cols())
206  func(*ptr, val(i_row, i_col));
207  else
208  func(*ptr, 0);
209  ptr++;
210  }
211  }
212  };
213 
214 
215  /**
216  * Computed data values for output stored as continuous buffer of their data elements.
217  * One data value has @p n_elem data elements (of type double, int or unsigned int).
218  */
219  ElemType *data_;
220 
221 
222  /**
223  * Auxiliary value
224  */
225  typename Value::return_type aux;
226 
227 
228  /**
229  * Auxiliary field value envelope over @p aux
230  */
231  Value val_aux;
232 
233 
234  /**
235  * Number of rows and cols in stored data element, valid values are (1,1)
236  * for scalar; (3,1) for vectors; (3,3) for tensors
237  */
238  unsigned int n_rows, n_cols;
239 
240 };
241 
242 
243 
244 /**************************************************************************************************************
245  * OutputTime implementation
246  */
247 
248 template<int spacedim, class Value>
250  MultiField<spacedim, Value> &multi_field)
251 {
252  OLD_ASSERT_LESS(type, N_DISCRETE_SPACES);
253  if (output_names.find(multi_field.name()) == output_names.end()) return;
254 
255  DiscreteSpaceFlags flags = output_names[multi_field.name()];
256  if (! flags) flags = 1 << type;
257  for (unsigned long index=0; index < multi_field.size(); index++)
258  for(unsigned int ids=0; ids < N_DISCRETE_SPACES; ids++)
259  if (flags & (1 << ids))
260  this->compute_field_data( DiscreteSpace(ids), multi_field[index] );
261 
262 }
263 
264 
265 template<int spacedim, class Value>
267  Field<spacedim, Value> &field_ref)
268 {
269  OLD_ASSERT_LESS(type, N_DISCRETE_SPACES);
270  if (output_names.find(field_ref.name()) == output_names.end()) return;
271 
272  DiscreteSpaceFlags flags = output_names[field_ref.name()];
273  if (! flags) flags = 1 << type;
274  for(unsigned int ids=0; ids < N_DISCRETE_SPACES; ids++)
275  if (flags & (1 << ids))
276  this->compute_field_data( DiscreteSpace(ids), field_ref);
277 }
278 
279 
280 
281 template<int spacedim, class Value>
283 {
284 
285  /* It's possible now to do output to the file only in the first process */
286  if( this->rank != 0) {
287  /* TODO: do something, when support for Parallel VTK is added */
288  return;
289  }
290 
291 
292  // TODO: remove const_cast after resolving problems with const Mesh.
293  Mesh *field_mesh = const_cast<Mesh *>(field.mesh());
294  OLD_ASSERT(!this->_mesh || this->_mesh==field_mesh, "Overwriting non-null mesh pointer.\n");
295  this->_mesh=field_mesh;
296  OLD_ASSERT(this->_mesh, "Null mesh pointer.\n");
297 
298  // get possibly existing data for the same field, check both name and type
299  std::vector<unsigned int> size(N_DISCRETE_SPACES);
300  size[NODE_DATA]=this->_mesh->n_nodes();
301  size[ELEM_DATA]=this->_mesh->n_elements();
302  size[CORNER_DATA]=this->_mesh->n_corners();
303 
304  auto &od_vec=this->output_data_vec_[space_type];
305  auto it=std::find_if(od_vec.begin(), od_vec.end(),
306  [&field](OutputDataPtr ptr) { return (ptr->field_name == field.name()); });
307  if ( it == od_vec.end() ) {
308  od_vec.push_back( std::make_shared< OutputData<Value> >(field, size[space_type]) );
309  it=--od_vec.end();
310  }
311  OutputData<Value> &output_data = dynamic_cast<OutputData<Value> &>(*(*it));
312 
313  unsigned int i_node;
314 
315  /* Copy data to array */
316  switch(space_type) {
317  case NODE_DATA: {
318  // set output data to zero
319  vector<unsigned int> count(output_data.n_values, 0);
320  for(unsigned int idx=0; idx < output_data.n_values; idx++)
321  output_data.zero(idx);
322 
323  // sum values
324  FOR_ELEMENTS(this->_mesh, ele) {
325  FOR_ELEMENT_NODES(ele, i_node) {
326  Node * node = ele->node[i_node];
327  unsigned int ele_index = ele.index();
328  unsigned int node_index = this->_mesh->node_vector.index(ele->node[i_node]);
329 
330  const Value &node_value =
331  Value( const_cast<typename Value::return_type &>(
332  field.value(node->point(),
333  ElementAccessor<spacedim>(this->_mesh, ele_index,false)) ));
334  output_data.add(node_index, node_value);
335  count[node_index]++;
336 
337  }
338  }
339 
340  // Compute mean values at nodes
341  for(unsigned int idx=0; idx < output_data.n_values; idx++)
342  output_data.normalize(idx, count[idx]);
343  }
344  break;
345  case CORNER_DATA: {
346  unsigned int corner_index=0;
347  FOR_ELEMENTS(this->_mesh, ele) {
348  FOR_ELEMENT_NODES(ele, i_node) {
349  Node * node = ele->node[i_node];
350  unsigned int ele_index = ele.index();
351 
352  const Value &node_value =
353  Value( const_cast<typename Value::return_type &>(
354  field.value(node->point(),
355  ElementAccessor<spacedim>(this->_mesh, ele_index,false)) ));
356  output_data.store_value(corner_index, node_value);
357  corner_index++;
358  }
359  }
360  }
361  break;
362  case ELEM_DATA: {
363  FOR_ELEMENTS(this->_mesh, ele) {
364  unsigned int ele_index = ele.index();
365  const Value &ele_value =
366  Value( const_cast<typename Value::return_type &>(
367  field.value(ele->centre(),
368  ElementAccessor<spacedim>(this->_mesh, ele_index,false)) ));
369  //std::cout << ele_index << " ele:" << typename Value::return_type(ele_value) << std::endl;
370  output_data.store_value(ele_index, ele_value);
371  }
372  }
373  break;
374  }
375 
376  /* Set the last time */
377  if(this->time < field.time()) {
378  this->time = field.time();
379  }
380 }
381 
382 
383 #endif
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:57
Common parent class for templated OutputData.
#define FOR_ELEMENT_NODES(i, j)
Definition: elements.h:139
void operate(unsigned int idx, const Value &val, const Func &func)
std::string output_field_name
void print(ostream &out_stream, unsigned int idx) override
unsigned int size() const
Number of subfields that compose the multi-field.
Definition: multi_field.hh:156
Definition: nodes.hh:32
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:408
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:62
void register_data(const DiscreteSpace type, MultiField< spacedim, Value > &multi_field)
Generic method for registering output data stored in MultiField.
~OutputData()
Destructor of OutputData.
Definition: mesh.h:99
unsigned int n_values
NumCompValueType n_elem_
This class is used for storing data that are copied from field.
void zero(unsigned int idx)
OutputData(const FieldCommon &field, unsigned int size)
Constructor of templated OutputData.
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
Value::element_type ElemType
unsigned int DiscreteSpaceFlags
Definition: output_time.hh:211
#define OLD_ASSERT(...)
Definition: global_defs.h:128
double time() const
void add(unsigned int idx, const Value &value)
#define xprintf(...)
Definition: system.hh:87
#define OLD_ASSERT_LESS(a, b)
Definition: global_defs.h:131
void normalize(unsigned int idx, unsigned int divisor)
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:337
void compute_field_data(DiscreteSpace type, Field< spacedim, Value > &field)
unsigned int n_rows
unsigned int n_cols
Value::return_type aux
ElemType * data_
std::string field_name
Definition: system.hh:59
const Mesh * mesh() const
FieldCommon & name(const string &name)
Definition: field_common.hh:83
std::shared_ptr< OutputDataBase > OutputDataPtr
Definition: output_time.hh:183
Class for representation of a vector of fields of the same physical quantity.
Definition: multi_field.hh:55
arma::vec3 & point()
Definition: nodes.hh:68
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:44
void store_value(unsigned int idx, const Value &value)
void print_all(ostream &out_stream) override
Print all data stored in output data.