395 std::cout <<
"SolutionTransfer<Description, dim, Number>::project()"
402 auto &[U, precomputed, parabolic] = new_state_vector;
403 U.template move_to_memory_space<dealii::MemorySpace::Host>();
404 precomputed.template move_to_memory_space<dealii::MemorySpace::Host>();
407 const auto &discretization = offline_data_->discretization();
408 auto &triangulation = *discretization.triangulation_;
411 handle_ != dealii::numbers::invalid_unsigned_int,
413 "Cannot project() a state vector without valid handle. "
414 "prepare_projection() or set_handle() have to be called first."));
416 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
417 const auto &affine_constraints = offline_data_->affine_constraints();
418 const auto n_locally_owned = offline_data_->n_locally_owned();
421 ScalarHostVector projected_mass;
422 projected_mass.reinit(offline_data_->scalar_partitioner());
424 projected_state.reinit_with_vector_partitioner(
425 offline_data_->hyperbolic_vector_partitioner());
433 std::map<std::tuple<
unsigned int ,
unsigned int >,
state_type>
435 std::map<
unsigned int ,
Bounds> bounds_map;
437 ScalarHostVector kappa;
438 kappa.reinit(offline_data_->scalar_partitioner());
446 triangulation.notify_ready_to_unpack(
448 [
this, &projected_mass, &projected_state](
450 const dealii::CellStatus status,
451 const auto &data_range) {
452 const auto &dof_handler = offline_data_->dof_handler();
453 const auto dof_cell =
typename dealii::DoFHandler<dim>::cell_iterator(
454 &cell->get_triangulation(),
463 const auto n_dofs_per_cell = dof_cell->get_fe().n_dofs_per_cell();
464 std::vector<dealii::types::global_dof_index> dof_indices(
467 const auto state_values = unpack_state_values<state_type>(data_range);
470 case dealii::CellStatus::cell_will_persist:
472 case dealii::CellStatus::children_will_be_coarsened: {
478 Assert(dof_cell->is_active(), dealii::ExcInternalError());
479 dof_cell->get_dof_indices(dof_indices);
481 const auto &discretization = offline_data_->discretization();
482 const auto index = dof_cell->active_fe_index();
483 const auto &finite_element = discretization.finite_element()[index];
484 const auto &mapping = discretization.mapping()[index];
485 const auto &quadrature = discretization.quadrature()[index];
487 dealii::FEValues<dim> fe_values(mapping,
490 dealii::update_values |
491 dealii::update_JxW_values);
493 fe_values.reinit(dof_cell);
495 dealii::Vector<double> mi(n_dofs_per_cell);
496 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
498 for (
unsigned int q = 0; q < quadrature.size(); ++q)
499 sum += fe_values.shape_value(i, q) * fe_values.JxW(q);
503 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
504 const auto global_i = dof_indices[i];
505 add_tensor(projected_state, mi(i) * state_values[i], global_i);
506 projected_mass(global_i) += mi(i);
511 case dealii::CellStatus::cell_will_be_refined: {
517 Assert(dof_cell->has_children(), dealii::ExcInternalError());
519 const auto &discretization = offline_data_->discretization();
520 const auto index = dof_cell->active_fe_index();
521 const auto &finite_element = discretization.finite_element()[index];
522 const auto &mapping = discretization.mapping()[index];
523 const auto &quadrature = discretization.quadrature()[index];
525 dealii::FEValues<dim> fe_values(
529 dealii::update_values | dealii::update_JxW_values |
530 dealii::update_quadrature_points);
532 const auto polynomial_space =
533 dealii::internal::FEPointEvaluation::get_polynomial_space(
535 std::vector<dealii::Point<dim, Number>> unit_points(
541 std::vector<dealii::Point<dim>> unit_points_temp(
542 std::is_same_v<Number, float> ? quadrature.size() : 0);
544 dealii::FullMatrix<double> mass_inverse(n_dofs_per_cell,
546 dealii::Vector<double> lumped_mass(n_dofs_per_cell);
547 std::vector<state_type> local_rhs(n_dofs_per_cell);
549 for (
unsigned int child = 0; child < dof_cell->n_children();
551 const auto child_cell = dof_cell->child(child);
553 Assert(child_cell->is_active(), dealii::ExcInternalError());
554 Assert(dof_cell->active_fe_index() ==
555 child_cell->active_fe_index(),
556 dealii::ExcMessage(
"SolutionTransfer: projection between "
557 "different FE space is not set up."));
559 child_cell->get_dof_indices(dof_indices);
563 fe_values.reinit(child_cell);
565 if constexpr (std::is_same_v<Number, float>) {
566 mapping.transform_points_real_to_unit_cell(
568 fe_values.get_quadrature_points(),
570 std::transform(std::begin(unit_points_temp),
571 std::end(unit_points_temp),
572 std::begin(unit_points),
573 [](
const auto &x) {
return x; });
575 mapping.transform_points_real_to_unit_cell(
576 dof_cell, fe_values.get_quadrature_points(), unit_points);
579 for (
auto &it : local_rhs)
582 for (
unsigned int q = 0; q < quadrature.size(); ++q) {
583 Assert(finite_element.degree == 1, dealii::ExcNotImplemented());
585 dealii::internal::evaluate_tensor_product_value(
587 make_const_array_view(state_values),
590 coefficient *= fe_values.JxW(q);
592 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
593 local_rhs[i] += coefficient * fe_values.shape_value(i, q);
598 mass_inverse = Number(0.);
599 lumped_mass = Number(0.);
600 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
601 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j) {
603 for (
unsigned int q = 0; q < quadrature.size(); ++q)
604 sum += fe_values.shape_value(i, q) *
605 fe_values.shape_value(j, q) * fe_values.JxW(q);
606 mass_inverse(i, j) = sum;
607 lumped_mass(i) += sum;
610 mass_inverse.gauss_jordan();
614 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i) {
616 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j) {
617 U_i += mass_inverse(i, j) * local_rhs[j];
620#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
622 hyperbolic_system_->template view<dim, Number>();
623 AssertThrow(view.is_admissible(U_i),
625 "Error: inadmissible state encountered in "
626 "ready_to_unpack / cell_will_be_refined"));
628 const auto global_i = dof_indices[i];
629 add_tensor(projected_state, lumped_mass(i) * U_i, global_i);
630 projected_mass(global_i) += lumped_mass(i);
636 case dealii::CellStatus::cell_invalid:
637 Assert(
false, dealii::ExcInternalError());
643 const auto projected_state_view = projected_state.view();
645 projected_mass.compress(dealii::VectorOperation::add);
646 projected_state_view.compress(dealii::VectorOperation::add);
662 const auto new_U_view = std::get<0>(new_state_vector).view();
668 const auto update_new_state_vector = [&]() {
669 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
671 const auto mU_i = projected_state_view.read_tensor(local_i);
672 const auto m_i = projected_mass.local_element(local_i);
674#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
675 const auto view = hyperbolic_system_->template view<dim, Number>();
677 view.is_admissible(mU_i / m_i),
678 dealii::ExcMessage(
"Error: inadmissible state encountered in "
679 "update_new_state_vector()"));
682 new_U_view.write_tensor(mU_i / m_i, local_i);
684 new_U_view.update_ghost_values();
687 update_new_state_vector();
689 const auto precomputed_view = std::get<1>(new_state_vector).view();
692 const auto update_precomputed_values = [&]() {
693 new_U_view.update_ghost_values();
694 hyperbolic_system_->fill_precomputed_values(
695 *offline_data_, new_state_vector,
false);
696 precomputed_view.update_ghost_values();
699 update_precomputed_values();
701 const auto limiter_view = limiter_.template view<dim, Number>();
714 for (
const auto &line : affine_constraints.get_lines()) {
715 const auto global_i = line.index;
716 const auto local_i = scalar_partitioner->global_to_local(global_i);
719 if (local_i >= n_locally_owned)
723 const auto m_i_star = projected_mass.local_element(local_i);
724 const auto U_i_star =
725 projected_state_view.read_tensor(local_i) / m_i_star;
727 auto &bounds = bounds_map[local_i];
728 bounds = limiter_view.projection_bounds_from_state(
729 precomputed_view, local_i, U_i_star);
733 for (
const auto &[global_k, c_k] : line.entries) {
734 const auto local_k = scalar_partitioner->global_to_local(global_k);
735 U_i_interp += c_k * new_U_view.read_tensor(local_k);
739 for (
const auto &[global_k, c_k] : line.entries) {
740 const auto local_k = scalar_partitioner->global_to_local(global_k);
741 const auto U_k = new_U_view.read_tensor(local_k);
743 const auto bounds_k = limiter_view.projection_bounds_from_state(
744 precomputed_view, local_k, U_k);
745 bounds = limiter_view.combine_bounds(bounds, bounds_k);
747 projected_state_view.add_tensor(c_k * m_i_star * U_i_star, local_k);
748 projected_mass.local_element(local_k) += c_k * m_i_star;
750 kappa.local_element(local_k) += Number(1.);
751 pik_matrix[{local_i, local_k}] = c_k * m_i_star * (U_k - U_i_interp);
756 projected_mass.compress(dealii::VectorOperation::add);
757 projected_state_view.compress(dealii::VectorOperation::add);
758 kappa.compress(dealii::VectorOperation::add);
759 update_new_state_vector();
762 projected_mass.update_ghost_values();
763 kappa.update_ghost_values();
767 const auto n_iterations = limiter_view.iterations();
768 for (
unsigned int pass = 0; pass < n_iterations; ++pass) {
771 update_precomputed_values();
773 for (
const auto &line : affine_constraints.get_lines()) {
774 const auto global_i = line.index;
775 const auto local_i = scalar_partitioner->global_to_local(global_i);
778 if (local_i >= n_locally_owned)
794 auto &bounds = bounds_map[local_i];
795 auto total_mass = Number(0.);
796 for (
const auto &[global_k, c_k] : line.entries) {
797 const auto local_k = scalar_partitioner->global_to_local(global_k);
798 const auto U_k = new_U_view.read_tensor(local_k);
799 const auto bounds_k = limiter_view.projection_bounds_from_state(
800 precomputed_view, local_k, U_k);
801 bounds = limiter_view.combine_bounds(bounds, bounds_k);
803 const auto m_k = projected_mass.local_element(local_k);
810 const auto relaxed_bounds =
811 limiter_view.fully_relax_bounds(bounds, total_mass);
815 for (
const auto &[global_k, c_k] : line.entries) {
816 const auto local_k = scalar_partitioner->global_to_local(global_k);
817 const auto kappa_k = kappa.local_element(local_k);
818 const auto m_k = projected_mass.local_element(local_k);
819 const auto U_k = new_U_view.read_tensor(local_k);
820 const auto P_ik = pik_matrix[{local_i, local_k}] * kappa_k / m_k;
822 const auto &[l_k, check] =
823 limiter_view.limit(relaxed_bounds, U_k, P_ik);
824 l = std::min(l, l_k);
829 for (
const auto &[global_k, c_k] : line.entries) {
830 const auto local_k = scalar_partitioner->global_to_local(global_k);
831 auto &mP_ik = pik_matrix[{local_i, local_k}];
832 projected_state_view.add_tensor(l * mP_ik, local_k);
838 projected_state_view.compress(dealii::VectorOperation::add);
839 update_new_state_vector();
843 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
844 const auto global_i = scalar_partitioner->local_to_global(local_i);
845 if (affine_constraints.is_constrained(global_i))
846 new_U_view.write_tensor(
state_type{}, local_i);
848 new_U_view.update_ghost_values();
850#ifdef DEBUG_SYMMETRY_CHECK
854 const auto &lumped_mass_matrix = offline_data_->lumped_mass_matrix();
855 for (
unsigned int local_i = 0; local_i < n_locally_owned; ++local_i) {
856 const auto global_i = scalar_partitioner->local_to_global(local_i);
857 if (affine_constraints.is_constrained(global_i))
860 const auto m_i = projected_mass.local_element(local_i);
861 const auto m_i_reference = lumped_mass_matrix.view().read_entry(local_i);
862 Assert(std::abs(m_i - m_i_reference) < 1.e-10,
864 "SolutionTransfer::projection(): something went wrong. Final "
865 "masses do not agree with those computed in OfflineData."));