OGS
Output.cpp
Go to the documentation of this file.
1 
11 #include "Output.h"
12 
13 #include <cassert>
14 #include <exception>
15 #include <fstream>
16 #include <vector>
17 
19 #include "BaseLib/FileTools.h"
20 #include "BaseLib/Logging.h"
21 #include "BaseLib/RunTime.h"
22 #include "ProcessLib/Process.h"
23 
24 namespace
25 {
28 int convertVtkDataMode(std::string const& data_mode)
29 {
30  if (data_mode == "Ascii")
31  {
32  return 0;
33  }
34  if (data_mode == "Binary")
35  {
36  return 1;
37  }
38  if (data_mode == "Appended")
39  {
40  return 2;
41  }
42  OGS_FATAL(
43  "Unsupported vtk output file data mode '{:s}'. Expected Ascii, Binary, "
44  "or Appended.",
45  data_mode);
46 }
47 
48 std::string constructPVDName(std::string const& output_directory,
49  std::string const& output_file_prefix,
50  std::string const& mesh_name)
51 {
52  return BaseLib::joinPaths(output_directory,
54  output_file_prefix, mesh_name, 0, 0, 0) +
55  ".pvd");
56 }
57 } // namespace
58 
59 namespace ProcessLib
60 {
61 bool Output::shallDoOutput(int timestep, double const t)
62 {
63  auto const fixed_output_time = std::lower_bound(
64  cbegin(_fixed_output_times), cend(_fixed_output_times), t);
65  if ((fixed_output_time != cend(_fixed_output_times)) &&
66  (std::abs(*fixed_output_time - t) <
67  std::numeric_limits<double>::epsilon()))
68  {
69  return true;
70  }
71 
72  int each_steps = 1;
73 
74  for (auto const& pair : _repeats_each_steps)
75  {
76  each_steps = pair.each_steps;
77 
78  if (timestep > pair.repeat * each_steps)
79  {
80  timestep -= pair.repeat * each_steps;
81  }
82  else
83  {
84  break;
85  }
86  }
87 
88  if (timestep % each_steps == 0)
89  {
90  return true;
91  }
92 
93  return false;
94 }
95 
96 Output::Output(std::string directory, OutputType file_type,
97  std::string file_prefix, std::string file_suffix,
98  bool const compress_output, unsigned int const n_files,
99  std::string const& data_mode,
100  bool const output_nonlinear_iteration_results,
101  std::vector<PairRepeatEachSteps> repeats_each_steps,
102  std::vector<double>&& fixed_output_times,
103  OutputDataSpecification&& output_data_specification,
104  std::vector<std::string>&& mesh_names_for_output,
105  std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes)
106  : _output_directory(std::move(directory)),
107  _output_file_type(file_type),
108  _output_file_prefix(std::move(file_prefix)),
109  _output_file_suffix(std::move(file_suffix)),
110  _output_file_compression(compress_output),
111  _n_files(n_files),
112  _output_file_data_mode(convertVtkDataMode(data_mode)),
113  _output_nonlinear_iteration_results(output_nonlinear_iteration_results),
114  _repeats_each_steps(std::move(repeats_each_steps)),
115  _fixed_output_times(std::move(fixed_output_times)),
116  _output_data_specification(std::move(output_data_specification)),
117  _mesh_names_for_output(mesh_names_for_output),
118  _meshes(meshes)
119 {
120  if (!std::is_sorted(cbegin(_fixed_output_times), cend(_fixed_output_times)))
121  {
122  OGS_FATAL(
123  "Vector of fixed output time steps passed to the Output "
124  "constructor must be sorted");
125  }
126 }
127 
129 {
130  if (_mesh_names_for_output.empty())
131  {
132  _mesh_names_for_output.push_back(process.getMesh().getName());
133  }
134 
135  for (auto const& mesh_output_name : _mesh_names_for_output)
136  {
137  auto const filename = constructPVDName(
138  _output_directory, _output_file_prefix, mesh_output_name);
139  _process_to_pvd_file.emplace(std::piecewise_construct,
140  std::forward_as_tuple(&process),
141  std::forward_as_tuple(filename));
142  }
143 }
144 
145 // TODO return a reference.
147  Process const& process,
148  const int process_id,
149  std::string const& mesh_name_for_output)
150 {
151  auto const filename = constructPVDName(
152  _output_directory, _output_file_prefix, mesh_name_for_output);
153  auto range = _process_to_pvd_file.equal_range(&process);
154  int counter = 0;
155  MeshLib::IO::PVDFile* pvd_file = nullptr;
156  for (auto spd_it = range.first; spd_it != range.second; ++spd_it)
157  {
158  if (spd_it->second.pvd_filename == filename)
159  {
160  if (counter == process_id)
161  {
162  pvd_file = &spd_it->second;
163  break;
164  }
165  counter++;
166  }
167  }
168  if (pvd_file == nullptr)
169  {
170  OGS_FATAL(
171  "The given process is not contained in the output configuration. "
172  "Aborting.");
173  }
174 
175  return pvd_file;
176 }
177 
179 {
180  OutputFile(std::string const& directory, OutputType const type,
181  std::string const& prefix, std::string const& suffix,
182  std::string const& mesh_name, int const timestep, double const t,
183  int const iteration, int const data_mode_,
184  bool const compression_,
185  std::set<std::string> const& outputnames,
186  unsigned int const n_files)
187  : name(constructFilename(type, prefix, suffix, mesh_name, timestep, t,
188  iteration)),
189  path(BaseLib::joinPaths(directory, name)),
190  type(type),
191  data_mode(data_mode_),
192  compression(compression_),
195  {
196  }
197 
198  std::string const name;
199  std::string const path;
205  int const data_mode;
207  bool const compression;
208  std::set<std::string> outputnames;
209  unsigned int n_files;
210  static std::string constructFilename(OutputType const type,
211  std::string prefix, std::string suffix,
212  std::string mesh_name,
213  int const timestep, double const t,
214  int const iteration)
215  {
216  std::map<OutputType, std::string> filetype_to_extension = {
217  {OutputType::vtk, "vtu"}, {OutputType::xdmf, "xdmf"}};
218 
219  try
220  {
221  std::string extension = filetype_to_extension.at(type);
222  return BaseLib::constructFormattedFileName(prefix, mesh_name,
223  timestep, t, iteration) +
224  BaseLib::constructFormattedFileName(suffix, mesh_name,
225  timestep, t, iteration) +
226  "." + extension;
227  }
228  catch (std::out_of_range&)
229  {
230  OGS_FATAL(
231  "No supported file type provided. Read `{:s}' from <output><type> \
232  in prj file. Supported: VTK, XDMF.",
233  type);
234  }
235  }
236 };
237 
239  OutputFile const& output_file,
240  std::vector<std::reference_wrapper<const MeshLib::Mesh>>
241  meshes,
242  int const timestep,
243  double const t)
244 {
245  // \TODO (tm) Refactor to a dedicated VTKOutput and XdmfOutput
246  // The XdmfOutput will create on construction the XdmfHdfWriter
248  {
249  std::filesystem::path path(output_file.path);
250  _mesh_xdmf_hdf_writer = std::make_unique<MeshLib::IO::XdmfHdfWriter>(
251  std::move(meshes), path, timestep, t,
253  output_file.compression, output_file.n_files);
254  }
255  else
256  {
257  _mesh_xdmf_hdf_writer->writeStep(t);
258  };
259 }
260 
261 void Output::outputMesh(OutputFile const& output_file,
262  MeshLib::IO::PVDFile* const pvd_file,
263  MeshLib::Mesh const& mesh,
264  double const t)
265 {
266  DBUG("output to {:s}", output_file.path);
267 
268  if (output_file.type == OutputType::vtk)
269  {
270  pvd_file->addVTUFile(output_file.name, t);
271  }
272 
273  makeOutput(output_file.path, mesh, output_file.compression,
274  output_file.data_mode);
275 }
276 
277 void Output::doOutputAlways(Process const& process,
278  const int process_id,
279  int const timestep,
280  const double t,
281  int const iteration,
282  std::vector<GlobalVector*> const& x)
283 {
284  BaseLib::RunTime time_output;
285  time_output.start();
286 
287  std::vector<NumLib::LocalToGlobalIndexMap const*> dof_tables;
288  dof_tables.reserve(x.size());
289  for (std::size_t i = 0; i < x.size(); ++i)
290  {
291  dof_tables.push_back(&process.getDOFTable(i));
292  }
293 
294  bool output_secondary_variable = true;
295  // Need to add variables of process to vtu even no output takes place.
296  addProcessDataToMesh(t, x, process_id, process.getMesh(), dof_tables,
297  dof_tables, process.getProcessVariables(process_id),
298  process.getSecondaryVariables(),
299  output_secondary_variable,
300  process.getIntegrationPointWriter(process.getMesh()),
302 
303  // For the staggered scheme for the coupling, only the last process, which
304  // gives the latest solution within a coupling loop, is allowed to make
305  // output.
306  if (!(process_id == static_cast<int>(_process_to_pvd_file.size() /
307  _mesh_names_for_output.size()) -
308  1 ||
309  process.isMonolithicSchemeUsed()))
310  {
311  return;
312  }
313 
314  auto output_bulk_mesh =
315  [&](std::vector<std::reference_wrapper<const MeshLib::Mesh>> meshes)
316  {
317  MeshLib::IO::PVDFile* pvd_file = nullptr;
319  {
320  for (auto const& mesh : meshes)
321  {
322  OutputFile const file(
324  _output_file_suffix, mesh.get().getName(), timestep, t,
327 
328  pvd_file =
329  findPVDFile(process, process_id, mesh.get().getName());
330  outputMesh(file, pvd_file, mesh, t);
331  }
332  }
334  {
335  std::string name = meshes[0].get().getName();
336  OutputFile const file(
338  name, timestep, t, iteration, _output_file_data_mode,
341 
342  outputMeshXdmf(std::move(file), std::move(meshes), timestep, t);
343  }
344  };
345 
346  std::vector<std::reference_wrapper<const MeshLib::Mesh>> output_meshes;
347  for (auto const& mesh_output_name : _mesh_names_for_output)
348  {
349  // process related output
350  if (process.getMesh().getName() == mesh_output_name)
351  {
352  output_meshes.push_back(process.getMesh());
353  continue;
354  }
355  // mesh related output
356  auto& non_bulk_mesh = *BaseLib::findElementOrError(
357  begin(_meshes), end(_meshes),
358  [&mesh_output_name](auto const& m)
359  { return m->getName() == mesh_output_name; },
360  "Need mesh '" + mesh_output_name + "' for the output.");
361 
362  std::vector<MeshLib::Node*> const& nodes = non_bulk_mesh.getNodes();
363  DBUG("Found {:d} nodes for output at mesh '{:s}'.", nodes.size(),
364  non_bulk_mesh.getName());
365 
366  std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>>
367  mesh_dof_tables;
368  mesh_dof_tables.reserve(x.size());
369  for (std::size_t i = 0; i < x.size(); ++i)
370  {
371  mesh_dof_tables.push_back(
373  MeshLib::MeshSubset{non_bulk_mesh, nodes}));
374  }
375  std::vector<NumLib::LocalToGlobalIndexMap const*>
376  mesh_dof_table_pointers;
377  mesh_dof_table_pointers.reserve(mesh_dof_tables.size());
378  transform(cbegin(mesh_dof_tables), cend(mesh_dof_tables),
379  back_inserter(mesh_dof_table_pointers),
380  [](std::unique_ptr<NumLib::LocalToGlobalIndexMap> const& p)
381  { return p.get(); });
382 
383  output_secondary_variable = false;
385  t, x, process_id, non_bulk_mesh, dof_tables,
386  mesh_dof_table_pointers, process.getProcessVariables(process_id),
387  process.getSecondaryVariables(), output_secondary_variable,
388  process.getIntegrationPointWriter(non_bulk_mesh),
390 
391  output_meshes.push_back(non_bulk_mesh);
392  }
393 
394  output_bulk_mesh(std::move(output_meshes));
395  INFO("[time] Output of timestep {:d} took {:g} s.", timestep,
396  time_output.elapsed());
397 }
398 
399 void Output::doOutput(Process const& process,
400  const int process_id,
401  int const timestep,
402  const double t,
403  int const iteration,
404  std::vector<GlobalVector*> const& x)
405 {
406  if (shallDoOutput(timestep, t))
407  {
408  doOutputAlways(process, process_id, timestep, t, iteration, x);
409  }
410 #ifdef USE_INSITU
411  // Note: last time step may be output twice: here and in
412  // doOutputLastTimestep() which throws a warning.
413  InSituLib::CoProcess(process.getMesh(), t, timestep, false,
415 #endif
416 }
417 
419  const int process_id,
420  int const timestep,
421  const double t,
422  int const iteration,
423  std::vector<GlobalVector*> const& x)
424 {
425  if (!shallDoOutput(timestep, t))
426  {
427  doOutputAlways(process, process_id, timestep, t, iteration, x);
428  }
429 #ifdef USE_INSITU
430  InSituLib::CoProcess(process.getMesh(), t, timestep, true,
432 #endif
433 }
434 
436  const int process_id,
437  int const timestep, const double t,
438  int const iteration,
439  std::vector<GlobalVector*> const& x)
440 {
442  {
443  return;
444  }
445 
446  BaseLib::RunTime time_output;
447  time_output.start();
448 
449  std::vector<NumLib::LocalToGlobalIndexMap const*> dof_tables;
450  for (std::size_t i = 0; i < x.size(); ++i)
451  {
452  dof_tables.push_back(&process.getDOFTable(i));
453  }
454 
455  bool const output_secondary_variable = true;
456  addProcessDataToMesh(t, x, process_id, process.getMesh(), dof_tables,
457  dof_tables, process.getProcessVariables(process_id),
458  process.getSecondaryVariables(),
459  output_secondary_variable,
460  process.getIntegrationPointWriter(process.getMesh()),
462 
463  // For the staggered scheme for the coupling, only the last process, which
464  // gives the latest solution within a coupling loop, is allowed to make
465  // output.
466  if (!(process_id == static_cast<int>(_process_to_pvd_file.size()) - 1 ||
467  process.isMonolithicSchemeUsed()))
468  {
469  return;
470  }
471 
472  // Only check whether a process data is available for output.
473  findPVDFile(process, process_id, process.getMesh().getName());
474 
475  std::string const output_file_name = OutputFile::constructFilename(
477  process.getMesh().getName(), timestep, t, iteration);
478 
479  std::string const output_file_path =
480  BaseLib::joinPaths(_output_directory, output_file_name);
481 
482  DBUG("output iteration results to {:s}", output_file_path);
483  makeOutput(output_file_path, process.getMesh(), _output_file_compression,
485  INFO("[time] Output took {:g} s.", time_output.elapsed());
486 }
487 } // namespace ProcessLib
#define OGS_FATAL(...)
Definition: Error.h:26
Filename manipulation routines.
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void DBUG(char const *fmt, Args const &... args)
Definition: Logging.h:27
Definition of the RunTime class.
Count the running time.
Definition: RunTime.h:29
double elapsed() const
Get the elapsed time in seconds.
Definition: RunTime.h:42
void start()
Start the timer.
Definition: RunTime.h:32
void addVTUFile(std::string const &vtu_fname, double timestep)
Add a VTU file to this PVD file.
Definition: PVDFile.cpp:24
A subset of nodes on a single mesh.
Definition: MeshSubset.h:27
const std::string getName() const
Get name of the mesh.
Definition: Mesh.h:92
LocalToGlobalIndexMap * deriveBoundaryConstrainedMap(int const variable_id, std::vector< int > const &component_ids, MeshLib::MeshSubset &&new_mesh_subset) const
std::vector< PairRepeatEachSteps > _repeats_each_steps
Describes after which timesteps to write output.
Definition: Output.h:121
void doOutputNonlinearIteration(Process const &process, const int process_id, int const timestep, const double t, const int iteration, std::vector< GlobalVector * > const &x)
Definition: Output.cpp:435
bool const _output_file_compression
Enables or disables zlib-compression of the output files.
Definition: Output.h:110
std::vector< std::string > _mesh_names_for_output
Definition: Output.h:143
std::string const _output_file_prefix
Definition: Output.h:106
OutputDataSpecification const _output_data_specification
Definition: Output.h:142
Output(std::string directory, OutputType const type, std::string prefix, std::string suffix, bool const compress_output, unsigned int n_files, std::string const &data_mode, bool const output_nonlinear_iteration_results, std::vector< PairRepeatEachSteps > repeats_each_steps, std::vector< double > &&fixed_output_times, OutputDataSpecification &&output_data_specification, std::vector< std::string > &&mesh_names_for_output, std::vector< std::unique_ptr< MeshLib::Mesh >> const &meshes)
Definition: Output.cpp:96
int const _output_file_data_mode
Definition: Output.h:117
std::multimap< Process const *, MeshLib::IO::PVDFile > _process_to_pvd_file
Definition: Output.h:126
void doOutput(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &x)
Definition: Output.cpp:399
void outputMeshXdmf(OutputFile const &output_file, std::vector< std::reference_wrapper< const MeshLib::Mesh >> meshes, int const timestep, double const t)
Definition: Output.cpp:238
static void outputMesh(OutputFile const &output_file, MeshLib::IO::PVDFile *const pvd_file, MeshLib::Mesh const &mesh, double const t)
Definition: Output.cpp:261
std::string const _output_directory
Definition: Output.h:104
bool shallDoOutput(int timestep, double const t)
Determines if there should be output at the given timestep or t.
Definition: Output.cpp:61
std::vector< double > const _fixed_output_times
Given times that steps have to reach.
Definition: Output.h:124
OutputType const _output_file_type
Definition: Output.h:105
void doOutputAlways(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &x)
Definition: Output.cpp:277
unsigned int const _n_files
Specifies the number of hdf5 output files.
Definition: Output.h:112
void doOutputLastTimestep(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &x)
Definition: Output.cpp:418
void addProcess(ProcessLib::Process const &process)
TODO doc. Opens a PVD file for each process.
Definition: Output.cpp:128
std::string const _output_file_suffix
Definition: Output.h:107
MeshLib::IO::PVDFile * findPVDFile(Process const &process, const int process_id, std::string const &mesh_name_for_output)
Definition: Output.cpp:146
std::unique_ptr< MeshLib::IO::XdmfHdfWriter > _mesh_xdmf_hdf_writer
Definition: Output.h:102
std::vector< std::unique_ptr< MeshLib::Mesh > > const & _meshes
Definition: Output.h:144
bool const _output_nonlinear_iteration_results
Definition: Output.h:118
virtual NumLib::LocalToGlobalIndexMap const & getDOFTable(const int) const
Definition: Process.h:137
std::vector< std::reference_wrapper< ProcessVariable > > const & getProcessVariables(const int process_id) const
Definition: Process.h:145
MeshLib::Mesh & getMesh() const
Definition: Process.h:143
std::vector< std::unique_ptr< IntegrationPointWriter > > const * getIntegrationPointWriter(MeshLib::Mesh const &mesh) const
Definition: Process.h:156
SecondaryVariableCollection const & getSecondaryVariables() const
Definition: Process.h:150
bool isMonolithicSchemeUsed() const
Definition: Process.h:102
std::string constructFormattedFileName(std::string const &format_specification, std::string const &mesh_name, int const timestep, double const t, int const iteration)
Definition: FileTools.cpp:116
std::string joinPaths(std::string const &pathA, std::string const &pathB)
Definition: FileTools.cpp:212
std::iterator_traits< InputIt >::reference findElementOrError(InputIt begin, InputIt end, Predicate predicate, std::string const &error="")
Definition: Algorithm.h:69
void CoProcess(MeshLib::Mesh const &mesh, double const time, unsigned int const timeStep, bool const lastTimeStep, std::string output_directory)
Definition: Adaptor.cpp:67
void addProcessDataToMesh(const double t, std::vector< GlobalVector * > const &x, int const process_id, MeshLib::Mesh &mesh, [[maybe_unused]] std::vector< NumLib::LocalToGlobalIndexMap const * > const &bulk_dof_tables, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< std::reference_wrapper< ProcessVariable >> const &process_variables, SecondaryVariableCollection const &secondary_variables, bool const output_secondary_variable, std::vector< std::unique_ptr< IntegrationPointWriter >> const *const integration_point_writer, OutputDataSpecification const &process_output)
void makeOutput(std::string const &file_name, MeshLib::Mesh const &mesh, bool const compress_output, int const data_mode)
std::string constructPVDName(std::string const &output_directory, std::string const &output_file_prefix, std::string const &mesh_name)
Definition: Output.cpp:48
int convertVtkDataMode(std::string const &data_mode)
Definition: Output.cpp:28
Holds information about which variables to write to output files.
Definition: ProcessOutput.h:23
std::set< std::string > output_variables
All variables that shall be output.
Definition: ProcessOutput.h:25
std::string const path
Definition: Output.cpp:199
bool const compression
Enables or disables zlib-compression of the output files.
Definition: Output.cpp:207
OutputFile(std::string const &directory, OutputType const type, std::string const &prefix, std::string const &suffix, std::string const &mesh_name, int const timestep, double const t, int const iteration, int const data_mode_, bool const compression_, std::set< std::string > const &outputnames, unsigned int const n_files)
Definition: Output.cpp:180
std::string const name
Definition: Output.cpp:198
static std::string constructFilename(OutputType const type, std::string prefix, std::string suffix, std::string mesh_name, int const timestep, double const t, int const iteration)
Definition: Output.cpp:210
std::set< std::string > outputnames
Definition: Output.cpp:208