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