Flow123d
output.cc
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.cc 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.cc
26  * @brief The functions for all outputs (methods of classes: Output and OutputTime).
27  *
28  */
29 
30 #include <string>
31 #include <typeinfo>
32 #include <petsc.h>
33 #include <boost/any.hpp>
34 #include <assert.h>
35 
36 #include "system/xio.h"
37 #include "io/output.h"
38 #include "io/output_vtk.h"
39 #include "io/output_msh.h"
40 #include "mesh/mesh.h"
41 #include "input/accessors.hh"
42 
43 
44 using namespace Input::Type;
45 
47  = Record("OutputStream", "Parameters of output.")
48  // The stream
50  "File path to the connected output file.")
51  // The format
53  "Format of output stream and possible parameters.")
54  .declare_key("time_step", Double(0.0),
55  "Time interval between outputs.\n"
56  "Regular grid of output time points starts at the initial time of the equation and ends at the end time which must be specified.\n"
57  "The start time and the end time are always added. ")
58  .declare_key("time_list", Array(Double(0.0)),
59  "Explicit array of output time points (can be combined with 'time_step'.")
60  .declare_key("add_input_times", Bool(), Default("false"),
61  "Add all input time points of the equation, mentioned in the 'input_fields' list, also as the output points.");
62 
63 
65  = AbstractRecord("OutputTime",
66  "Format of output stream and possible parameters.");
67 
68 /**
69  * \brief This method add right suffix to .pvd VTK file
70  */
71 static inline void fix_VTK_file_name(string *fname)
72 {
73  // When VTK file doesn't .pvd suffix, then add .pvd suffix to this file name
74  if(fname->compare(fname->size()-4, 4, ".pvd") != 0) {
75  xprintf(Warn, "Renaming name of output file from: %s to %s.pvd\n", fname->c_str(), fname->c_str());
76  *fname = *fname + ".pvd";
77  }
78 }
79 
80 /**
81  * \brief This method add right suffix to .msh GMSH file
82  */
83 static inline void fix_GMSH_file_name(string *fname)
84 {
85  // When GMSH file doesn't .msh suffix, then add .msh suffix to this file name
86  if(fname->compare(fname->size()-4, 4, ".msh") != 0) {
87  xprintf(Warn, "Renaming name of output file from: %s to %s.msh\n", fname->c_str(), fname->c_str());
88  *fname = *fname + ".msh";
89  }
90 }
91 
92 
94  (const std::string &field_name, DiscreteSpace ref_type)
95 {
96  std::vector<OutputDataBase*> *data_vector;
97 
98  switch(ref_type) {
99  case NODE_DATA:
100  data_vector = &this->node_data;
101  break;
102  case CORNER_DATA:
103  data_vector = &this->corner_data;
104  break;
105  case ELEM_DATA:
106  data_vector = &this->elem_data;
107  break;
108  }
109 
110  /* Try to find existing data */
111  for(auto &data : *data_vector)
112  if (data->field_name == field_name) return data;
113 
114  return nullptr;
115 }
116 
117 /* Initialize static member of the class */
119 
120 // Destroy all objects
122 {
123  // Delete all objects
125  ot_iter != OutputTime::output_streams.end();
126  ++ot_iter)
127  {
128  delete *ot_iter;
129  }
130 
132 }
133 
134 /*
135 OutputTime *OutputTime::output_stream_by_name(string name)
136 {
137  OutputTime *output_time;
138  // Try to find existing object
139  for(std::vector<OutputTime*>::iterator output_iter = OutputTime::output_streams.begin();
140  output_iter != OutputTime::output_streams.end();
141  ++output_iter)
142  {
143  output_time = (*output_iter);
144  if( output_time->name == name) {
145  return output_time;
146  }
147  }
148 
149  return NULL;
150 }
151 */
152 
153 /*
154 OutputTime *OutputTime::output_stream_by_key_name(const Input::Record &in_rec, const string key_name)
155 {
156  // TODO: do not try to find empty string and raise exception
157 
158  // Try to find record with output stream (the key is name of data)
159  Input::Iterator<string> stream_name_iter = in_rec.find<string>(key_name);
160 
161  // If record was not found, then throw exception
162  if(!stream_name_iter) {
163  return nullptr;
164  }
165 
166  // Try to find existing output stream
167  return output_stream_by_name(*stream_name_iter);
168 }
169 */
170 
172 {
173  OutputTime* output_time;
174 
176 
177  if(format) {
178  if((*format).type() == OutputVTK::input_type) {
179  output_time = new OutputVTK(in_rec);
180  } else if ( (*format).type() == OutputMSH::input_type) {
181  output_time = new OutputMSH(in_rec);
182  } else {
183  xprintf(Warn, "Unsupported file format, using default VTK\n");
184  output_time = new OutputVTK(in_rec);
185  }
186  } else {
187  output_time = new OutputVTK(in_rec);
188  }
189 
190  return output_time;
191 }
192 
193 /*
194 OutputTime *OutputTime::output_stream(const Input::Record &in_rec)
195 {
196  // testing rank of process
197  int ierr, rank;
198  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
199  ASSERT(ierr == 0, "Error in MPI_Comm_rank.");
200 
201  // It's possible now to do output to the file only in the first process
202  //if(rank != 0) {
203  // xprintf(MsgLog, "NOT MASTER PROC\n");
204  // // TODO: do something, when support for Parallel VTK is added
205  // return NULL;
206  //}
207 
208  OutputTime *output_time;
209  string name = in_rec.val<string>("name");
210 
211  xprintf(MsgLog, "Trying to find output_stream: %s ... ", name.c_str());
212 
213  output_time = OutputTime::output_stream_by_name(name);
214  if(output_time != NULL) {
215  xprintf(MsgLog, "FOUND\n");
216  return output_time;
217  }
218 
219  xprintf(MsgLog, "NOT FOUND. Creating new ... ");
220 
221  output_time = OutputTime::create_output_stream(in_rec);
222  OutputTime::output_streams.push_back(output_time);
223 
224  xprintf(MsgLog, "DONE\n");
225 
226  ASSERT(output_time == OutputTime::output_stream_by_name(name),"Wrong stream push back.\n");
227  return output_time;
228 }
229 */
230 
232 {
233  vector<Input::Enum> field_ids;
234  in_array.copy_to(field_ids);
235 
236  // first copy all possible field names from selection
237  for (auto it = in_sel.begin(); it != in_sel.end(); ++it)
238  //output_names.emplace(it->key_, false); //introduced in gcc4.8 (C++11) - does not work with gcc4.7
239  output_names.insert(std::pair<std::string, bool>(it->key_,false));
240 
241  // then mark those fields that will be saved
242  for (auto it: field_ids)
243  if (in_sel.has_value(it))
244  output_names[in_sel.int_to_name(it)] = true;
245 }
246 
247 
249 : input_record_(in_rec)
250 {
251  int ierr;
253  ASSERT(ierr == 0, "Error in MPI_Comm_rank.");
254 
255  /* It's possible now to do output to the file only in the first process */
256  //if(rank!=0) {
257  // /* TODO: do something, when support for Parallel VTK is added */
258  // return;
259  //}
260 
261  Mesh *mesh = NULL; // This is set, when first register_* method is called
262 
263  ofstream *base_file;
264  string *base_filename;
265 
266  string fname = in_rec.val<FilePath>("file");
267  //string stream_name = in_rec.val<string>("name");
268 
270 
271  // TODO: move this part to OutputVTK.cc and OutputMSH.cc
272  // Check if file suffix is suffix of specified file format
273  if(format) {
274  if((*format).type() == OutputVTK::input_type) {
275  // This should be pvd file format
276  fix_VTK_file_name(&fname);
277  } else if((*format).type() == OutputMSH::input_type) {
278  // This should be msh file format
279  fix_GMSH_file_name(&fname);
280  } else {
281  // Unsuported file format
282  fix_VTK_file_name(&fname);
283  }
284  } else {
285  // Default file format is VTK
286  fix_VTK_file_name(&fname);
287  }
288 
289  base_file = new ofstream;
290 
291  if (rank==0) {
292  base_file->open(fname.c_str());
293  INPUT_CHECK( base_file->is_open() , "Can not open output file: %s\n", fname.c_str() );
294  xprintf(MsgLog, "Writing flow output file: %s ... \n", fname.c_str());
295  }
296 
297  base_filename = new string(fname);
298 
299  //this->name = stream_name;
300  this->current_step = 0;
301 
302  set_base_file(base_file);
304  set_mesh(mesh);
305 
306  this->time = -1.0;
307  this->write_time = -1.0;
308 
309 }
310 
312 {
313  /* It's possible now to do output to the file only in the first process */
314  //if(rank != 0) {
315  // /* TODO: do something, when support for Parallel VTK is added */
316  // return;
317  // }
318 
319  if(this->_base_filename != NULL) {
320  delete this->_base_filename;
321  }
322 
323  if(base_file != NULL) {
324  base_file->close();
325  delete base_file;
326  }
327 
328  xprintf(MsgLog, "O.K.\n");
329 }
330 
331 
333 {
334  TimeMark::Type output_mark_type = tg.equation_fixed_mark_type() | tg.marks().type_output();
335 
336  double time_step;
337  if (input_record_.opt_val("time_step", time_step)) {
338  tg.add_time_marks_grid(time_step, output_mark_type);
339  }
340 
341  Input::Array time_list;
342  if (input_record_.opt_val("time_list", time_list)) {
344  time_list.copy_to(list);
345  for( double time : list) tg.marks().add(TimeMark(time, output_mark_type));
346  }
347 
348  bool add_flag;
349  if (input_record_.opt_val("add_input_times", add_flag) && add_flag) {
350  TimeMark::Type input_mark_type = tg.equation_mark_type() | tg.marks().type_input();
351  vector<double> mark_times;
352  // can not add marks while iterating through time marks
353  for(auto it = tg.marks().begin(input_mark_type); it != tg.marks().end(input_mark_type); ++it)
354  mark_times.push_back(it->time());
355  for(double time : mark_times)
356  tg.marks().add( TimeMark(time, output_mark_type) );
357 
358  }
359 
360 }
361 
362 
364 {
365  int ierr, rank;
366  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
367  ASSERT(ierr == 0, "Error in MPI_Comm_rank.");
368 
369  OutputTime *output_time = NULL;
370 
371  /* TODO: do something, when support for Parallel VTK is added */
372  if (rank == 0) {
373  // Write data to output stream, when data registered to this output
374  // streams were changed
375  if(write_time < time) {
376  xprintf(MsgLog, "Write output to output stream: %s for time: %f\n", _base_filename->c_str(), time);
377  write_data();
378  // Remember the last time of writing to output stream
379  write_time = time;
380  current_step++;
381  } else {
382  xprintf(MsgLog, "Skipping output stream: %s in time: %f\n", _base_filename->c_str(), time);
383  }
384  }
385  clear_data();
386 }
387 /*
388 void OutputTime::write_all_data(void)
389 {
390  int ierr, rank;
391  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
392  ASSERT(ierr == 0, "Error in MPI_Comm_rank.");
393 
394  OutputTime *output_time = NULL;
395 
396  // It's possible now to do output to the file only in the first process
397 //if(rank != 0) {
398 // // TODO: do something, when support for Parallel VTK is added
399 // return;
400 // }
401  if (rank == 0) {
402  // Go through all OutputTime objects
403  for(std::vector<OutputTime*>::iterator stream_iter = OutputTime::output_streams.begin();
404  stream_iter != OutputTime::output_streams.end();
405  ++stream_iter)
406  {
407  // Write data to output stream, when data registered to this output
408  // streams were changed
409  output_time = (*stream_iter);
410  if(output_time->write_time < output_time->time) {
411  xprintf(MsgLog, "Write output to output stream: %s for time: %f\n",
412  output_time->name.c_str(),
413  output_time->time);
414  output_time->write_data();
415  // Remember the last time of writing to output stream
416  output_time->write_time = output_time->time;
417  output_time->current_step++;
418  } else {
419  xprintf(MsgLog, "Skipping output stream: %s in time: %f\n",
420  output_time->name.c_str(),
421  output_time->time);
422  }
423  }
424  }
425 
426  // Free all registered data
427  for(auto *stream : OutputTime::output_streams) stream->clear_data();
428 }
429 */
430 
432 {
433  node_data.clear();
434  corner_data.clear();
435  elem_data.clear();
436 }
437 
438 
439 
440 #define INSTANCE_register_field(spacedim, value) \
441  template void OutputTime::register_data<spacedim, value> \
442  (const DiscreteSpace ref_type, Field<spacedim, value> &field);
443 
444 #define INSTANCE_register_multifield(spacedim, value) \
445  template void OutputTime::register_data<spacedim, value> \
446  (const DiscreteSpace ref_type, MultiField<spacedim, value> &field);
447 
448 
449 #define INSTANCE_OutputData(spacedim, value) \
450  template class OutputData<value>;
451 
452 
453 #define INSTANCE_DIM_DEP_VALUES( MACRO, dim_from, dim_to) \
454  MACRO(dim_from, FieldValue<dim_to>::VectorFixed ) \
455  MACRO(dim_from, FieldValue<dim_to>::TensorFixed )
456 
457 #define INSTANCE_TO_ALL( MACRO, dim_from) \
458  MACRO(dim_from, FieldValue<0>::Enum ) \
459  MACRO(dim_from, FieldValue<0>::EnumVector) \
460  MACRO(dim_from, FieldValue<0>::Integer) \
461  MACRO(dim_from, FieldValue<0>::Scalar) \
462  MACRO(dim_from, FieldValue<0>::Vector) \
463 \
464 INSTANCE_DIM_DEP_VALUES(MACRO, dim_from, 2) \
465 INSTANCE_DIM_DEP_VALUES(MACRO, dim_from, 3) \
466 
467 #define INSTANCE_ALL(MACRO) \
468  INSTANCE_TO_ALL( MACRO, 3) \
469  INSTANCE_TO_ALL( MACRO, 2)
470 
471 
474 
475 //INSTANCE_TO_ALL( INSTANCE_OutputData, 0)
476 
477 
478 //INSTANCE_register_field(3, FieldValue<0>::Scalar)
479 //INSTANCE_register_multifield(3, FieldValue<0>::Scalar)
480 //INSTANCE_OutputData(3, FieldValue<0>::Scalar)