116 const std::string &name)
119 std::cout <<
"Quantities<dim, Number>::prepare()" << std::endl;
124 extractor_.prepare(quantities_);
126 AssertThrow(1 <= n_moments_ && n_moments_ <= 4,
127 dealii::ExcMessage(
"Invalid number of moments: \"" +
128 std::to_string(n_moments_) +
129 "\" is not in the range 1 to 4."));
131 const unsigned int n_owned = offline_data_->n_locally_owned();
132 const auto sparsity_simd_view =
133 offline_data_->sparsity_pattern_simd().view();
134 const auto lumped_mass_matrix_view =
135 offline_data_->lumped_mass_matrix().template view<1>();
142 const auto create_manifold = [](
const auto &entry,
const bool boundary) {
143 const auto &[name, expression, options] = entry;
146 manifold.name = name;
147 manifold.boundary = boundary;
148 manifold.instantaneous =
149 options.find(
"instantaneous") != std::string::npos;
150 manifold.time_averaged =
151 options.find(
"time_averaged") != std::string::npos;
152 manifold.space_averaged =
153 options.find(
"space_averaged") != std::string::npos;
155 AssertThrow(manifold.instantaneous || manifold.time_averaged ||
156 manifold.space_averaged,
158 "Invalid options \"" + options +
"\" for manifold \"" +
160 "\": at least one of instantaneous, time_averaged, or "
161 "space_averaged has to be selected."));
172 const auto sort_points = [](std::vector<ManifoldPoint> &points) {
173 const auto less = [](
const auto &left,
const auto &right) {
174 for (
unsigned int d = 0; d < dim; ++d)
175 if (left[d] != right[d])
176 return left[d] < right[d];
180 points.begin(), points.end(), [&](
const auto &a,
const auto &b) {
181 const auto &[i_a, n_a, nm_a, m_a, id_a, x_a] = a;
182 const auto &[i_b, n_b, nm_b, m_b, id_b, x_b] = b;
183 return less(x_a, x_b) || (!less(x_b, x_a) && less(n_a, n_b));
192 const auto finalize = [&](Manifold &manifold) {
193 sort_points(manifold.points);
195 const auto n_points = manifold.points.size();
199 auto *indices = manifold.indices.view();
200 auto *masses = manifold.masses.view();
201 Number mass_sum = Number(0.);
202 for (std::size_t p = 0; p < n_points; ++p) {
203 indices[p] = std::get<0>(manifold.points[p]);
204 masses[p] = std::get<3>(manifold.points[p]);
205 mass_sum += masses[p];
209 Utilities::MPI::sum(mass_sum, mpi_ensemble_.ensemble_communicator());
211 manifolds_.push_back(std::move(manifold));
221 for (
const auto &entry : interior_manifolds_) {
222 auto manifold = create_manifold(entry,
false);
223 FunctionParser<dim> level_set_function(std::get<1>(entry));
225 const auto &discretization = offline_data_->discretization();
226 const auto &dof_handler = offline_data_->dof_handler();
228 const auto support_points =
229 dof_handler.get_fe().get_unit_support_points();
231 std::vector<dealii::types::global_dof_index> local_dof_indices;
234 std::map<unsigned int, ManifoldPoint> preliminary_map;
236 for (
auto cell : dof_handler.active_cell_iterators()) {
237 if (!cell->is_locally_owned())
240 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
241 local_dof_indices.resize(dofs_per_cell);
242 cell->get_active_or_mg_dof_indices(local_dof_indices);
244 const auto &mapping = discretization.mapping()[cell->active_fe_index()];
246 for (
unsigned int j = 0; j < dofs_per_cell; ++j) {
247 const Point<dim> position =
248 mapping.transform_unit_to_real_cell(cell, support_points[j]);
250 if (std::abs(level_set_function.value(position)) > 1.e-12)
253 const auto global_index = local_dof_indices[j];
255 offline_data_->scalar_partitioner()->global_to_local(
259 if (sparsity_simd_view.row_length(index) == 1)
262 if (index >= n_owned)
265 const Number mass = lumped_mass_matrix_view.read_entry(index);
266 preliminary_map[index] = {index,
267 dealii::Tensor<1, dim, Number>(),
270 dealii::numbers::internal_face_boundary_id,
275 for (
const auto &[index, point] : preliminary_map)
276 manifold.points.push_back(point);
286 for (
const auto &entry : boundary_manifolds_) {
287 auto manifold = create_manifold(entry,
true);
288 FunctionParser<dim> level_set_function(std::get<1>(entry));
290 for (
const auto &point : offline_data_->boundary_map()) {
291 const auto &i = std::get<0>(point);
298 if (offline_data_->affine_constraints().is_constrained(
299 offline_data_->scalar_partitioner()->local_to_global(i)))
302 const auto &position = std::get<5>(point);
303 if (std::abs(level_set_function.value(position)) < 1.e-12)
304 manifold.points.push_back(point);
314 mesh_files_have_been_written_ =
false;
346 std::cout <<
"Quantities<dim, Number>::accumulate()" << std::endl;
351 extractor_.template prepare_extraction<MemorySpace>(state_vector);
353 for (
auto &manifold : manifolds_) {
355 if (!manifold.time_averaged && !manifold.space_averaged)
358 std::swap(manifold.t_old, manifold.t_new);
359 std::swap(manifold.old, manifold.current);
363 auto spatial_average = internal_accumulate(manifold);
368 manifold.t_new == Number(0.))) {
370 manifold.t_old = t - 1.;
376 const Number tau = manifold.t_new - manifold.t_old;
377 const Number weight = 0.5 * tau;
380 std::as_const(manifold.old).template view<MemorySpace>();
381 const auto *current =
382 std::as_const(manifold.current).template view<MemorySpace>();
383 auto *sum = manifold.sum.template view<MemorySpace>();
385 const auto body = [=](
auto sentinel,
const unsigned int j) {
386 using T =
decltype(sentinel);
387 if constexpr (std::is_same_v<T, dealii::VectorizedArray<Number>>) {
392 s += weight * (o + c);
395 sum[j] += weight * (old[j] + current[j]);
399 const auto n_entries =
static_cast<unsigned int>(manifold.sum.size());
400 loop<MemorySpace, Number>(
401 "quantities_trapezoidal_rule", body, 0, n_entries, n_entries);
403 manifold.t_sum += tau;
408 spatial_average.data(), n_moments_, extractor_.n_selected());
409 manifold.time_series.emplace_back(t, std::move(spatial_average));
421 std::cout <<
"Quantities<dim, Number>::write_out()" << std::endl;
427 if (!mesh_files_have_been_written_) {
428 write_mesh_files(cycle);
429 mesh_files_have_been_written_ =
true;
438 if (std::any_of(manifolds_.begin(), manifolds_.end(), [](
const auto &m) {
439 return m.instantaneous && !m.time_averaged && !m.space_averaged;
441 extractor_.template prepare_extraction<selected_memory_space_t>(
449 for (
auto &manifold : manifolds_) {
450 const auto prefix = base_name_ +
"-" + manifold.name +
"-R" +
451 Utilities::to_string(cycle, 4);
457 if (manifold.instantaneous) {
458 const std::string file_name = prefix +
"-instantaneous.dat";
460 std::stringstream time_stamp;
461 time_stamp << std::scientific << std::setprecision(14);
462 time_stamp <<
"# at t = " << t << std::endl;
466 if (!manifold.time_averaged && !manifold.space_averaged)
467 internal_accumulate(manifold);
469 AssertThrow(manifold.t_new == t, dealii::ExcInternalError());
471 internal_write_out(file_name,
482 if (manifold.time_averaged) {
483 const std::string file_name = prefix +
"-time_averaged.dat";
486 if (manifold.t_sum != Number(0.)) {
487 std::stringstream time_stamp;
488 time_stamp << std::scientific << std::setprecision(14);
489 time_stamp <<
"# averaged from t = "
490 << manifold.t_new - manifold.t_sum
491 <<
" to t = " << manifold.t_new << std::endl;
493 internal_write_out(file_name,
496 Number(1.) / manifold.t_sum,
505 if (manifold.space_averaged) {
508 if (!manifold.time_series_cycle.has_value()) {
509 manifold.time_series_cycle = cycle;
513 const auto file_name =
514 base_name_ +
"-" + manifold.name +
"-R" +
515 Utilities::to_string(manifold.time_series_cycle.value(), 4) +
516 "-space_averaged_time_series.dat";
518 internal_write_out_time_series(
519 file_name, manifold.time_series, append);
520 manifold.time_series.clear();
524 if (clear_temporal_statistics_on_writeout_)