73 add_parameter(
"boundary manifolds",
75 "List of level set functions describing boundary. The "
76 "description is used to only output point values for "
77 "boundary vertices belonging to a certain level set. "
78 "Format: '<name> : <level set formula> : <options> , [...] "
79 "(options: time_averaged, space_averaged, instantaneous)");
81 clear_temporal_statistics_on_writeout_ =
true;
82 add_parameter(
"clear statistics on writeout",
83 clear_temporal_statistics_on_writeout_,
84 "If set to true then all temporal statistics (for "
85 "\"time_averaged\" quantities) accumulated so far are reset "
86 "each time a writeout of quantities is performed");
90 template <
typename Description,
int dim,
typename Number>
94 std::cout <<
"Quantities<dim, Number>::prepare()" << std::endl;
100 time_series_cycle_.reset();
102 const unsigned int n_owned = offline_data_->n_locally_owned();
103 const auto sparsity_simd_view =
104 offline_data_->sparsity_pattern_simd().view();
105 const auto lumped_mass_matrix_view =
106 offline_data_->lumped_mass_matrix().view();
114 interior_maps_.clear();
116 interior_manifolds_.begin(),
117 interior_manifolds_.end(),
118 std::inserter(interior_maps_, interior_maps_.end()),
119 [
this, n_owned, &sparsity_simd_view, &lumped_mass_matrix_view](
121 const auto &[name, expression, option] = it;
122 FunctionParser<dim> level_set_function(expression);
124 std::vector<interior_point> map;
125 std::map<int, interior_point> preliminary_map;
127 const auto &discretization = offline_data_->discretization();
128 const auto &dof_handler = offline_data_->dof_handler();
130 const auto support_points =
131 dof_handler.get_fe().get_unit_support_points();
133 std::vector<dealii::types::global_dof_index> local_dof_indices;
136 for (auto cell : dof_handler.active_cell_iterators()) {
139 if (!cell->is_locally_owned())
142 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
143 local_dof_indices.resize(dofs_per_cell);
144 cell->get_active_or_mg_dof_indices(local_dof_indices);
146 const auto &mapping =
147 discretization.mapping()[cell->active_fe_index()];
149 for (unsigned int j = 0; j < dofs_per_cell; ++j) {
151 Point<dim> position =
152 mapping.transform_unit_to_real_cell(cell, support_points[j]);
159 if (std::abs(level_set_function.value(position)) > 1.e-12)
162 const auto global_index = local_dof_indices[j];
164 offline_data_->scalar_partitioner()->global_to_local(
168 const unsigned int row_length =
169 sparsity_simd_view.row_length(index);
173 if (index >= n_owned)
176 const Number interior_mass =
177 lumped_mass_matrix_view.read_entry(index);
179 preliminary_map[index] = {index, interior_mass, position};
187 for (
const auto &[index, tuple] : preliminary_map) {
188 map.push_back(tuple);
191 return std::make_pair(name, map);
203 boundary_maps_.clear();
205 boundary_manifolds_.begin(),
206 boundary_manifolds_.end(),
207 std::inserter(boundary_maps_, boundary_maps_.end()),
208 [
this, n_owned](
auto it) {
209 const auto &[name, expression, option] = it;
210 FunctionParser<dim> level_set_function(expression);
212 std::vector<boundary_point> map;
214 for (const auto &entry : offline_data_->boundary_map()) {
216 const auto &i = std::get<0>(entry);
223 if (offline_data_->affine_constraints().is_constrained(
224 offline_data_->scalar_partitioner()->local_to_global(i)))
227 const auto &position = std::get<5>(entry);
228 if (std::abs(level_set_function.value(position)) < 1.e-12)
229 map.push_back(entry);
231 return std::make_pair(name, map);
238 mesh_files_have_been_written_ =
false;
241 const auto &names = View::primitive_component_names;
242 header_ = std::accumulate(
246 [](
const std::string &description,
const std::string &name) {
247 return description.empty()
248 ? (std::string(
"primitive state (") + name)
249 : (description +
", " + name);
251 ")\t and 2nd moments\n";
255 template <
typename Description,
int dim,
typename Number>
260 std::cout <<
"Quantities<dim, Number>::accumulate()" << std::endl;
263 const auto accumulate = [&](
const auto &point_maps,
264 const auto &manifolds,
267 for (
const auto &[name, point_map] : point_maps) {
270 const auto &options = get_options_from_name(manifolds, name);
273 if (options.find(
"time_averaged") == std::string::npos &&
274 options.find(
"space_averaged") == std::string::npos)
277 auto &[val_old, val_new, val_sum, t_old, t_new, t_sum] =
280 std::swap(t_old, t_new);
281 std::swap(val_old, val_new);
285 const auto spatial_average =
286 internal_accumulate(state_vector, point_map, val_new);
298 const Number tau = t_new - t_old;
300 for (std::size_t i = 0; i < val_sum.size(); ++i) {
301 std::get<0>(val_sum[i]) += 0.5 * tau * std::get<0>(val_old[i]);
302 std::get<0>(val_sum[i]) += 0.5 * tau * std::get<0>(val_new[i]);
303 std::get<1>(val_sum[i]) += 0.5 * tau * std::get<1>(val_old[i]);
304 std::get<1>(val_sum[i]) += 0.5 * tau * std::get<1>(val_new[i]);
310 time_series[name].push_back({t, spatial_average});
314 accumulate(interior_maps_,
316 interior_statistics_,
317 interior_time_series_);
319 accumulate(boundary_maps_,
321 boundary_statistics_,
322 boundary_time_series_);
326 template <
typename Description,
int dim,
typename Number>
328 const StateVector &state_vector,
const Number t,
unsigned int cycle)
331 std::cout <<
"Quantities<dim, Number>::write_out()" << std::endl;
337 if (!mesh_files_have_been_written_) {
338 write_mesh_files(cycle);
339 mesh_files_have_been_written_ =
true;
347 const auto write_out = [&](
const auto &point_maps,
348 const auto &manifolds,
351 for (
const auto &[name, point_map] : point_maps) {
354 const auto &options = get_options_from_name(manifolds, name);
357 base_name_ +
"-" + name +
"-R" + Utilities::to_string(cycle, 4);
363 if (options.find(
"instantaneous") != std::string::npos) {
365 const std::string file_name = prefix +
"-instantaneous.dat";
367 auto &[val_old, val_new, val_sum, t_old, t_new, t_sum] =
370 std::stringstream time_stamp;
371 time_stamp << std::scientific << std::setprecision(14);
372 time_stamp <<
"# at t = " << t << std::endl;
376 if (options.find(
"time_averaged") == std::string::npos &&
377 options.find(
"space_averaged") == std::string::npos)
378 internal_accumulate(state_vector, point_map, val_new);
380 AssertThrow(t_new == t, dealii::ExcInternalError());
382 internal_write_out(file_name, time_stamp.str(), val_new, Number(1.));
389 if (options.find(
"time_averaged") != std::string::npos) {
391 const std::string file_name = prefix +
"-time_averaged.dat";
393 auto &[val_old, val_new, val_sum, t_old, t_new, t_sum] =
397 if (t_sum != Number(0.)) {
398 std::stringstream time_stamp;
399 time_stamp << std::scientific << std::setprecision(14);
400 time_stamp <<
"# averaged from t = " << t_new - t_sum
401 <<
" to t = " << t_new << std::endl;
404 file_name, time_stamp.str(), val_sum, Number(1.) / t_sum);
412 if (options.find(
"space_averaged") != std::string::npos) {
414 if (!time_series_cycle_.has_value()) {
415 time_series_cycle_ = cycle;
419 const auto file_name =
420 base_name_ +
"-" + name +
"-R" +
421 Utilities::to_string(time_series_cycle_.value(), 4) +
422 "-space_averaged_time_series.dat";
424 auto &series = time_series[name];
425 internal_write_out_time_series(file_name, series, append);
431 write_out(interior_maps_,
433 interior_statistics_,
434 interior_time_series_);
436 write_out(boundary_maps_,
438 boundary_statistics_,
439 boundary_time_series_);
441 if (clear_temporal_statistics_on_writeout_)
446 template <
typename Description,
int dim,
typename Number>
454 for (
const auto &[name, interior_map] : interior_maps_) {
456 const auto &options = get_options_from_name(interior_manifolds_, name);
457 if (options.find(
"instantaneous") == std::string::npos &&
458 options.find(
"time_averaged") == std::string::npos)
467 const auto received = Utilities::MPI::gather(
468 mpi_ensemble_.ensemble_communicator(), interior_map);
470 if (Utilities::MPI::this_mpi_process(
471 mpi_ensemble_.ensemble_communicator()) == 0) {
473 std::ofstream output(base_name_ +
"-" + name +
"-R" +
474 Utilities::to_string(cycle, 4) +
"-points.dat");
476 output << std::scientific << std::setprecision(14);
478 output <<
"#\n# position\tinterior mass\n";
480 unsigned int rank = 0;
481 for (
const auto &entries : received) {
482 output <<
"# rank " << rank++ <<
"\n";
483 for (
const auto &entry : entries) {
484 const auto &[index, mass_i, x_i] = entry;
485 output << x_i <<
"\t" << mass_i <<
"\n";
489 output << std::flush;
497 for (
const auto &[name, boundary_map] : boundary_maps_) {
499 const auto &options = get_options_from_name(boundary_manifolds_, name);
500 if (options.find(
"instantaneous") == std::string::npos &&
501 options.find(
"time_averaged") == std::string::npos)
510 const auto received = Utilities::MPI::gather(
511 mpi_ensemble_.ensemble_communicator(), boundary_map);
513 if (Utilities::MPI::this_mpi_process(
514 mpi_ensemble_.ensemble_communicator()) == 0) {
516 std::ofstream output(base_name_ +
"-" + name +
"-R" +
517 Utilities::to_string(cycle, 4) +
"-points.dat");
519 output << std::scientific << std::setprecision(14);
521 output <<
"#\n# position\tnormal\tnormal mass\tboundary mass\n";
523 unsigned int rank = 0;
524 for (
const auto &entries : received) {
525 output <<
"# rank " << rank++ <<
"\n";
526 for (
const auto &entry : entries) {
527 const auto &[index, n_i, nm_i, bm_i, id, x_i] = entry;
528 output << x_i <<
"\t" << n_i <<
"\t" << nm_i <<
"\t" << bm_i
533 output << std::flush;
539 template <
typename Description,
int dim,
typename Number>
540 void Quantities<Description, dim, Number>::clear_statistics()
542 const auto reset = [](
const auto &manifold_map,
auto &statistics_map) {
543 for (
const auto &[name, data_map] : manifold_map) {
544 const auto n_entries = data_map.size();
545 auto &[val_old, val_new, val_sum, t_old, t_new, t_sum] =
546 statistics_map[name];
547 val_old.resize(n_entries);
548 val_new.resize(n_entries);
549 val_sum.resize(n_entries);
550 t_old = t_new = t_sum = 0.;
556 interior_statistics_.clear();
557 reset(interior_maps_, interior_statistics_);
558 interior_time_series_.clear();
560 boundary_statistics_.clear();
561 reset(boundary_maps_, boundary_statistics_);
562 boundary_time_series_.clear();
566 template <
typename Description,
int dim,
typename Number>
567 template <
typename po
int_type,
typename value_type>
568 value_type Quantities<Description, dim, Number>::internal_accumulate(
569 const StateVector &state_vector,
570 const std::vector<point_type> &points_vector,
571 std::vector<value_type> &val_new)
575 ComputingTimer::Scope scope(
"time step [X] _ - memory space transfers");
576 const auto &[U, precomputed, parabolic] = state_vector;
577 U.template copy_to_memory_space<dealii::MemorySpace::Host>();
578 precomputed.template copy_to_memory_space<dealii::MemorySpace::Host>();
581 const auto U_view = std::get<0>(state_vector).view();
583 value_type spatial_average;
584 Number mass_sum = Number(0.);
587 points_vector.begin(),
590 [&](
auto point) -> value_type {
591 const auto i = std::get<0>(point);
596 constexpr auto index =
597 std::is_same_v<point_type, interior_point> ? 1 : 3;
598 const auto mass_i = std::get<index>(point);
600 const auto U_i = U_view.read_tensor(i);
601 const auto view = hyperbolic_system_->template view<dim, Number>();
602 const auto primitive_state = view.to_primitive_state(U_i);
605 std::get<0>(result) = primitive_state;
607 std::get<1>(result) = schur_product(primitive_state, primitive_state);
610 std::get<0>(spatial_average) += mass_i * std::get<0>(result);
611 std::get<1>(spatial_average) += mass_i * std::get<1>(result);
619 Utilities::MPI::sum(mass_sum, mpi_ensemble_.ensemble_communicator());
621 std::get<0>(spatial_average) = Utilities::MPI::sum(
622 std::get<0>(spatial_average), mpi_ensemble_.ensemble_communicator());
623 std::get<1>(spatial_average) = Utilities::MPI::sum(
624 std::get<1>(spatial_average), mpi_ensemble_.ensemble_communicator());
628 std::get<0>(spatial_average) /= mass_sum;
629 std::get<1>(spatial_average) /= mass_sum;
631 return spatial_average;
635 template <
typename Description,
int dim,
typename Number>
636 template <
typename value_type>
637 void Quantities<Description, dim, Number>::internal_write_out(
638 const std::string &file_name,
639 const std::string &time_stamp,
640 const std::vector<value_type> &values,
649 const auto received =
650 Utilities::MPI::gather(mpi_ensemble_.ensemble_communicator(), values);
652 if (Utilities::MPI::this_mpi_process(
653 mpi_ensemble_.ensemble_communicator()) == 0) {
655 std::ofstream output(file_name);
656 output << std::scientific << std::setprecision(14);
657 output << time_stamp <<
"# " << header_;
659 unsigned int rank = 0;
660 for (
const auto &entries : received) {
661 output <<
"# rank " << rank++ <<
"\n";
662 for (
const auto &entry : entries) {
663 const auto &[state, state_square] = entry;
664 output << scale * state <<
"\t" << scale * state_square <<
"\n";
668 output << std::flush;
673 template <
typename Description,
int dim,
typename Number>
674 template <
typename value_type>
675 void Quantities<Description, dim, Number>::internal_write_out_time_series(
676 const std::string &file_name,
677 const std::vector<std::tuple<Number, value_type>> &values,
680 if (Utilities::MPI::this_mpi_process(
681 mpi_ensemble_.ensemble_communicator()) == 0) {
682 std::ofstream output;
683 output << std::scientific << std::setprecision(14);
686 output.open(file_name, std::ofstream::out | std::ofstream::app);
688 output.open(file_name, std::ofstream::out | std::ofstream::trunc);
689 output <<
"# time t\t" << header_;
692 for (
const auto &entry : values) {
693 const auto t = std::get<0>(entry);
694 const auto &[state, state_square] = std::get<1>(entry);
696 output << t <<
"\t" << state <<
"\t" << state_square <<
"\n";
699 output << std::flush;