120 std::cout <<
"Quantities<dim, Number>::prepare()" << std::endl;
125 extractor_.prepare(quantities_);
127 AssertThrow(1 <= n_moments_ && n_moments_ <= 4,
128 dealii::ExcMessage(
"Invalid number of moments: \"" +
129 std::to_string(n_moments_) +
130 "\" is not in the range 1 to 4."));
132 const unsigned int n_owned = offline_data_->n_locally_owned();
133 const auto sparsity_simd_view =
134 offline_data_->sparsity_pattern_simd().view();
135 const auto lumped_mass_matrix_view =
136 offline_data_->lumped_mass_matrix().view();
143 const auto create_manifold = [](
const auto &entry,
const bool boundary) {
144 const auto &[name, expression, options] = entry;
147 manifold.name = name;
148 manifold.boundary = boundary;
149 manifold.instantaneous =
150 options.find(
"instantaneous") != std::string::npos;
151 manifold.time_averaged =
152 options.find(
"time_averaged") != std::string::npos;
153 manifold.space_averaged =
154 options.find(
"space_averaged") != std::string::npos;
156 AssertThrow(manifold.instantaneous || manifold.time_averaged ||
157 manifold.space_averaged,
159 "Invalid options \"" + options +
"\" for manifold \"" +
161 "\": at least one of instantaneous, time_averaged, or "
162 "space_averaged has to be selected."));
173 const auto sort_points = [](std::vector<ManifoldPoint> &points) {
174 const auto less = [](
const auto &left,
const auto &right) {
175 for (
unsigned int d = 0; d < dim; ++d)
176 if (left[d] != right[d])
177 return left[d] < right[d];
181 points.begin(), points.end(), [&](
const auto &a,
const auto &b) {
182 const auto &[i_a, n_a, nm_a, m_a, id_a, x_a] = a;
183 const auto &[i_b, n_b, nm_b, m_b, id_b, x_b] = b;
184 return less(x_a, x_b) || (!less(x_b, x_a) && less(n_a, n_b));
193 const auto finalize = [&](Manifold &manifold) {
194 sort_points(manifold.points);
196 const auto n_points = manifold.points.size();
200 auto *indices = manifold.indices.view();
201 auto *masses = manifold.masses.view();
202 Number mass_sum = Number(0.);
203 for (std::size_t p = 0; p < n_points; ++p) {
204 indices[p] = std::get<0>(manifold.points[p]);
205 masses[p] = std::get<3>(manifold.points[p]);
206 mass_sum += masses[p];
210 Utilities::MPI::sum(mass_sum, mpi_ensemble_.ensemble_communicator());
212 manifolds_.push_back(std::move(manifold));
222 for (
const auto &entry : interior_manifolds_) {
223 auto manifold = create_manifold(entry,
false);
224 FunctionParser<dim> level_set_function(std::get<1>(entry));
226 const auto &discretization = offline_data_->discretization();
227 const auto &dof_handler = offline_data_->dof_handler();
229 const auto support_points =
230 dof_handler.get_fe().get_unit_support_points();
232 std::vector<dealii::types::global_dof_index> local_dof_indices;
235 std::map<unsigned int, ManifoldPoint> preliminary_map;
237 for (
auto cell : dof_handler.active_cell_iterators()) {
238 if (!cell->is_locally_owned())
241 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
242 local_dof_indices.resize(dofs_per_cell);
243 cell->get_active_or_mg_dof_indices(local_dof_indices);
245 const auto &mapping = discretization.mapping()[cell->active_fe_index()];
247 for (
unsigned int j = 0; j < dofs_per_cell; ++j) {
248 const Point<dim> position =
249 mapping.transform_unit_to_real_cell(cell, support_points[j]);
251 if (std::abs(level_set_function.value(position)) > 1.e-12)
254 const auto global_index = local_dof_indices[j];
256 offline_data_->scalar_partitioner()->global_to_local(
260 if (sparsity_simd_view.row_length(index) == 1)
263 if (index >= n_owned)
266 const Number mass = lumped_mass_matrix_view.read_entry(index);
267 preliminary_map[index] = {index,
268 dealii::Tensor<1, dim, Number>(),
271 dealii::numbers::internal_face_boundary_id,
276 for (
const auto &[index, point] : preliminary_map)
277 manifold.points.push_back(point);
287 for (
const auto &entry : boundary_manifolds_) {
288 auto manifold = create_manifold(entry,
true);
289 FunctionParser<dim> level_set_function(std::get<1>(entry));
291 for (
const auto &point : offline_data_->boundary_map()) {
292 const auto &i = std::get<0>(point);
299 if (offline_data_->affine_constraints().is_constrained(
300 offline_data_->scalar_partitioner()->local_to_global(i)))
303 const auto &position = std::get<5>(point);
304 if (std::abs(level_set_function.value(position)) < 1.e-12)
305 manifold.points.push_back(point);
315 mesh_files_have_been_written_ =
false;
347 std::cout <<
"Quantities<dim, Number>::accumulate()" << std::endl;
352 extractor_.template prepare_extraction<MemorySpace>(state_vector);
354 for (
auto &manifold : manifolds_) {
356 if (!manifold.time_averaged && !manifold.space_averaged)
359 std::swap(manifold.t_old, manifold.t_new);
360 std::swap(manifold.old, manifold.current);
364 auto spatial_average = internal_accumulate(manifold);
369 manifold.t_new == Number(0.))) {
371 manifold.t_old = t - 1.;
377 const Number tau = manifold.t_new - manifold.t_old;
378 const Number weight = 0.5 * tau;
381 std::as_const(manifold.old).template view<MemorySpace>();
382 const auto *current =
383 std::as_const(manifold.current).template view<MemorySpace>();
384 auto *sum = manifold.sum.template view<MemorySpace>();
386 const auto body = [=](
auto sentinel,
const unsigned int j) {
387 using T =
decltype(sentinel);
388 if constexpr (std::is_same_v<T, dealii::VectorizedArray<Number>>) {
393 s += weight * (o + c);
396 sum[j] += weight * (old[j] + current[j]);
400 const auto n_entries =
static_cast<unsigned int>(manifold.sum.size());
401 loop<MemorySpace, Number>(
402 "quantities_trapezoidal_rule", body, 0, n_entries, n_entries);
404 manifold.t_sum += tau;
409 spatial_average.data(), n_moments_, extractor_.n_selected());
410 manifold.time_series.emplace_back(t, std::move(spatial_average));
417 const StateVector &state_vector,
const Number t,
unsigned int cycle)
420 std::cout <<
"Quantities<dim, Number>::write_out()" << std::endl;
426 if (!mesh_files_have_been_written_) {
427 write_mesh_files(cycle);
428 mesh_files_have_been_written_ =
true;
437 if (std::any_of(manifolds_.begin(), manifolds_.end(), [](
const auto &m) {
438 return m.instantaneous && !m.time_averaged && !m.space_averaged;
440 extractor_.template prepare_extraction<selected_memory_space_t>(
448 for (
auto &manifold : manifolds_) {
449 const auto prefix = base_name_ +
"-" + manifold.name +
"-R" +
450 Utilities::to_string(cycle, 4);
456 if (manifold.instantaneous) {
457 const std::string file_name = prefix +
"-instantaneous.dat";
459 std::stringstream time_stamp;
460 time_stamp << std::scientific << std::setprecision(14);
461 time_stamp <<
"# at t = " << t << std::endl;
465 if (!manifold.time_averaged && !manifold.space_averaged)
466 internal_accumulate(manifold);
468 AssertThrow(manifold.t_new == t, dealii::ExcInternalError());
470 internal_write_out(file_name,
481 if (manifold.time_averaged) {
482 const std::string file_name = prefix +
"-time_averaged.dat";
485 if (manifold.t_sum != Number(0.)) {
486 std::stringstream time_stamp;
487 time_stamp << std::scientific << std::setprecision(14);
488 time_stamp <<
"# averaged from t = "
489 << manifold.t_new - manifold.t_sum
490 <<
" to t = " << manifold.t_new << std::endl;
492 internal_write_out(file_name,
495 Number(1.) / manifold.t_sum,
504 if (manifold.space_averaged) {
507 if (!manifold.time_series_cycle.has_value()) {
508 manifold.time_series_cycle = cycle;
512 const auto file_name =
513 base_name_ +
"-" + manifold.name +
"-R" +
514 Utilities::to_string(manifold.time_series_cycle.value(), 4) +
515 "-space_averaged_time_series.dat";
517 internal_write_out_time_series(
518 file_name, manifold.time_series, append);
519 manifold.time_series.clear();
523 if (clear_temporal_statistics_on_writeout_)