13#ifndef dealii_tensor_product_matrix_creator_h
14#define dealii_tensor_product_matrix_creator_h
64 template <
int dim,
typename Number>
65 std::pair<std::array<FullMatrix<Number>, dim>,
66 std::array<FullMatrix<Number>, dim>>
70 const ::ndarray<LaplaceBoundaryType, dim, 2> &boundary_ids,
71 const ::ndarray<double, dim, 3> &cell_extent,
72 const unsigned int n_overlap = 1);
78 template <
int dim,
typename Number>
79 std::pair<std::array<FullMatrix<Number>, dim>,
80 std::array<FullMatrix<Number>, dim>>
83 const std::set<types::boundary_id> &dirichlet_boundaries,
84 const std::set<types::boundary_id> &neumann_boundaries,
87 const ::ndarray<double, dim, 3> &cell_extent,
88 const unsigned int n_overlap = 1);
114 template <
typename Number =
double>
119 const std::pair<bool, bool> include_endpoints = {
true,
true},
120 std::vector<unsigned int> numbering = std::vector<unsigned int>());
142 template <
typename Number =
double>
147 const std::pair<bool, bool> include_endpoints = {
true,
true},
148 std::vector<unsigned int> numbering = std::vector<unsigned int>());
182 template <
typename Number =
double>
186 const unsigned int &n_cells,
187 const unsigned int &overlap,
188 const std::pair<bool, bool> include_endpoints = {
true,
true});
207 template <
typename Number =
double>
212 std::vector<Number> coefficients = std::vector<Number>());
233 template <
typename Number =
double>
237 &polynomial_basis_derivative,
238 const unsigned int overlap = 1);
251 template <
typename Number>
254 const unsigned int n,
257 for (
unsigned int i = 0; i < n_dofs_1D_with_overlap; ++i)
264 template <
typename Number>
291 const auto lexicographic_to_hierarchic_numbering =
293 FETools::hierarchic_to_lexicographic_numbering<1>(
297 for (
const unsigned int i : fe_values.
dof_indices())
298 for (
const unsigned int j : fe_values.
dof_indices())
300 mass_matrix_reference(i, j) +=
301 (fe_values.
shape_value(lexicographic_to_hierarchic_numbering[i],
303 fe_values.
shape_value(lexicographic_to_hierarchic_numbering[j],
305 fe_values.
JxW(q_index));
307 derivative_matrix_reference(i, j) +=
308 (fe_values.
shape_grad(lexicographic_to_hierarchic_numbering[i],
310 fe_values.
shape_grad(lexicographic_to_hierarchic_numbering[j],
312 fe_values.
JxW(q_index));
316 mass_matrix_reference, derivative_matrix_reference,
false};
322 template <
int dim,
typename Number>
323 std::pair<std::array<FullMatrix<Number>, dim>,
324 std::array<FullMatrix<Number>, dim>>
328 const ::ndarray<LaplaceBoundaryType, dim, 2> &boundary_ids,
329 const ::ndarray<double, dim, 3> &cell_extent,
330 const unsigned int n_overlap)
333 const auto create_reference_mass_and_stiffness_matrices =
334 internal::create_reference_mass_and_stiffness_matrices<Number>(
338 std::get<0>(create_reference_mass_and_stiffness_matrices);
340 std::get<1>(create_reference_mass_and_stiffness_matrices);
342 std::get<2>(create_reference_mass_and_stiffness_matrices);
351 const unsigned int n_dofs_1D = M_ref.n();
352 const unsigned int n_dofs_1D_with_overlap = M_ref.n() - 2 + 2 * n_overlap;
354 std::array<FullMatrix<Number>, dim> Ms;
355 std::array<FullMatrix<Number>, dim> Ks;
357 for (
unsigned int d = 0; d < dim; ++d)
359 Ms[d].reinit(n_dofs_1D_with_overlap, n_dofs_1D_with_overlap);
360 Ks[d].reinit(n_dofs_1D_with_overlap, n_dofs_1D_with_overlap);
363 for (
unsigned int i = 0; i < n_dofs_1D; ++i)
364 for (
unsigned int j = 0; j < n_dofs_1D; ++j)
366 const unsigned int i0 = i + n_overlap - 1;
367 const unsigned int j0 = j + n_overlap - 1;
368 Ms[d][i0][j0] = M_ref[i][j] * cell_extent[d][1];
369 Ks[d][i0][j0] = K_ref[i][j] / cell_extent[d][1];
378 for (
unsigned int i = 0; i < n_overlap; ++i)
379 for (
unsigned int j = 0; j < n_overlap; ++j)
381 const unsigned int i0 = n_dofs_1D - n_overlap + i;
382 const unsigned int j0 = n_dofs_1D - n_overlap + j;
383 Ms[d][i][j] += M_ref[i0][j0] * cell_extent[d][0];
384 Ks[d][i][j] += K_ref[i0][j0] / cell_extent[d][0];
392 const unsigned i0 = n_overlap - 1;
415 for (
unsigned int i = 0; i < n_overlap; ++i)
416 for (
unsigned int j = 0; j < n_overlap; ++j)
418 const unsigned int i0 = n_overlap + n_dofs_1D + i - 2;
419 const unsigned int j0 = n_overlap + n_dofs_1D + j - 2;
420 Ms[d][i0][j0] += M_ref[i][j] * cell_extent[d][2];
421 Ks[d][i0][j0] += K_ref[i][j] / cell_extent[d][2];
429 const unsigned i0 = n_overlap + n_dofs_1D - 2;
452 template <
int dim,
typename Number>
453 std::pair<std::array<FullMatrix<Number>, dim>,
454 std::array<FullMatrix<Number>, dim>>
457 const std::set<types::boundary_id> &dirichlet_boundaries,
458 const std::set<types::boundary_id> &neumann_boundaries,
461 const ::ndarray<double, dim, 3> &cell_extent,
462 const unsigned int n_overlap)
466 for (
unsigned int d = 0; d < dim; ++d)
469 if ((cell->at_boundary(2 * d) ==
false) ||
470 cell->has_periodic_neighbor(2 * d))
479 const auto bid = cell->face(2 * d)->boundary_id();
480 if (dirichlet_boundaries.find(bid) !=
481 dirichlet_boundaries.end() )
486 else if (neumann_boundaries.find(bid) !=
487 neumann_boundaries.end() )
499 if ((cell->at_boundary(2 * d + 1) ==
false) ||
500 cell->has_periodic_neighbor(2 * d + 1))
508 const auto bid = cell->face(2 * d + 1)->boundary_id();
509 if (dirichlet_boundaries.find(bid) !=
510 dirichlet_boundaries.end() )
515 else if (neumann_boundaries.find(bid) !=
516 neumann_boundaries.end() )
528 return create_laplace_tensor_product_matrix<dim, Number>(
529 fe, quadrature, boundary_ids, cell_extent, n_overlap);
532 template <
typename Number>
536 const std::pair<bool, bool> include_endpoints,
537 std::vector<unsigned int> numbering)
539 if (
dynamic_cast<const FE_DGQ<1> *
>(&fe) ==
nullptr &&
540 numbering.size() == 0)
543 include_endpoints.first ==
true && include_endpoints.second ==
true,
545 "You tried to generate a 1D mass matrix with excluding boundary "
546 "dofs for a non-DGQ element without providing a numbering."));
549 if (numbering.size() == 0)
552 std::iota(numbering.begin(), numbering.end(), 0);
555 const unsigned int degree = fe.
degree;
562 unsigned int start_dof = include_endpoints.first ? 0 : 1;
563 unsigned int end_dof =
564 include_endpoints.second ? n_dofs_per_cell : n_dofs_per_cell - 1;
565 const unsigned int shift = include_endpoints.first ? 0 : 1;
567 for (
unsigned int i = start_dof; i < end_dof; ++i)
568 for (
unsigned int j = start_dof; j < end_dof; ++j)
569 for (
unsigned int q = 0; q < quadrature.size(); ++q)
570 cell_matrix(i - shift, j - shift) +=
571 (fe.
shape_value(numbering[i], quadrature.point(q)) *
572 fe.
shape_value(numbering[j], quadrature.point(q))) *
573 (h * quadrature.weight(q));
578 template <
typename Number>
582 const std::pair<bool, bool> include_endpoints,
583 std::vector<unsigned int> numbering)
585 if (
dynamic_cast<const FE_DGQ<1> *
>(&fe) ==
nullptr &&
586 numbering.size() == 0)
589 include_endpoints.first ==
true && include_endpoints.second ==
true,
591 "You tried to generate a 1D derivative matrix with excluding boundary "
592 "dofs for a non-DGQ element without providing a numbering."));
595 if (numbering.size() == 0)
598 std::iota(numbering.begin(), numbering.end(), 0);
601 const unsigned int degree = fe.
degree;
603 const Number &JxW = h;
609 unsigned int start_dof = include_endpoints.first ? 0 : 1;
610 unsigned int end_dof =
611 include_endpoints.second ? n_dofs_per_cell : n_dofs_per_cell - 1;
612 const unsigned int shift = include_endpoints.first ? 0 : 1;
614 for (
unsigned int i = start_dof; i < end_dof; ++i)
615 for (
unsigned int j = start_dof; j < end_dof; ++j)
616 for (
unsigned int q = 0; q < quadrature.size(); ++q)
617 cell_matrix(i - shift, j - shift) +=
618 (fe.
shape_grad(numbering[i], quadrature.point(q)) / h *
619 fe.
shape_grad(numbering[j], quadrature.point(q))) /
620 h * (h * quadrature.weight(q));
625 template <
typename Number>
628 const unsigned int &n_cells,
629 const unsigned int &overlap,
630 const std::pair<bool, bool> include_endpoints)
632 const unsigned int n_dofs_per_cell = cell_matrix.n();
634 Assert(cell_matrix.m() == n_dofs_per_cell,
636 "The provided cell mass matrix must be a square matrix."));
640 "create_1D_discretization_matrix() returns a full matrix and is not meant to be used with a larger number of cells. "));
642 ExcMessage(
"You are trying to get a mass matrix of zero cells."));
643 Assert(overlap < n_dofs_per_cell,
644 ExcMessage(
"The overlap must be smaller than the number of dofs."));
646 unsigned int n_total_dofs =
647 n_cells * n_dofs_per_cell - overlap * (n_cells - 1);
649 if (!include_endpoints.first)
651 if (!include_endpoints.second)
657 const unsigned int left_shift = include_endpoints.first ? 0 : 1;
659 for (
unsigned int cell = 0; cell < n_cells; ++cell)
661 const unsigned int dof_shift = cell * overlap + left_shift;
663 const unsigned int start_dof =
664 (cell == 0 && !include_endpoints.first) ? 1 : 0;
666 const unsigned int end_dof =
667 (cell == n_cells - 1 && !include_endpoints.second) ?
668 n_dofs_per_cell - 1 :
670 for (
unsigned int i = start_dof; i < end_dof; ++i)
671 for (
unsigned int j = start_dof; j < end_dof; ++j)
673 result_matrix(i + cell * n_dofs_per_cell - dof_shift,
674 j + cell * n_dofs_per_cell - dof_shift) +=
678 return result_matrix;
683 template <
typename Number>
687 std::vector<Number> coefficients)
692 const unsigned int degree = fe.
degree;
694 ExcMessage(
"Provided element degree has to greater than 0"));
697 Assert(coefficients.size() == 0 || coefficients.size() == degree,
699 "Provided coefficients vector has to be empty or the same size "
700 "as the number of dofs"));
702 if (coefficients.size() == 0)
704 coefficients.resize(degree);
706 double inverse_factorial_square = 1.;
707 coefficients[0] = 1.;
708 for (
unsigned int k = 2; k <= degree; ++k)
710 inverse_factorial_square /= (k * k);
711 coefficients[k - 1] = inverse_factorial_square;
715 std::vector<std::vector<Polynomials::Polynomial<double>>> polynomial_basis;
717 polynomial_basis.resize(degree + 1);
720 std::sort(support_points.begin(),
721 support_points.end(),
726 polynomial_basis[0] =
729 for (
unsigned int k = 1; k < degree + 1; ++k)
731 polynomial_basis[k].reserve(degree + 1);
732 for (
unsigned int i = 0; i < degree + 1; ++i)
734 polynomial_basis[k - 1][i].derivative());
740 penalty_matrix *= coefficients[0];
742 for (
unsigned int k = 2; k < degree + 1; ++k)
746 penalty_matrix.
add(coefficients[k - 1], kth_matrix);
749 penalty_matrix *= (1 / h);
750 return penalty_matrix;
754 template <
typename Number>
758 &polynomial_basis_derivative,
759 const unsigned int overlap)
761 const unsigned int n_dofs_per_cell = polynomial_basis_derivative.size();
762 const unsigned int n_total_dofs = 2 * n_dofs_per_cell - overlap;
763 const unsigned int shift = n_dofs_per_cell - overlap;
767 std::vector<double> values_left(n_dofs_per_cell);
768 std::vector<double> values_right(n_dofs_per_cell);
770 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
772 values_left[i] = polynomial_basis_derivative[i].value(0);
773 values_right[i] = polynomial_basis_derivative[i].value(1);
776 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
777 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j)
778 penalty_matrix(i, j) += values_right[i] * values_right[j];
781 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
782 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j)
783 penalty_matrix(i + shift, j) -= values_left[i] * values_right[j];
785 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
786 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j)
787 penalty_matrix(i, j + shift) -= values_right[i] * values_left[j];
789 for (
unsigned int i = 0; i < n_dofs_per_cell; ++i)
790 for (
unsigned int j = 0; j < n_dofs_per_cell; ++j)
791 penalty_matrix(i + shift, j + shift) += values_left[i] * values_left[j];
793 return penalty_matrix;
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
void distribute_dofs(const FiniteElement< dim, spacedim > &fe)
std_cxx20::ranges::iota_view< unsigned int, unsigned int > dof_indices() const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > quadrature_point_indices() const
const Tensor< 1, spacedim > & shape_grad(const unsigned int i, const unsigned int q_point) const
double JxW(const unsigned int q_point) const
const double & shape_value(const unsigned int i, const unsigned int q_point) const
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
const unsigned int degree
unsigned int n_dofs_per_cell() const
unsigned int tensor_degree() const
const unsigned int dofs_per_cell
virtual Tensor< 1, dim > shape_grad(const unsigned int i, const Point< dim > &p) const
const std::vector< Point< dim > > & get_unit_support_points() const
virtual double shape_value(const unsigned int i, const Point< dim > &p) const
void add(const number a, const FullMatrix< number2 > &A)
cell_iterator begin(const unsigned int level=0) const
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
std::vector< Polynomial< double > > generate_complete_Lagrange_basis(const std::vector< Point< 1 > > &points)
void clear_row_and_column(const unsigned int n_dofs_1D_with_overlap, const unsigned int n, FullMatrix< Number > &matrix)
std::tuple< FullMatrix< Number >, FullMatrix< Number >, bool > create_reference_mass_and_stiffness_matrices(const FiniteElement< 1 > &fe, const Quadrature< 1 > &quadrature)
std::pair< std::array< FullMatrix< Number >, dim >, std::array< FullMatrix< Number >, dim > > create_laplace_tensor_product_matrix(const FiniteElement< 1 > &fe, const Quadrature< 1 > &quadrature, const ::ndarray< LaplaceBoundaryType, dim, 2 > &boundary_ids, const ::ndarray< double, dim, 3 > &cell_extent, const unsigned int n_overlap=1)
FullMatrix< Number > create_1d_cell_mass_matrix(const FiniteElement< 1 > &fe, const Number &h, const std::pair< bool, bool > include_endpoints={true, true}, std::vector< unsigned int > numbering=std::vector< unsigned int >())
FullMatrix< Number > create_1D_discretization_matrix(FullMatrix< Number > &cell_matrix, const unsigned int &n_cells, const unsigned int &overlap, const std::pair< bool, bool > include_endpoints={true, true})
FullMatrix< Number > create_1d_cell_laplace_matrix(const FiniteElement< 1 > &fe, const Number &h, const std::pair< bool, bool > include_endpoints={true, true}, std::vector< unsigned int > numbering=std::vector< unsigned int >())
FullMatrix< Number > create_1d_ghost_penalty_matrix(const FiniteElement< 1 > &fe, const Number h, std::vector< Number > coefficients=std::vector< Number >())
Create a 1D ghost penalty matrix for a given finite element. Ghost penalty is used for stabilization ...
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray