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