395 <<
"SolutionTransfer<HyperbolicDescription, dim, Number>::project()"
399 move_to_memory_space<dealii::MemorySpace::Host>(
404 const auto &discretization = offline_data_->discretization();
405 auto &triangulation = *discretization.triangulation_;
408 handle_ != dealii::numbers::invalid_unsigned_int,
410 "Cannot project() a state vector without valid handle. "
411 "prepare_projection() or set_handle() have to be called first."));
413 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
414 const auto &affine_constraints = offline_data_->affine_constraints();
415 const auto n_locally_owned = offline_data_->n_locally_owned();
418 projected_mass.reinit(offline_data_->scalar_partitioner());
421 offline_data_->hyperbolic_vector_partitioner(), problem_dimension);
429 std::map<std::tuple<
unsigned int ,
unsigned int >,
state_type>
431 std::map<
unsigned int ,
Bounds> bounds_map;
434 kappa.reinit(offline_data_->scalar_partitioner());
442 triangulation.notify_ready_to_unpack(
444 [
this, &projected_mass, &projected_state](
446 const dealii::CellStatus status,
447 const auto &data_range) {
448 const auto &dof_handler = offline_data_->dof_handler();
449 const auto dof_cell =
typename dealii::DoFHandler<dim>::cell_iterator(
450 &cell->get_triangulation(),
459 const auto n_dofs_per_cell = dof_cell->get_fe().n_dofs_per_cell();
460 std::vector<dealii::types::global_dof_index> dof_indices(
463 const auto state_values = unpack_state_values<state_type>(data_range);
466 case dealii::CellStatus::cell_will_persist:
468 case dealii::CellStatus::children_will_be_coarsened: {
474 Assert(dof_cell->is_active(), dealii::ExcInternalError());
475 dof_cell->get_dof_indices(dof_indices);
477 const auto &discretization = offline_data_->discretization();
478 const auto index = dof_cell->active_fe_index();
479 const auto &finite_element = discretization.finite_element()[index];
480 const auto &mapping = discretization.mapping()[index];
481 const auto &quadrature = discretization.quadrature()[index];
483 dealii::FEValues<dim> fe_values(mapping,
486 dealii::update_values |
487 dealii::update_JxW_values);
489 fe_values.reinit(dof_cell);
491 dealii::Vector<double> mi(n_dofs_per_cell);
492 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
494 for (
unsigned int q = 0; q < quadrature.size(); ++q)
495 sum += fe_values.shape_value(i, q) * fe_values.JxW(q);
499 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
500 const auto global_i = dof_indices[i];
501 add_tensor(projected_state, mi(i) * state_values[i], global_i);
502 projected_mass(global_i) += mi(i);
507 case dealii::CellStatus::cell_will_be_refined: {
513 Assert(dof_cell->has_children(), dealii::ExcInternalError());
515 const auto &discretization = offline_data_->discretization();
516 const auto index = dof_cell->active_fe_index();
517 const auto &finite_element = discretization.finite_element()[index];
518 const auto &mapping = discretization.mapping()[index];
519 const auto &quadrature = discretization.quadrature()[index];
521 dealii::FEValues<dim> fe_values(
525 dealii::update_values | dealii::update_JxW_values |
526 dealii::update_quadrature_points);
528 const auto polynomial_space =
529 dealii::internal::FEPointEvaluation::get_polynomial_space(
531 std::vector<dealii::Point<dim, Number>> unit_points(
537 std::vector<dealii::Point<dim>> unit_points_temp(
538 std::is_same_v<Number, float> ? quadrature.size() : 0);
540 dealii::FullMatrix<double> mass_inverse(n_dofs_per_cell,
542 dealii::Vector<double> lumped_mass(n_dofs_per_cell);
543 std::vector<state_type> local_rhs(n_dofs_per_cell);
545 for (
unsigned int child = 0; child < dof_cell->n_children();
547 const auto child_cell = dof_cell->child(child);
549 Assert(child_cell->is_active(), dealii::ExcInternalError());
550 Assert(dof_cell->active_fe_index() ==
551 child_cell->active_fe_index(),
552 dealii::ExcMessage(
"SolutionTransfer: projection between "
553 "different FE space is not set up."));
555 child_cell->get_dof_indices(dof_indices);
559 fe_values.reinit(child_cell);
561 if constexpr (std::is_same_v<Number, float>) {
562 mapping.transform_points_real_to_unit_cell(
564 fe_values.get_quadrature_points(),
566 std::transform(std::begin(unit_points_temp),
567 std::end(unit_points_temp),
568 std::begin(unit_points),
569 [](
const auto &x) {
return x; });
571 mapping.transform_points_real_to_unit_cell(
572 dof_cell, fe_values.get_quadrature_points(), unit_points);
575 for (
auto &it : local_rhs)
578 for (
unsigned int q = 0; q < quadrature.size(); ++q) {
579 Assert(finite_element.degree == 1, dealii::ExcNotImplemented());
581 dealii::internal::evaluate_tensor_product_value(
583 make_const_array_view(state_values),
586 coefficient *= fe_values.JxW(q);
588 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
589 local_rhs[i] += coefficient * fe_values.shape_value(i, q);
594 mass_inverse = Number(0.);
595 lumped_mass = Number(0.);
596 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
597 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j) {
599 for (
unsigned int q = 0; q < quadrature.size(); ++q)
600 sum += fe_values.shape_value(i, q) *
601 fe_values.shape_value(j, q) * fe_values.JxW(q);
602 mass_inverse(i, j) = sum;
603 lumped_mass(i) += sum;
606 mass_inverse.gauss_jordan();
610 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
612 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j) {
613 U_i += mass_inverse(i, j) * local_rhs[j];
616#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
618 hyperbolic_system_->template view<dim, Number>();
619 AssertThrow(view.is_admissible(U_i),
621 "Error: inadmissible state encountered in "
622 "ready_to_unpack / cell_will_be_refined"));
624 const auto global_i = dof_indices[i];
625 add_tensor(projected_state, lumped_mass(i) * U_i, global_i);
626 projected_mass(global_i) += lumped_mass(i);
632 case dealii::CellStatus::cell_invalid:
633 Assert(
false, dealii::ExcInternalError());
639 const auto projected_state_view =
640 projected_state.template view<problem_dimension>();
642 projected_mass.compress(dealii::VectorOperation::add);
643 projected_state_view.compress(dealii::VectorOperation::add);
659 const auto new_U_view =
660 new_state_vector.U.template view<problem_dimension>();
666 const auto update_new_state_vector = [&]() {
667 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
669 const auto mU_i = projected_state_view.read_tensor(local_i);
670 const auto m_i = projected_mass.local_element(local_i);
672#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
673 const auto view = hyperbolic_system_->template view<dim, Number>();
675 view.is_admissible(mU_i / m_i),
676 dealii::ExcMessage(
"Error: inadmissible state encountered in "
677 "update_new_state_vector()"));
680 new_U_view.write_tensor(mU_i / m_i, local_i);
682 new_U_view.update_ghost_values();
685 update_new_state_vector();
687 const auto precomputed_view =
688 new_state_vector.precomputed.template view<n_precomputed_values>();
691 const auto update_precomputed_values = [&]() {
692 new_U_view.update_ghost_values();
693 hyperbolic_system_->fill_precomputed_values(
694 *offline_data_, new_state_vector,
false);
695 precomputed_view.update_ghost_values();
698 update_precomputed_values();
700 const auto limiter_view = limiter_.template view<dim, Number>();
713 for (
const auto &line : affine_constraints.get_lines()) {
714 const auto global_i = line.index;
715 const auto local_i = scalar_partitioner->global_to_local(global_i);
718 if (local_i >= n_locally_owned)
722 const auto m_i_star = projected_mass.local_element(local_i);
723 const auto U_i_star =
724 projected_state_view.read_tensor(local_i) / m_i_star;
726 auto &bounds = bounds_map[local_i];
727 bounds = limiter_view.projection_bounds_from_state(
728 precomputed_view, local_i, U_i_star);
732 for (
const auto &[global_k, c_k] : line.entries) {
733 const auto local_k = scalar_partitioner->global_to_local(global_k);
734 U_i_interp += c_k * new_U_view.read_tensor(local_k);
738 for (
const auto &[global_k, c_k] : line.entries) {
739 const auto local_k = scalar_partitioner->global_to_local(global_k);
740 const auto U_k = new_U_view.read_tensor(local_k);
742 const auto bounds_k = limiter_view.projection_bounds_from_state(
743 precomputed_view, local_k, U_k);
744 bounds = limiter_view.combine_bounds(bounds, bounds_k);
746 projected_state_view.add_tensor(c_k * m_i_star * U_i_star, local_k);
747 projected_mass.local_element(local_k) += c_k * m_i_star;
749 kappa.local_element(local_k) += Number(1.);
750 pik_matrix[{local_i, local_k}] = c_k * m_i_star * (U_k - U_i_interp);
755 projected_mass.compress(dealii::VectorOperation::add);
756 projected_state_view.compress(dealii::VectorOperation::add);
757 kappa.compress(dealii::VectorOperation::add);
758 update_new_state_vector();
761 projected_mass.update_ghost_values();
762 kappa.update_ghost_values();
766 const auto n_iterations = limiter_view.iterations();
767 for (
unsigned int pass = 0; pass < n_iterations; ++pass) {
770 update_precomputed_values();
772 for (
const auto &line : affine_constraints.get_lines()) {
773 const auto global_i = line.index;
774 const auto local_i = scalar_partitioner->global_to_local(global_i);
777 if (local_i >= n_locally_owned)
793 auto &bounds = bounds_map[local_i];
794 auto total_mass = Number(0.);
795 for (
const auto &[global_k, c_k] : line.entries) {
796 const auto local_k = scalar_partitioner->global_to_local(global_k);
797 const auto U_k = new_U_view.read_tensor(local_k);
798 const auto bounds_k = limiter_view.projection_bounds_from_state(
799 precomputed_view, local_k, U_k);
800 bounds = limiter_view.combine_bounds(bounds, bounds_k);
802 const auto m_k = projected_mass.local_element(local_k);
809 const auto relaxed_bounds =
810 limiter_view.fully_relax_bounds(bounds, total_mass);
814 for (
const auto &[global_k, c_k] : line.entries) {
815 const auto local_k = scalar_partitioner->global_to_local(global_k);
816 const auto kappa_k = kappa.local_element(local_k);
817 const auto m_k = projected_mass.local_element(local_k);
818 const auto U_k = new_U_view.read_tensor(local_k);
819 const auto P_ik = pik_matrix[{local_i, local_k}] * kappa_k / m_k;
821 const auto &[l_k, check] =
822 limiter_view.limit(relaxed_bounds, U_k, P_ik);
823 l = std::min(l, l_k);
828 for (
const auto &[global_k, c_k] : line.entries) {
829 const auto local_k = scalar_partitioner->global_to_local(global_k);
830 auto &mP_ik = pik_matrix[{local_i, local_k}];
831 projected_state_view.add_tensor(l * mP_ik, local_k);
837 projected_state_view.compress(dealii::VectorOperation::add);
838 update_new_state_vector();
842 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
843 const auto global_i = scalar_partitioner->local_to_global(local_i);
844 if (affine_constraints.is_constrained(global_i))
845 new_U_view.write_tensor(
state_type{}, local_i);
847 new_U_view.update_ghost_values();
849#ifdef DEBUG_SYMMETRY_CHECK
853 const auto &lumped_mass_matrix = offline_data_->lumped_mass_matrix();
854 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
855 const auto global_i = scalar_partitioner->local_to_global(local_i);
856 if (affine_constraints.is_constrained(global_i))
859 const auto m_i = projected_mass.local_element(local_i);
860 const auto m_i_reference = lumped_mass_matrix.view().read_entry(local_i);
861 Assert(std::abs(m_i - m_i_reference) < 1.e-10,
863 "SolutionTransfer::projection(): something went wrong. Final "
864 "masses do not agree with those computed in OfflineData."));