Flow123d  jenkins-Flow123d-windows32-release-multijob-51
output.h
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 <fstream>
75 #include <ostream>
76 
77 #include "system/system.hh"
78 #include "mesh/mesh.h"
79 
80 #include "fields/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 //class OutputVTK;
88 //class OutputMSH;
89 
90 
91 
92 /**
93  * \brief This class is used for storing data that are copied from field.
94  *
95  *
96  */
97 template <class Value>
98 class OutputData : public OutputDataBase {
99 public:
100  typedef typename Value::element_type ElemType;
101 
102  /**
103  * \brief Constructor of templated OutputData
104  */
105  OutputData(const FieldCommon &field,
106  unsigned int size)
107  : val_aux(aux)
108  {
109  this->field_name = field.name();
110  this->field_units = field.units();
111  this->output_field_name = this->field_name;
112 
113  this->n_values=size;
114  //val_aux.set_n_comp(10); // just to check that n_elem depends on n_comp
115 
116  if (val_aux.NCols_==1) {
117  if (val_aux.NRows_==1) {
118  this->n_elem_ = scalar;
119  this->n_rows = 1;
120  this->n_cols = 1;
121  } else {
122  if (val_aux.NRows_>1) {
123  if (val_aux.NRows_ > 3) {
124  xprintf(PrgErr, "Do not support output of vectors with fixed size >3. Field: %s\n", this->field_name.c_str());
125  } else {
126  this->n_elem_ = vector;
127  this->n_rows = 3;
128  this->n_cols = 1;
129  }
130  } else {
131  THROW(OutputTime::ExcOutputVariableVector() << OutputTime::EI_FieldName(this->field_name));
132  }
133  }
134  } else {
135  this->n_elem_ = tensor;
136  this->n_rows = 3;
137  this->n_cols = 3;
138  }
139 
140 
141  data_ = new ElemType[n_values * n_elem_];
142  }
143 
144 
145  /**
146  * \brief Destructor of OutputData
147  */
149  {
150  delete[] this->data_;
151  }
152 
153 
154  /**
155  * Output data element on given index @p idx. Method for writing data to output stream
156  *
157  * TODO: should at least output whole output value at once, since storage format should be hidden.
158  * TODO: should output whole array at once, otherwise this could be performance bottleneck.
159  * TODO: indicate if the tensor data are output in column-first or raw-first order
160  * and possibly implement transposition. Set such property for individual file formats.
161  * Class OutputData stores always in raw-first order.
162  */
163  void print(ostream &out_stream, unsigned int idx) override
164  {
165  ASSERT_LESS(idx, this->n_values);
166  ElemType *ptr_begin = data_ + n_elem_ * idx;
167  for(ElemType *ptr = ptr_begin; ptr < ptr_begin + n_elem_; ptr++ )
168  out_stream << *ptr << " ";
169  }
170 
171  /**
172  * Store data element of given data value under given index.
173  */
174  void store_value(unsigned int idx, const Value& value) {
175  operate(idx, value, [](ElemType& raw, ElemType val) {raw=val;});
176  };
177 
178  /**
179  * Add value to given index
180  */
181  void add(unsigned int idx, const Value& value) {
182  operate(idx, value, [](ElemType& raw, ElemType val) {raw+=val;});
183  };
184 
185  void zero(unsigned int idx) {
186  operate(idx, val_aux, [](ElemType& raw, ElemType val) {raw=0;});
187  };
188 
189  void normalize(unsigned int idx, unsigned int divisor) {
190  operate(idx, val_aux, [divisor](ElemType& raw, ElemType val) {raw/=divisor;});
191  };
192 
193 
194 
195 private:
196 
197 
198  template <class Func>
199  void operate(unsigned int idx, const Value &val, const Func& func) {
200  ASSERT_LESS(idx, this->n_values);
201  ElemType *ptr = data_ + idx*n_elem_;
202  for(unsigned int i_row=0; i_row < this->n_rows; i_row++)
203  for(unsigned int i_col=0; i_col < this->n_cols; i_col++)
204  {
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 
217  /**
218  * Computed data values for output stored as continuous buffer of their data elements.
219  * One data value has @p n_elem data elements (of type double, int or unsigned int).
220  */
221  ElemType *data_;
222 
223  /// auxiliary value
224  typename Value::return_type aux;
225  // auxiliary field value envelope over @p aux
226  Value val_aux;
227 
228  // Number of rows and cols in stored data element, valid values are
229  // (1,1) for scalar; (3,1) for vectors; (3,3) for tensors
230  unsigned int n_rows, n_cols;
231 
232 
233 
234 };
235 
236 
237 
238 /**************************************************************************************************************
239  * OutputTime implementation
240  */
241 
242 template<int spacedim, class Value>
244  MultiField<spacedim, Value> &multi_field)
245 {
246  if (output_names.find(multi_field.name()) != output_names.end()) {
247  if (output_names[multi_field.name()] == true)
248  for (unsigned long index=0; index < multi_field.size(); index++)
249  this->compute_field_data(type, multi_field[index] );
250 
251  return;
252  }
253  else
254  {
255  // We are trying to output field that is not recognized by the stream.
256  //DBGMSG("Internal error: Output stream %s does not support field %s.\n", name.c_str(), multi_field.name().c_str());
257  }
258 }
259 
260 
261 template<int spacedim, class Value>
263  Field<spacedim, Value> &field_ref)
264 {
265  if (output_names.find(field_ref.name()) != output_names.end()) {
266  if (output_names[field_ref.name()] == true)
267  this->compute_field_data(ref_type, field_ref);
268 
269  return;
270  }
271  else
272  {
273  // We are trying to output field that is not recognized by the stream.
274  //DBGMSG("Internal error: Output stream %s does not support field %s.\n", name.c_str(), field_ref.name().c_str());
275  }
276 }
277 
278 
279 template<int spacedim, class Value>
281 {
282 
283  /* It's possible now to do output to the file only in the first process */
284  if( this->rank != 0) {
285  /* TODO: do something, when support for Parallel VTK is added */
286  return;
287  }
288 
289 
290  // TODO: remove const_cast after resolving problems with const Mesh.
291  mesh = const_cast<Mesh *>(field.mesh());
292  ASSERT(mesh, "Null mesh pointer.\n");
293 
294  // get possibly existing data for the same field, check both name and type
295  OutputDataBase *data = output_data_by_field_name(field.name(), space_type);
296  OutputData<Value> *output_data = dynamic_cast<OutputData<Value> *>(data);
297 
298  if (!output_data) {
299  switch(space_type) {
300  case NODE_DATA:
301  output_data = new OutputData<Value>(field, mesh->n_nodes());
302  node_data.push_back(output_data);
303  break;
304  case CORNER_DATA: {
305  unsigned int n_corners = 0;
306  FOR_ELEMENTS(mesh, ele)
307  n_corners += ele->n_nodes();
308  output_data = new OutputData<Value>(field, n_corners );
309  corner_data.push_back(output_data);
310  }
311  break;
312  case ELEM_DATA:
313  output_data = new OutputData<Value>(field, mesh->n_elements() );
314  elem_data.push_back(output_data);
315  break;
316  }
317  }
318 
319  unsigned int i_node;
320 
321  /* Copy data to array */
322  switch(space_type) {
323  case NODE_DATA: {
324  // set output data to zero
325  vector<unsigned int> count(output_data->n_values, 0);
326  for(unsigned int idx=0; idx < output_data->n_values; idx++)
327  output_data->zero(idx);
328 
329  // sum values
330  FOR_ELEMENTS(mesh, ele) {
331  FOR_ELEMENT_NODES(ele, i_node) {
332  Node * node = ele->node[i_node];
333  unsigned int ele_index = ele.index();
334  unsigned int node_index = mesh->node_vector.index(ele->node[i_node]);
335 
336  const Value &node_value =
337  Value( const_cast<typename Value::return_type &>(
338  field.value(node->point(), ElementAccessor<spacedim>(mesh, ele_index,false)) ));
339  output_data->add(node_index, node_value);
340  count[node_index]++;
341 
342  }
343  }
344 
345  // Compute mean values at nodes
346  for(unsigned int idx=0; idx < output_data->n_values; idx++)
347  output_data->normalize(idx, count[idx]);
348  }
349  break;
350  case CORNER_DATA: {
351  unsigned int corner_index=0;
352  FOR_ELEMENTS(mesh, ele) {
353  FOR_ELEMENT_NODES(ele, i_node) {
354  Node * node = ele->node[i_node];
355  unsigned int ele_index = ele.index();
356 
357  const Value &node_value =
358  Value( const_cast<typename Value::return_type &>(
359  field.value(node->point(), ElementAccessor<spacedim>(mesh, ele_index,false)) ));
360  output_data->store_value(corner_index, node_value);
361  corner_index++;
362  }
363  }
364  }
365  break;
366  case ELEM_DATA: {
367  FOR_ELEMENTS(mesh, ele) {
368  unsigned int ele_index = ele.index();
369  const Value &ele_value =
370  Value( const_cast<typename Value::return_type &>(
371  field.value(ele->centre(), ElementAccessor<spacedim>(mesh, ele_index,false)) ));
372  //std::cout << ele_index << " ele:" << typename Value::return_type(ele_value) << std::endl;
373  output_data->store_value(ele_index, ele_value);
374  }
375  }
376  break;
377  }
378 
379  /* Set the last time */
380  if(this->time < field.time()) {
381  this->time = field.time();
382  }
383 }
384 
385 
386 #endif
double time
The newest time of registered data.
Definition: output_time.hh:274
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:45
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)
Definition: output.h:199
std::string output_field_name
void print(ostream &out_stream, unsigned int idx) override
Definition: output.h:163
unsigned int size() const
Number of subfields that compose the multi-field.
Definition: field.hh:365
Definition: nodes.hh:44
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:357
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:48
void register_data(const DiscreteSpace type, MultiField< spacedim, Value > &multi_field)
Generic method for registering output data stored in MultiField.
Definition: output.h:243
???
~OutputData()
Destructor of OutputData.
Definition: output.h:148
Definition: mesh.h:108
unsigned int n_values
This class is used for storing data that are copied from field.
Definition: output.h:98
void zero(unsigned int idx)
Definition: output.h:185
OutputData(const FieldCommon &field, unsigned int size)
Constructor of templated OutputData.
Definition: output.h:105
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
vector< OutputDataBase * > node_data
Definition: output_time.hh:267
Value::element_type ElemType
Definition: output.h:100
double time() const
unsigned int n_elements() const
Definition: mesh.h:137
#define ASSERT(...)
Definition: global_defs.h:121
void compute_field_data(DiscreteSpace space, Field< spacedim, Value > &field)
Definition: output.h:280
Value val_aux
Definition: output.h:226
void add(unsigned int idx, const Value &value)
Definition: output.h:181
#define xprintf(...)
Definition: system.hh:100
#define ASSERT_LESS(a, b)
Definition: global_defs.h:164
OutputDataBase * output_data_by_field_name(const string &field_name, DiscreteSpace ref_type)
This method returns pointer at existing data, when corresponding output data exists or it creates new...
Definition: output.cc:94
void normalize(unsigned int idx, unsigned int divisor)
Definition: output.h:189
vector< OutputDataBase * > elem_data
Definition: output_time.hh:269
map< string, bool > output_names
Map of names of output fields. True means that field will be saved.
Definition: output_time.hh:278
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:399
int rank
MPI rank of process (is tested in methods)
Definition: output_time.hh:261
unsigned int n_rows
Definition: output.h:230
unsigned int n_cols
Definition: output.h:230
Value::return_type aux
auxiliary value
Definition: output.h:224
ElemType * data_
Definition: output.h:211
std::string field_name
Mesh * mesh
Definition: output_time.hh:174
Definition: system.hh:72
const Mesh * mesh() const
FieldCommon & name(const string &name)
Definition: field_common.hh:71
unsigned int n_nodes() const
Definition: mesh.h:133
Class for representation of a vector of fields of the same physical quantity.
Definition: field.hh:309
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:196
void store_value(unsigned int idx, const Value &value)
Definition: output.h:174
vector< OutputDataBase * > corner_data
Definition: output_time.hh:268