Reduced Lagrange Multipliers
 
Loading...
Searching...
No Matches
reduced_coupling.h
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2024 by Luca Heltai
4//
5// This file is part of the reduced_lagrange_multipliers application, based on
6// the deal.II library.
7//
8// The reduced_lagrange_multipliers application is free software; you can use
9// it, redistribute it, and/or modify it under the terms of the Apache-2.0
10// License WITH LLVM-exception as published by the Free Software Foundation;
11// either version 3.0 of the License, or (at your option) any later version. The
12// full text of the license can be found in the file LICENSE.md at the top level
13// of the reduced_lagrange_multipliers distribution.
14//
15// ---------------------------------------------------------------------
16
17
18#ifndef rdlm_reduced_coupling_h
19#define rdlm_reduced_coupling_h
20
26
28
29#include <deal.II/fe/fe.h>
32
33#include <deal.II/grid/tria.h>
34
39#include <deal.II/lac/vector.h>
40
42
43#include <fstream>
44
46#include "particle_coupling.h"
48#include "utils.h"
49#include "vtk_utils.h"
50
51using namespace dealii;
52
67template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
104
119template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
121 : public TensorProductSpace<reduced_dim, dim, spacedim, n_components>,
122 public ParticleCoupling<spacedim>
123{
132 &par);
133
138 void
141
148 void
151 const DoFHandler<spacedim> &dh,
152 const AffineConstraints<double> &constraints) const;
153
161 template <typename MatrixType>
162 void
163 assemble_coupling_matrix(MatrixType &coupling_matrix,
164 const DoFHandler<spacedim> &dh,
165 const AffineConstraints<double> &constraints) const;
166
167 template <typename MatrixType>
168 void
169 assemble_coupling_mass_matrix(MatrixType &mass_matrix) const;
170
198 template <typename VectorType>
199 void
200 assemble_reduced_rhs(VectorType &reduced_rhs) const;
201
208
209private:
213 const MPI_Comm mpi_communicator;
214
220
225
230
234 std::unique_ptr<FunctionParser<spacedim>> coupling_rhs;
235
241};
242
243
244// Template specializations
245#ifndef DOXYGEN
246template <int reduced_dim, int dim, int spacedim, int n_components>
247template <typename MatrixType>
248inline void
250 assemble_coupling_matrix(MatrixType &coupling_matrix,
251 const DoFHandler<spacedim> &dh,
252 const AffineConstraints<double> &constraints) const
253{
254 const auto &fe = dh.get_fe();
255 const auto &immersed_fe = this->get_dof_handler().get_fe();
256
257 std::vector<types::global_dof_index> background_dof_indices(
258 fe.n_dofs_per_cell());
259
260 FullMatrix<double> local_coupling_matrix(fe.n_dofs_per_cell(),
261 immersed_fe.n_dofs_per_cell());
262
263 FullMatrix<double> local_coupling_matrix_transpose(
264 immersed_fe.n_dofs_per_cell(), fe.n_dofs_per_cell());
265
266 auto particle = this->get_particles().begin();
267 while (particle != this->get_particles().end())
268 {
269 const auto &cell = particle->get_surrounding_cell();
270 const auto dh_cell =
271 typename DoFHandler<spacedim>::cell_iterator(*cell, &dh);
272 dh_cell->get_dof_indices(background_dof_indices);
273
274 const auto pic = this->get_particles().particles_in_cell(cell);
275 Assert(pic.begin() == particle, ExcInternalError());
276
279 local_coupling_matrix = 0;
280 for (const auto &p : pic)
281 {
282 const auto [immersed_cell_id, immersed_q, section_q] =
284
285 const auto &background_p = p.get_reference_location();
286 const auto immersed_p = this->get_quadrature().point(immersed_q);
287 const auto &JxW = p.get_properties()[0];
288 last_cell_id = immersed_cell_id;
289 if (immersed_cell_id != previous_cell_id &&
290 previous_cell_id != numbers::invalid_unsigned_int)
291 {
292 // Distribute the matrix to the previous dofs
293 const auto &immersed_dof_indices =
294 this->get_dof_indices(previous_cell_id);
295 constraints.distribute_local_to_global(local_coupling_matrix,
296 background_dof_indices,
298 immersed_dof_indices,
299 coupling_matrix);
300 local_coupling_matrix = 0;
301 previous_cell_id = immersed_cell_id;
302 }
303
304 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
305 {
306 const auto comp_i = fe.system_to_component_index(i).first;
307 if (comp_i < n_components)
308 {
309 const auto v_i_comp_i = fe.shape_value(i, background_p);
310
311 for (unsigned int j = 0; j < immersed_fe.n_dofs_per_cell();
312 ++j)
313 {
314 const auto comp_j =
315 immersed_fe.system_to_component_index(j).first;
316
317 const auto phi_comp_j_comp_i =
318 this->get_reference_cross_section().shape_value(
319 comp_j, section_q, comp_i);
320
321 const auto w_j_comp_j =
322 immersed_fe.shape_value(j, immersed_p);
323
324 local_coupling_matrix(i, j) +=
325 v_i_comp_i * phi_comp_j_comp_i * w_j_comp_j * JxW;
326 }
327 }
328 }
329 }
330 const auto &immersed_dof_indices = this->get_dof_indices(last_cell_id);
331 constraints.distribute_local_to_global(local_coupling_matrix,
332 background_dof_indices,
334 immersed_dof_indices,
335 coupling_matrix);
336 particle = pic.end();
337 }
338 coupling_matrix.compress(VectorOperation::add);
339}
340
341template <int reduced_dim, int dim, int spacedim, int n_components>
342template <typename MatrixType>
343inline void
345 assemble_coupling_mass_matrix(MatrixType &mass_matrix) const
346{
347 AssertDimension(mass_matrix.m(), this->get_dof_handler().n_dofs());
348 AssertDimension(mass_matrix.n(), this->get_dof_handler().n_dofs());
349
350 mass_matrix = 0;
351 const auto &fe = this->get_dof_handler().get_fe();
352
353 FullMatrix<double> local_mass_matrix(fe.n_dofs_per_cell(),
354 fe.n_dofs_per_cell());
355 std::vector<types::global_dof_index> dof_indices(fe.n_dofs_per_cell());
357 this->get_quadrature(),
359
360
361 const auto &properties_fe = this->properties_dh.get_fe();
362 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
363 this->get_quadrature(),
365
366 // Find the index of the thickness field in the properties
367 const unsigned int thickness_field_index =
368 std::distance(this->properties_names.begin(),
369 std::find(this->properties_names.begin(),
370 this->properties_names.end(),
371 par.thickness_field_name));
372
373 const auto thickness_start =
374 thickness_field_index >= this->properties_names.size() ?
376 VTKUtils::get_block_indices(properties_fe)
377 .block_start(thickness_field_index);
378
379 FEValuesExtractors::Scalar thickness(thickness_start);
380
381 // Initialize the thickness values with the constant thickness
382 std::vector<double> thickness_values(
383 this->get_quadrature().size(),
384 par.tensor_product_space_parameters.thickness);
385
386 for (const auto &cell : this->get_dof_handler().active_cell_iterators())
387 if (cell->is_locally_owned())
388 {
389 fe_values.reinit(cell);
390 const auto &JxW = fe_values.get_JxW_values();
391
392 if (thickness_start != numbers::invalid_unsigned_int)
393 {
394 properties_fe_values.reinit(
395 cell->as_dof_handler_iterator(this->properties_dh));
396 properties_fe_values[thickness].get_function_values(
397 this->properties, thickness_values);
398 }
399
400 local_mass_matrix = 0;
401 for (const auto q : fe_values.quadrature_point_indices())
402 {
403 const auto section_measure =
404 this->get_reference_cross_section().measure(thickness_values[q]);
405
406 for (const auto i : fe_values.dof_indices())
407 {
408 const auto comp_i =
409 fe_values.get_fe().system_to_component_index(i).first;
410 for (const auto j : fe_values.dof_indices())
411 {
412 const auto comp_j =
413 fe_values.get_fe().system_to_component_index(j).first;
414 if (comp_i == comp_j)
415 local_mass_matrix(i, j) += fe_values.shape_value(i, q) *
416 fe_values.shape_value(j, q) *
417 JxW[q] * section_measure;
418 }
419 }
420 }
421 cell->get_dof_indices(dof_indices);
422 coupling_constraints.distribute_local_to_global(local_mass_matrix,
423 dof_indices,
424 mass_matrix);
425 }
426 mass_matrix.compress(VectorOperation::add);
427}
428
429
430
431template <int reduced_dim, int dim, int spacedim, int n_components>
432template <typename VectorType>
433inline void
435 VectorType &reduced_rhs) const
436{
437 FEValues<reduced_dim, spacedim> fe_values(this->get_dof_handler().get_fe(),
438 this->get_quadrature(),
442
443 Vector<double> local_rhs(this->get_dof_handler().get_fe().n_dofs_per_cell());
444 std::vector<Vector<double>> rhs_values(
445 this->get_quadrature().size(),
446 Vector<double>(this->get_reference_cross_section().n_selected_basis()));
447 std::vector<types::global_dof_index> dof_indices(
448 this->get_dof_handler().get_fe().n_dofs_per_cell());
449
450
451 const auto &properties_fe = this->properties_dh.get_fe();
452 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
453 this->get_quadrature(),
455
456 // Find the index of the thickness field in the properties
457 const unsigned int thickness_field_index =
458 std::distance(this->properties_names.begin(),
459 std::find(this->properties_names.begin(),
460 this->properties_names.end(),
461 par.thickness_field_name));
462
463 const auto thickness_start =
464 thickness_field_index >= this->properties_names.size() ?
466 VTKUtils::get_block_indices(properties_fe)
467 .block_start(thickness_field_index);
468 ;
469
470 FEValuesExtractors::Scalar thickness(thickness_start);
471
472 // Initialize the thickness values with the constant thickness
473 std::vector<double> thickness_values(
474 this->get_quadrature().size(),
475 par.tensor_product_space_parameters.thickness);
476
477 // VectorTools::create_right_hand_side(this->get_dof_handler(),
478 // this->get_quadrature(),
479 // *coupling_rhs,
480 // reduced_rhs,
481 // coupling_constraints);
482 for (const auto &cell : this->get_dof_handler().active_cell_iterators())
483 if (cell->is_locally_owned())
484 {
485 fe_values.reinit(cell);
486 const auto &JxW = fe_values.get_JxW_values();
487 const auto &q_points = fe_values.get_quadrature_points();
488 coupling_rhs->vector_value_list(q_points, rhs_values);
489
490
491 if (thickness_start != numbers::invalid_unsigned_int)
492 {
493 properties_fe_values.reinit(
494 cell->as_dof_handler_iterator(this->properties_dh));
495 properties_fe_values[thickness].get_function_values(
496 this->properties, thickness_values);
497 }
498
499 local_rhs = 0;
500 for (const auto q : fe_values.quadrature_point_indices())
501 for (const auto i : fe_values.dof_indices())
502 {
503 const auto comp_i =
504 fe_values.get_fe().system_to_component_index(i).first;
505 local_rhs(i) += rhs_values[q][comp_i] *
506 fe_values.shape_value(i, q) * JxW[q] *
507 this->get_reference_cross_section().measure(
508 thickness_values[q]);
509 }
510 cell->get_dof_indices(dof_indices);
511 coupling_constraints.distribute_local_to_global(local_rhs,
512 dof_indices,
513 reduced_rhs);
514 }
515
516 reduced_rhs.compress(VectorOperation::add);
517}
518#endif
519
520#endif
void distribute_local_to_global(const InVector &local_vector, const std::vector< size_type > &local_dof_indices, OutVector &global_vector) const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const std::vector< double > & get_JxW_values() const
void get_function_values(const ReadVector< Number > &fe_function, std::vector< Number > &values) const
const std::vector< Point< spacedim > > & get_quadrature_points() const
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 FiniteElement< dim, spacedim > & get_fe() 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)
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
ParameterAcceptor(const std::string &section_name="")
A class implementing a repartitioning policy for immersed triangulations.
SmartPointer< const Mapping< dim > > mapping
Smart pointer to the mapping associated with the triangulation.
const Particles::ParticleHandler< dim > & get_particles() const
ParticleCoupling(const ParticleCouplingParameters< dim > &par)
Constructor.
Stores parameters related to particle coupling in a simulation.
TensorProductSpace(const TensorProductSpaceParameters< reduced_dim, dim, spacedim, n_components > &par, MPI_Comm mpi_communicator=MPI_COMM_WORLD)
DoFHandler< reduced_dim, spacedim > properties_dh
const ReferenceCrossSection< dim - reduced_dim, spacedim, n_components > & get_reference_cross_section() const
auto get_quadrature() const -> const QGauss< reduced_dim > &
const DoFHandler< reduced_dim, spacedim > & get_dof_handler() const
const std::vector< types::global_dof_index > & get_dof_indices(const types::global_cell_index cell_index) const
std::tuple< unsigned int, unsigned int, unsigned int > particle_id_to_cell_and_qpoint_indices(const unsigned int qpoint_index) const
LinearAlgebra::distributed::Vector< double > properties
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
update_values
update_JxW_values
update_quadrature_points
std::size_t size
constexpr unsigned int invalid_unsigned_int
unsigned int global_cell_index
ObserverPointer< T, P > SmartPointer
static MappingQ< dim, spacedim > mapping
void initialize(const Mapping< spacedim > &mapping=StaticMappingQ1< spacedim >::mapping)
Initialize the tensor product space and particle coupling.
ImmersedRepartitioner< reduced_dim, spacedim > immersed_partitioner
void assemble_reduced_rhs(VectorType &reduced_rhs) const
Assemble the right-hand side vector for the reduced space.
void assemble_coupling_mass_matrix(MatrixType &mass_matrix) const
void assemble_coupling_matrix(MatrixType &coupling_matrix, const DoFHandler< spacedim > &dh, const AffineConstraints< double > &constraints) const
Assemble the coupling matrix between background and reduced spaces.
std::unique_ptr< FunctionParser< spacedim > > coupling_rhs
The right-hand side function for the coupling.
AffineConstraints< double > coupling_constraints
Affine constraints for the coupling.
const ReducedCouplingParameters< reduced_dim, dim, spacedim, n_components > & par
Reference to the parameters used for this coupling.
void assemble_coupling_sparsity(DynamicSparsityPattern &dsp, const DoFHandler< spacedim > &dh, const AffineConstraints< double > &constraints) const
Assemble the sparsity pattern for the coupling matrix.
const MPI_Comm mpi_communicator
The MPI communicator used for parallel operations.
ReducedCoupling(parallel::TriangulationBase< spacedim > &background_tria, const ReducedCouplingParameters< reduced_dim, dim, spacedim, n_components > &par)
Constructor that initializes the ReducedCoupling object with background triangulation and parameters.
SmartPointer< parallel::TriangulationBase< spacedim > > background_tria
The triangulation of the background domain.
const AffineConstraints< double > & get_coupling_constraints() const
Get the affine constraints associated with the coupling.
Parameter structure for configuring ReducedCoupling objects.
ReducedCouplingParameters()
Constructor that registers parameters with the ParameterAcceptor.
ParticleCouplingParameters< spacedim > particle_coupling_parameters
Parameters for the particle coupling.
RefinementParameters refinement_parameters
TensorProductSpaceParameters< reduced_dim, dim, spacedim, n_components > tensor_product_space_parameters
Parameters for the tensor product space.
std::vector< std::string > coupling_rhs_expressions
Right hand side expressions for the reduced coupling.