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
20#include "BaseLib/FileTools.h"
21#include "BaseLib/Logging.h"
22#include "BaseLib/RunTime.h"
24#include "ProcessLib/Process.h"
25
26namespace ProcessLib
27{
29 MeshLib::Mesh& sub_mesh,
30 std::string const& property_name)
31{
32 if (bulk_mesh == sub_mesh)
33 {
34 return;
35 }
36
37 if (!bulk_mesh.getProperties().existsPropertyVector<double>(
38 std::string_view(property_name)))
39 {
40 return;
41 }
42 auto const& bulk_mesh_property =
43 *bulk_mesh.getProperties().getPropertyVector<double>(
44 std::string_view(property_name));
45 auto const mesh_item_type = bulk_mesh_property.getMeshItemType();
46
47 std::string_view mesh_item_type_string =
48 [mesh_item_type, &property_name]() -> std::string_view
49 {
50 switch (mesh_item_type)
51 {
54 break;
57 break;
59 WARN(
60 "Property '{}' is assigned to edges. But mappings from the "
61 "bulk edges to submesh edges isn't implemented. Mesh item "
62 "type 'Edge' is not supported, only 'Node' and 'Cell' are "
63 "implemented at the moment.",
64 property_name);
65 return "";
66 break;
68 WARN(
69 "Property '{}' is assigned to faces. But mappings from the "
70 "bulk faces to submesh faces isn't implemented. Mesh item "
71 "type 'Face' is not supported, only 'Node' and 'Cell' are "
72 "implemented at the moment.",
73 property_name);
74 return "";
75 break;
77 WARN(
78 "Property '{}' is assigned to integration points. But "
79 "mappings from the bulk integration points to submesh "
80 "integration points isn't implemented. Mesh item type "
81 "'IntegrationPoint' is not supported, only 'Node' and "
82 "'Cell' are implemented at the moment.",
83 property_name);
84 return "";
85 break;
86 default:
87 OGS_FATAL("Unknown mesh item type '{}'.",
88 static_cast<int>(mesh_item_type));
89 return "";
90 }
91 }();
92
93 if (mesh_item_type_string.empty())
94 {
95 return;
96 }
97 if (!sub_mesh.getProperties().existsPropertyVector<std::size_t>(
98 mesh_item_type_string, mesh_item_type, 1))
99 {
100 WARN(
101 "The property {} is required for output on the mesh {}, but it "
102 "doesn't exist.",
103 mesh_item_type_string, sub_mesh.getName());
104 return;
105 }
106
107 auto const& bulk_ids =
108 *sub_mesh.getProperties().getPropertyVector<std::size_t>(
109 mesh_item_type_string);
110
111 auto const number_of_components =
112 bulk_mesh_property.getNumberOfGlobalComponents();
113 auto& sub_mesh_property = *MeshLib::getOrCreateMeshProperty<double>(
114 sub_mesh, property_name, mesh_item_type, number_of_components);
115
116 for (std::size_t sub_mesh_node_id = 0;
117 sub_mesh_node_id < bulk_ids.getNumberOfTuples();
118 ++sub_mesh_node_id)
119 {
120 auto const& bulk_id = bulk_ids[sub_mesh_node_id];
121 for (std::remove_cv_t<decltype(number_of_components)> c = 0;
122 c < number_of_components;
123 ++c)
124 {
125 sub_mesh_property.getComponent(sub_mesh_node_id, c) =
126 bulk_mesh_property.getComponent(bulk_id, c);
127 }
128 }
129}
130
131bool Output::isOutputProcess(const int process_id, const Process& process) const
132{
133 auto const is_last_process =
134 process_id == static_cast<int>(_output_processes.size()) - 1;
135
136 return process.isMonolithicSchemeUsed()
137 // For the staggered scheme for the coupling, only the last
138 // process, which gives the latest solution within a coupling
139 // loop, is allowed to make output.
140 || is_last_process;
141}
142
143Output::Output(std::unique_ptr<OutputFormat>&& output_format,
144 bool const output_nonlinear_iteration_results,
145 OutputDataSpecification&& output_data_specification,
146 std::vector<std::string>&& mesh_names_for_output,
147 std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes)
148 : _output_format(std::move(output_format)),
149 _output_nonlinear_iteration_results(output_nonlinear_iteration_results),
150 _output_data_specification(std::move(output_data_specification)),
151 _mesh_names_for_output(std::move(mesh_names_for_output)),
152 _meshes(meshes)
153{
154}
155
157{
158 _output_processes.push_back(process);
159 if (_mesh_names_for_output.empty())
160 {
161 _mesh_names_for_output.push_back(process.getMesh().getName());
162 }
163}
164
166 std::string const& property_name,
167 MeshLib::MeshItemType const mesh_item_type)
168{
170 mesh_item_type);
171}
172
174 const int timestep, const double t, const int iteration,
175 std::vector<std::reference_wrapper<const MeshLib::Mesh>> const& meshes)
176 const
177{
179 {
180 // special case: no output properties specified => output all properties
181 for (auto const& mesh : meshes)
182 {
183 for (auto [name, property] : mesh.get().getProperties())
184 {
185 property->is_for_output = true;
186 }
187 }
188 }
189 else
190 {
191 for (auto const& mesh : meshes)
192 {
193 for (auto [name, property] : mesh.get().getProperties())
194 {
195 property->is_for_output =
197 }
198 }
199 }
200 _output_format->outputMeshes(timestep, t, iteration, meshes,
202}
203
205 std::string const& submesh_output_name, Process const& process,
206 const int process_id, double const t,
207 std::vector<GlobalVector*> const& xs) const
208{
209 auto& submesh = *BaseLib::findElementOrError(
210 _meshes.get().begin(), _meshes.get().end(),
211 [&submesh_output_name](auto const& m)
212 { return m->getName() == submesh_output_name; },
213 "Need mesh '" + submesh_output_name + "' for the output.");
214
215 DBUG("Found {:d} nodes for output at mesh '{:s}'.",
216 submesh.getNumberOfNodes(), submesh.getName());
217
218 bool const output_secondary_variables = false;
219
220 // TODO Under the assumption that xs.size() and submesh do not change during
221 // the simulation, process output data should not be recreated every time,
222 // but should rather be computed only once and stored for later reuse.
223 auto const process_output_data =
224 createProcessOutputData(process, xs.size(), submesh);
225
226 addProcessDataToMesh(t, xs, process_id, process_output_data,
227 output_secondary_variables,
229
230 auto const& bulk_mesh = process.getMesh();
231 auto const& property_names =
233
234 // TODO Once all processes have been refactored to use the new residuum
235 // assembly logic, the functionality of this lambda should be refactored.
236 // Currently (Jan '23) there is a difference between the logic using this
237 // lambda and doNotProjectFromBulkMeshToSubmeshes(): The latter is
238 // considered regardless of submesh dimension.
239 auto is_residuum_field = [](std::string const& name) -> bool
240 {
241 using namespace std::literals::string_view_literals;
242 static constexpr std::string_view endings[] = {
243 "FlowRate"sv, "heat_flux"sv, "MaterialForces"sv, "NodalForces"sv,
244 "NodalForcesJump"sv};
245 auto ends_with = [&](std::string_view const& ending)
246 { return name.ends_with(ending); };
247 return std::find_if(std::begin(endings), std::end(endings),
248 ends_with) != std::end(endings);
249 };
250
251 for (auto const& name : property_names)
252 {
254 {name, MeshLib::MeshItemType::Node}))
255 {
256 // the projection is disabled regardless of mesh and submesh
257 // dimension
258 continue;
259 }
260
261 if (bulk_mesh.getDimension() == submesh.getDimension())
262 {
263 // omit the 'simple' transfer of the properties in the if condition
264 // on submeshes with equal dimension to the bulk mesh
265 // for those data extra assembly is required
266 if (is_residuum_field(name))
267 {
268 continue;
269 }
270 addBulkMeshPropertyToSubMesh(bulk_mesh, submesh, name);
271 }
272 else
273 {
274 // For residuum based properties it is assumed that the lower
275 // dimensional mesh is a boundary mesh!
276 addBulkMeshPropertyToSubMesh(bulk_mesh, submesh, name);
277 }
278 }
279 return submesh;
280}
281
282void Output::doOutputAlways(Process const& process,
283 const int process_id,
284 int const timestep,
285 const double t,
286 int const iteration,
287 std::vector<GlobalVector*> const& xs) const
288{
289 BaseLib::RunTime time_output;
290 time_output.start();
291
292 bool const output_secondary_variables = true;
293 auto const process_output_data =
294 createProcessOutputData(process, xs.size(), process.getMesh());
295
296 // Need to add variables of process to mesh even if no output takes place.
297 addProcessDataToMesh(t, xs, process_id, process_output_data,
298 output_secondary_variables,
300
301 if (!isOutputProcess(process_id, process))
302 {
303 return;
304 }
305
306 std::vector<std::reference_wrapper<const MeshLib::Mesh>> output_meshes;
307 for (auto const& mesh_output_name : _mesh_names_for_output)
308 {
309 if (process.getMesh().getName() == mesh_output_name)
310 {
311 // process related output
312 output_meshes.emplace_back(process.getMesh());
313 }
314 else
315 {
316 // mesh related output
317 auto const& submesh =
318 prepareSubmesh(mesh_output_name, process, process_id, t, xs);
319 output_meshes.emplace_back(submesh);
320 }
321 }
322
323 outputMeshes(timestep, t, iteration, std::move(output_meshes));
324
325 INFO("[time] Output of timestep {:d} took {:g} s.", timestep,
326 time_output.elapsed());
327}
328
329void Output::doOutput(Process const& process,
330 const int process_id,
331 int const timestep,
332 const double t,
333 int const iteration,
334 std::vector<GlobalVector*> const& xs) const
335{
337 {
338 doOutputAlways(process, process_id, timestep, t, iteration, xs);
339 }
340#ifdef OGS_USE_INSITU
341 // Note: last time step may be output twice: here and in
342 // doOutputLastTimestep() which throws a warning.
343 InSituLib::CoProcess(process.getMesh(), t, timestep, false,
344 _output_format->directory);
345#endif
346}
347
349 const int process_id,
350 int const timestep,
351 const double t,
352 int const iteration,
353 std::vector<GlobalVector*> const& xs) const
354{
356 {
357 doOutputAlways(process, process_id, timestep, t, iteration, xs);
358 }
359#ifdef OGS_USE_INSITU
360 InSituLib::CoProcess(process.getMesh(), t, timestep, true,
361 _output_format->directory);
362#endif
363}
364
366 Process const& process, const int process_id, int const timestep,
367 const double t, int const iteration,
368 std::vector<GlobalVector*> const& xs) const
369{
371 {
372 return;
373 }
374
375 BaseLib::RunTime time_output;
376 time_output.start();
377
378 bool const output_secondary_variable = true;
379 auto const process_output_data =
380 createProcessOutputData(process, xs.size(), process.getMesh());
381
382 addProcessDataToMesh(t, xs, process_id, process_output_data,
383 output_secondary_variable, _output_data_specification);
384
385 if (!isOutputProcess(process_id, process))
386 {
387 return;
388 }
389
390 std::string const output_file_name = _output_format->constructFilename(
391 process.getMesh().getName(), timestep, t, iteration);
392
393 std::string const output_file_path =
394 BaseLib::joinPaths(_output_format->directory, output_file_name);
395
396 DBUG("output iteration results to {:s}", output_file_path);
397
398 if (dynamic_cast<OutputVTKFormat*>(_output_format.get()))
399 {
401 output_file_path, process.getMesh(), _output_format->compression,
402 dynamic_cast<OutputVTKFormat*>(_output_format.get())->data_mode);
403 }
404 else
405 {
406 DBUG("non-linear iterations can only written in Vtk/VTU format.");
407 }
408 INFO("[time] Output took {:g} s.", time_output.elapsed());
409}
410
411std::vector<std::string> Output::getFileNamesForOutput() const
412{
413 std::vector<std::string> output_names;
414 for (auto const& output_name : _mesh_names_for_output)
415 {
416 output_names.push_back(
417 _output_format->constructFilename(output_name, 0, 0, 0));
418 }
419 return output_names;
420}
421
422std::ostream& operator<<(std::ostream& os, Output const& output)
423{
424 os << "Output::_output_data_specification:\t"
426 os << "Output::_output_format:\t" << *(output._output_format);
427 return os;
428}
429
430} // namespace ProcessLib
#define OGS_FATAL(...)
Definition: Error.h:26
Filename manipulation routines.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:30
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:40
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
Properties & getProperties()
Definition: Mesh.h:129
const std::string getName() const
Get name of the mesh.
Definition: Mesh.h:98
std::vector< std::string > getPropertyVectorNames() const
Definition: Properties.cpp:34
bool existsPropertyVector(std::string_view name) const
PropertyVector< T > const * getPropertyVector(std::string_view name) const
MeshItemType getMeshItemType() const
int getNumberOfGlobalComponents() const
std::set< std::pair< std::string, MeshLib::MeshItemType > > _do_not_project_from_bulk_mesh_to_submeshes
Definition: Output.h:126
std::reference_wrapper< std::vector< std::unique_ptr< MeshLib::Mesh > > const > _meshes
Definition: Output.h:123
void doOutputLastTimestep(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &xs) const
Definition: Output.cpp:348
std::vector< std::string > _mesh_names_for_output
Definition: Output.h:114
MeshLib::Mesh const & prepareSubmesh(std::string const &submesh_output_name, Process const &process, const int process_id, double const t, std::vector< GlobalVector * > const &xs) const
Definition: Output.cpp:204
void doOutput(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &xs) const
Definition: Output.cpp:329
void doNotProjectFromBulkMeshToSubmeshes(std::string const &property_name, MeshLib::MeshItemType const mesh_item_type)
Definition: Output.cpp:165
OutputDataSpecification _output_data_specification
Definition: Output.h:112
void doOutputNonlinearIteration(Process const &process, const int process_id, int const timestep, const double t, const int iteration, std::vector< GlobalVector * > const &xs) const
Definition: Output.cpp:365
std::vector< std::reference_wrapper< Process const > > _output_processes
Definition: Output.h:113
bool isOutputProcess(int const process_id, Process const &process) const
Definition: Output.cpp:131
std::unique_ptr< OutputFormat > _output_format
Definition: Output.h:108
void outputMeshes(int const timestep, const double t, int const iteration, std::vector< std::reference_wrapper< const MeshLib::Mesh > > const &meshes) const
Definition: Output.cpp:173
void addProcess(ProcessLib::Process const &process)
TODO doc. Opens a PVD file for each process.
Definition: Output.cpp:156
Output(std::unique_ptr< OutputFormat > &&output_file, bool const output_nonlinear_iteration_results, OutputDataSpecification &&output_data_specification, std::vector< std::string > &&mesh_names_for_output, std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
Definition: Output.cpp:143
bool _output_nonlinear_iteration_results
Definition: Output.h:110
std::vector< std::string > getFileNamesForOutput() const
Definition: Output.cpp:411
void doOutputAlways(Process const &process, const int process_id, int const timestep, const double t, int const iteration, std::vector< GlobalVector * > const &xs) const
Definition: Output.cpp:282
MeshLib::Mesh & getMesh() const
Definition: Process.h:150
bool isMonolithicSchemeUsed() const
Definition: Process.h:109
std::iterator_traits< InputIt >::reference findElementOrError(InputIt begin, InputIt end, Predicate predicate, std::string const &error="")
Definition: Algorithm.h:69
std::string joinPaths(std::string const &pathA, std::string const &pathB)
Definition: FileTools.cpp:216
void CoProcess(MeshLib::Mesh const &mesh, double const time, unsigned int const timeStep, bool const lastTimeStep, std::string output_directory)
Definition: Adaptor.cpp:69
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
Definition: Properties.h:188
MeshItemType
Definition: Location.h:21
void addProcessDataToMesh(const double t, std::vector< GlobalVector * > const &xs, int const process_id, ProcessOutputData const &process_output_data, bool const output_secondary_variables, OutputDataSpecification const &process_output)
ProcessOutputData createProcessOutputData(Process const &process, std::size_t const n_processes, MeshLib::Mesh &output_mesh)
Extracts data necessary for output from the given process.
std::ostream & operator<<(std::ostream &os, Output const &output)
Definition: Output.cpp:422
void outputMeshVtk(std::string const &file_name, MeshLib::Mesh const &mesh, bool const compress_output, int const data_mode)
void addBulkMeshPropertyToSubMesh(MeshLib::Mesh const &bulk_mesh, MeshLib::Mesh &sub_mesh, std::string const &property_name)
Definition: Output.cpp:28
Holds information about which variables to write to output files.
std::set< std::string > output_variables
All variables that shall be output.
bool isOutputStep(int timestep, double const time) const