ryujin 2.1.1 revision b04fb4aba7bd97ddfa5994a6b4b6e8586eb15db2
Loading...
Searching...
No Matches
vtu_output.template.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include "computing_timer.h"
9#include "vtu_output.h"
10
11#include <deal.II/base/function_parser.h>
12#include <deal.II/numerics/data_out.h>
13#include <deal.II/numerics/vector_tools.h>
14
15
16namespace ryujin
17{
18 using namespace dealii;
19
20
21 template <typename HyperbolicDescription, int dim, typename Number>
23 const MPIEnsemble &mpi_ensemble,
24 const OfflineData<dim, Number> &offline_data,
25 const HyperbolicSystem &hyperbolic_system,
26 const Interface::ParabolicSystem &parabolic_system,
28 const MultiComponentVector<Number> &initial_precomputed,
29 const ScalarVector<Number> &alpha,
31 const std::string &subsection /*= "VTUOutput"*/)
32 : ParameterAcceptor(subsection)
33 , mpi_ensemble_(mpi_ensemble)
34 , offline_data_(&offline_data)
35 , postprocessor_(&postprocessor)
36 , selected_components_extractor_(offline_data,
37 hyperbolic_system,
38 parabolic_system,
39 initial_precomputed,
40 {"alpha", "smoothness_indicators"},
41 {alpha, smoothness_indicators})
42 {
43 use_mpi_io_ = true;
44 add_parameter("use mpi io",
45 use_mpi_io_,
46 "If enabled write out one vtu file via MPI IO using "
47 "write_vtu_in_parallel() instead of independent output files "
48 "via write_vtu_with_pvtu_record()");
49
50 add_parameter("manifolds",
51 manifolds_,
52 "List of level set functions. The description is used to "
53 "only output cells that intersect the given level set.");
54
55 vtu_output_quantities_ = hyperbolic_system.state_names(dim);
56
57 const auto &initial_names =
58 hyperbolic_system.initial_precomputed_names(dim);
59 vtu_output_quantities_.insert(vtu_output_quantities_.end(),
60 initial_names.begin(),
61 initial_names.end());
63 add_parameter("vtu output quantities",
64 vtu_output_quantities_,
65 "List of conserved, primitive, precomputed, or postprocessed "
66 "quantities that will be written to the vtu files.");
67 }
68
69
70 template <typename HyperbolicDescription, int dim, typename Number>
72 {
73#ifdef DEBUG_OUTPUT
74 std::cout << "VTUOutput<dim, Number>::prepare()" << std::endl;
75#endif
76
77 selected_components_extractor_.prepare(vtu_output_quantities_);
78 }
79
81 template <typename HyperbolicDescription, int dim, typename Number>
83 const StateVector<Number> &state_vector,
84 std::string name,
85 Number t [[maybe_unused]],
86 unsigned int cycle,
87 bool output_full,
88 bool output_levelsets)
89 {
90#ifdef DEBUG_OUTPUT
91 std::cout << "VTUOutput<dim, Number>::schedule_output()" << std::endl;
92#endif
93
94 /*
95 * Extract quantities and store in ScalarHostVectors so that we can
96 * call DataOut::add_data_vector()
97 */
98
99 selected_components_extractor_.prepare_extraction(state_vector);
100 auto selected_components = selected_components_extractor_.view().extract();
101
102 /*
103 * Attach data vectors to DataOut object:
104 */
106 auto data_out = std::make_unique<dealii::DataOut<dim>>();
107
108 const auto attach_data_vector = [&](auto &data, const auto &name) {
109 const auto &dof_handler_cg = offline_data_->dof_handler_cg();
110 const auto &dof_handler_dg = offline_data_->dof_handler_dg();
111
112 if (data.size() == dof_handler_cg.n_dofs()) {
113 offline_data_->affine_constraints_cg().distribute(data);
114 data.update_ghost_values();
115 data_out->add_data_vector(dof_handler_cg, data, name);
116
117 } else if (data.size() == dof_handler_dg.n_dofs()) {
118 offline_data_->affine_constraints_dg().distribute(data);
119 data.update_ghost_values();
120 data_out->add_data_vector(dof_handler_dg, data, name);
121
122 } else {
123 Assert(
124 false,
125 dealii::ExcMessage("The selected solution component »" + name +
126 "« is associated with an unknown dof handler"));
127 }
128 };
129
130 for (unsigned int d = 0; d < selected_components.size(); ++d) {
131 attach_data_vector(selected_components[d], vtu_output_quantities_[d]);
132 }
133
134 const auto n_quantities = postprocessor_->n_quantities();
135 for (unsigned int i = 0; i < n_quantities; ++i) {
136 // FIXME maybe also refactor to use attach_data_vector()
137 data_out->add_data_vector(offline_data_->dof_handler(),
138 postprocessor_->quantities()[i],
139 postprocessor_->component_names()[i]);
140 }
141
142 DataOutBase::VtkFlags flags(
143 t, cycle, true, DataOutBase::CompressionLevel::best_speed);
144 data_out->set_flags(flags);
145
146 const auto &discretization = offline_data_->discretization();
147 const auto &mapping = discretization.mapping();
148 const auto patch_order =
149 std::max(1u, discretization.polynomial_degree()) - 1u;
150
151 /* Perform output: */
152
153 if (output_full) {
154 data_out->build_patches(
155 mapping, patch_order, DataOut<dim>::curved_inner_cells);
156
157 if (use_mpi_io_) {
158 /* MPI-based synchronous IO */
159 data_out->write_vtu_in_parallel(
160 name + "_" + Utilities::to_string(cycle, 6) + ".vtu",
161 mpi_ensemble_.ensemble_communicator());
162 } else {
163 data_out->write_vtu_with_pvtu_record(
164 "", name, cycle, mpi_ensemble_.ensemble_communicator(), 6);
165 }
166 }
167
168 if (output_levelsets && manifolds_.size() != 0) {
169 /*
170 * Specify an output filter that selects only cells for output that are
171 * in the viscinity of a specified set of output planes:
172 */
173
174 std::vector<std::shared_ptr<FunctionParser<dim>>> level_set_functions;
175 for (const auto &expression : manifolds_)
176 level_set_functions.emplace_back(
177 std::make_shared<FunctionParser<dim>>(expression));
178
179 data_out->set_cell_selection([level_set_functions](const auto &cell) {
180 if (!cell->is_active() || cell->is_artificial())
181 return false;
182
183 for (const auto &function : level_set_functions) {
184
185 unsigned int above = 0;
186 unsigned int below = 0;
187
188 for (unsigned int v : cell->vertex_indices()) {
189 const auto vertex = cell->vertex(v);
190 constexpr auto eps = std::numeric_limits<Number>::epsilon();
191 if (function->value(vertex) >= 0. - 100. * eps)
192 above++;
193 if (function->value(vertex) <= 0. + 100. * eps)
194 below++;
195 if (above > 0 && below > 0)
196 return true;
197 }
198 }
199 return false;
200 });
201
202 data_out->build_patches(
203 mapping, patch_order, DataOut<dim>::curved_inner_cells);
204
205 if (use_mpi_io_) {
206 /* MPI-based synchronous IO */
207 data_out->write_vtu_in_parallel(
208 name + "-levelsets_" + Utilities::to_string(cycle, 6) + ".vtu",
209 mpi_ensemble_.ensemble_communicator());
210 } else {
211 data_out->write_vtu_with_pvtu_record(
212 "",
213 name + "-levelsets",
214 cycle,
215 mpi_ensemble_.ensemble_communicator(),
216 6);
217 }
218 }
219
220 /* Explicitly delete pointer to free up memory early: */
221 data_out.reset();
222 }
223
224} /* namespace ryujin */
void schedule_output(const StateVector< Number > &state_vector, std::string name, Number t, unsigned int cycle, bool output_full=true, bool output_cutplanes=true)
VTUOutput(const MPIEnsemble &mpi_ensemble, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const Interface::ParabolicSystem &parabolic_system, const Postprocessor< HyperbolicDescription, dim, Number > &postprocessor, const MultiComponentVector< Number > &initial_precomputed, const ScalarVector< Number > &alpha, const ScalarVector< Number > &smoothness_indicators, const std::string &subsection="/VTUOutput")
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
Definition vtu_output.h:41