Program Listing for File reduced_coupling.h¶
↰ Return to documentation for file (include/reduced_coupling.h)
// ---------------------------------------------------------------------
//
// Copyright (C) 2024 by Luca Heltai
//
// This file is part of the reduced_lagrange_multipliers application, based on
// the deal.II library.
//
// The reduced_lagrange_multipliers application is free software; you can use
// it, redistribute it, and/or modify it under the terms of the Apache-2.0
// License WITH LLVM-exception as published by the Free Software Foundation;
// either version 3.0 of the License, or (at your option) any later version. The
// full text of the license can be found in the file LICENSE.md at the top level
// of the reduced_lagrange_multipliers distribution.
//
// ---------------------------------------------------------------------
#ifndef rdlm_reduced_coupling_h
#define rdlm_reduced_coupling_h
#include <deal.II/base/function_parser.h>
#include <deal.II/base/parameter_acceptor.h>
#include <deal.II/base/patterns.h>
#include <deal.II/base/polynomials_p.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/fe/fe.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/mapping_q.h>
#include <deal.II/grid/tria.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/la_parallel_vector.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/sparsity_pattern.h>
#include <deal.II/lac/vector.h>
#include <deal.II/numerics/vector_tools.h>
#include <fstream>
#include "immersed_repartitioner.h"
#include "particle_coupling.h"
#include "tensor_product_space.h"
#include "utils.h"
#ifdef DEAL_II_WITH_VTK
# include "vtk_utils.h"
using namespace dealii;
template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
struct ReducedCouplingParameters : public ParameterAcceptor
{
ReducedCouplingParameters();
TensorProductSpaceParameters<reduced_dim, dim, spacedim, n_components>
tensor_product_space_parameters;
ParticleCouplingParameters<spacedim> particle_coupling_parameters;
RefinementParameters refinement_parameters;
std::string thickness_field_name = "";
std::vector<std::string> coupling_rhs_expressions = {"0"};
};
template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
struct ReducedCoupling
: public TensorProductSpace<reduced_dim, dim, spacedim, n_components>,
public ParticleCoupling<spacedim>
{
ReducedCoupling(
parallel::TriangulationBase<spacedim> &background_tria,
const ReducedCouplingParameters<reduced_dim, dim, spacedim, n_components>
&par);
void
initialize(
const Mapping<spacedim> &mapping = StaticMappingQ1<spacedim>::mapping);
void
assemble_coupling_sparsity(
DynamicSparsityPattern &dsp,
const DoFHandler<spacedim> &dh,
const AffineConstraints<double> &constraints) const;
template <typename MatrixType>
void
assemble_coupling_matrix(MatrixType &coupling_matrix,
const DoFHandler<spacedim> &dh,
const AffineConstraints<double> &constraints) const;
template <typename MatrixType>
void
assemble_coupling_mass_matrix(MatrixType &mass_matrix) const;
template <typename VectorType>
void
assemble_reduced_rhs(VectorType &reduced_rhs) const;
const AffineConstraints<double> &
get_coupling_constraints() const;
private:
const MPI_Comm mpi_communicator;
const ReducedCouplingParameters<reduced_dim, dim, spacedim, n_components>
∥
SmartPointer<parallel::TriangulationBase<spacedim>> background_tria;
AffineConstraints<double> coupling_constraints;
std::unique_ptr<FunctionParser<spacedim>> coupling_rhs;
ImmersedRepartitioner<reduced_dim, spacedim> immersed_partitioner;
};
// Template specializations
# ifndef DOXYGEN
template <int reduced_dim, int dim, int spacedim, int n_components>
template <typename MatrixType>
inline void
ReducedCoupling<reduced_dim, dim, spacedim, n_components>::
assemble_coupling_matrix(MatrixType &coupling_matrix,
const DoFHandler<spacedim> &dh,
const AffineConstraints<double> &constraints) const
{
const auto &fe = dh.get_fe();
const auto &immersed_fe = this->get_dof_handler().get_fe();
std::vector<types::global_dof_index> background_dof_indices(
fe.n_dofs_per_cell());
FullMatrix<double> local_coupling_matrix(fe.n_dofs_per_cell(),
immersed_fe.n_dofs_per_cell());
FullMatrix<double> local_coupling_matrix_transpose(
immersed_fe.n_dofs_per_cell(), fe.n_dofs_per_cell());
auto particle = this->get_particles().begin();
while (particle != this->get_particles().end())
{
const auto &cell = particle->get_surrounding_cell();
const auto dh_cell =
typename DoFHandler<spacedim>::cell_iterator(*cell, &dh);
dh_cell->get_dof_indices(background_dof_indices);
const auto pic = this->get_particles().particles_in_cell(cell);
Assert(pic.begin() == particle, ExcInternalError());
types::global_cell_index previous_cell_id = numbers::invalid_unsigned_int;
types::global_cell_index last_cell_id = numbers::invalid_unsigned_int;
local_coupling_matrix = 0;
for (const auto &p : pic)
{
const auto [immersed_cell_id, immersed_q, section_q] =
this->particle_id_to_cell_and_qpoint_indices(p.get_id());
const auto &background_p = p.get_reference_location();
const auto immersed_p = this->get_quadrature().point(immersed_q);
const double JxW = p.get_properties()[0];
last_cell_id = immersed_cell_id;
if (immersed_cell_id != previous_cell_id &&
previous_cell_id != numbers::invalid_unsigned_int)
{
// Distribute the matrix to the previous dofs
const auto &immersed_dof_indices =
this->get_dof_indices(previous_cell_id);
constraints.distribute_local_to_global(local_coupling_matrix,
background_dof_indices,
coupling_constraints,
immersed_dof_indices,
coupling_matrix);
local_coupling_matrix = 0;
previous_cell_id = immersed_cell_id;
}
for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
{
const auto comp_i = fe.system_to_component_index(i).first;
if (comp_i < n_components)
{
const auto v_i_comp_i = fe.shape_value(i, background_p);
for (unsigned int j = 0; j < immersed_fe.n_dofs_per_cell();
++j)
{
const auto comp_j =
immersed_fe.system_to_component_index(j).first;
const auto phi_comp_j_comp_i =
this->get_reference_cross_section().shape_value(
comp_j, section_q, comp_i);
const auto w_j_comp_j =
immersed_fe.shape_value(j, immersed_p);
local_coupling_matrix(i, j) +=
v_i_comp_i * phi_comp_j_comp_i * w_j_comp_j * JxW;
}
}
}
}
const auto &immersed_dof_indices = this->get_dof_indices(last_cell_id);
constraints.distribute_local_to_global(local_coupling_matrix,
background_dof_indices,
coupling_constraints,
immersed_dof_indices,
coupling_matrix);
particle = pic.end();
}
coupling_matrix.compress(VectorOperation::add);
}
template <int reduced_dim, int dim, int spacedim, int n_components>
template <typename MatrixType>
inline void
ReducedCoupling<reduced_dim, dim, spacedim, n_components>::
assemble_coupling_mass_matrix(MatrixType &mass_matrix) const
{
AssertDimension(mass_matrix.m(), this->get_dof_handler().n_dofs());
AssertDimension(mass_matrix.n(), this->get_dof_handler().n_dofs());
mass_matrix = 0;
const auto &fe = this->get_dof_handler().get_fe();
FullMatrix<double> local_mass_matrix(fe.n_dofs_per_cell(),
fe.n_dofs_per_cell());
std::vector<types::global_dof_index> dof_indices(fe.n_dofs_per_cell());
FEValues<reduced_dim, spacedim> fe_values(fe,
this->get_quadrature(),
update_values | update_JxW_values);
const auto &properties_fe = this->properties_dh.get_fe();
FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
this->get_quadrature(),
update_values);
// Find the index of the thickness field in the properties
const unsigned int thickness_field_index =
std::distance(this->properties_names.begin(),
std::find(this->properties_names.begin(),
this->properties_names.end(),
par.thickness_field_name));
const auto thickness_start =
thickness_field_index >= this->properties_names.size() ?
numbers::invalid_unsigned_int :
VTKUtils::get_block_indices(properties_fe)
.block_start(thickness_field_index);
FEValuesExtractors::Scalar thickness(thickness_start);
// Initialize the thickness values with the constant thickness
std::vector<double> thickness_values(
this->get_quadrature().size(),
par.tensor_product_space_parameters.thickness);
for (const auto &cell : this->get_dof_handler().active_cell_iterators())
if (cell->is_locally_owned())
{
fe_values.reinit(cell);
const auto &JxW = fe_values.get_JxW_values();
if (thickness_start != numbers::invalid_unsigned_int)
{
properties_fe_values.reinit(
cell->as_dof_handler_iterator(this->properties_dh));
properties_fe_values[thickness].get_function_values(
this->properties, thickness_values);
}
local_mass_matrix = 0;
for (const auto q : fe_values.quadrature_point_indices())
{
const auto section_measure =
this->get_reference_cross_section().measure(thickness_values[q]);
for (const auto i : fe_values.dof_indices())
{
const auto comp_i =
fe_values.get_fe().system_to_component_index(i).first;
for (const auto j : fe_values.dof_indices())
{
const auto comp_j =
fe_values.get_fe().system_to_component_index(j).first;
if (comp_i == comp_j)
local_mass_matrix(i, j) += fe_values.shape_value(i, q) *
fe_values.shape_value(j, q) *
JxW[q] * section_measure;
}
}
}
cell->get_dof_indices(dof_indices);
coupling_constraints.distribute_local_to_global(local_mass_matrix,
dof_indices,
mass_matrix);
}
mass_matrix.compress(VectorOperation::add);
}
template <int reduced_dim, int dim, int spacedim, int n_components>
template <typename VectorType>
inline void
ReducedCoupling<reduced_dim, dim, spacedim, n_components>::assemble_reduced_rhs(
VectorType &reduced_rhs) const
{
FEValues<reduced_dim, spacedim> fe_values(this->get_dof_handler().get_fe(),
this->get_quadrature(),
update_values |
update_quadrature_points |
update_JxW_values);
Vector<double> local_rhs(this->get_dof_handler().get_fe().n_dofs_per_cell());
std::vector<Vector<double>> rhs_values(
this->get_quadrature().size(),
Vector<double>(this->get_reference_cross_section().n_selected_basis()));
std::vector<types::global_dof_index> dof_indices(
this->get_dof_handler().get_fe().n_dofs_per_cell());
const auto &properties_fe = this->properties_dh.get_fe();
FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
this->get_quadrature(),
update_values);
// Find the index of the thickness field in the properties
const unsigned int thickness_field_index =
std::distance(this->properties_names.begin(),
std::find(this->properties_names.begin(),
this->properties_names.end(),
par.thickness_field_name));
const auto thickness_start =
thickness_field_index >= this->properties_names.size() ?
numbers::invalid_unsigned_int :
VTKUtils::get_block_indices(properties_fe)
.block_start(thickness_field_index);
;
FEValuesExtractors::Scalar thickness(thickness_start);
// Initialize the thickness values with the constant thickness
std::vector<double> thickness_values(
this->get_quadrature().size(),
par.tensor_product_space_parameters.thickness);
// VectorTools::create_right_hand_side(this->get_dof_handler(),
// this->get_quadrature(),
// *coupling_rhs,
// reduced_rhs,
// coupling_constraints);
for (const auto &cell : this->get_dof_handler().active_cell_iterators())
if (cell->is_locally_owned())
{
fe_values.reinit(cell);
const auto &JxW = fe_values.get_JxW_values();
const auto &q_points = fe_values.get_quadrature_points();
coupling_rhs->vector_value_list(q_points, rhs_values);
if (thickness_start != numbers::invalid_unsigned_int)
{
properties_fe_values.reinit(
cell->as_dof_handler_iterator(this->properties_dh));
properties_fe_values[thickness].get_function_values(
this->properties, thickness_values);
}
local_rhs = 0;
for (const auto q : fe_values.quadrature_point_indices())
for (const auto i : fe_values.dof_indices())
{
const auto comp_i =
fe_values.get_fe().system_to_component_index(i).first;
local_rhs(i) += rhs_values[q][comp_i] *
fe_values.shape_value(i, q) * JxW[q] *
this->get_reference_cross_section().measure(
thickness_values[q]);
}
cell->get_dof_indices(dof_indices);
coupling_constraints.distribute_local_to_global(local_rhs,
dof_indices,
reduced_rhs);
}
reduced_rhs.compress(VectorOperation::add);
}
# endif
#endif // DEAL_II_WITH_VTK
#endif