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 "vtk_utils.h"
49
50using namespace dealii;
51
66template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
103
118template <int reduced_dim, int dim, int spacedim = dim, int n_components = 1>
120 : public TensorProductSpace<reduced_dim, dim, spacedim, n_components>,
121 public ParticleCoupling<spacedim>
122{
131 &par);
132
137 void
140
147 void
150 const DoFHandler<spacedim> &dh,
151 const AffineConstraints<double> &constraints) const;
152
160 template <typename MatrixType>
161 void
162 assemble_coupling_matrix(MatrixType &coupling_matrix,
163 const DoFHandler<spacedim> &dh,
164 const AffineConstraints<double> &constraints) const;
165
166 template <typename MatrixType>
167 void
168 assemble_coupling_mass_matrix(MatrixType &mass_matrix) const;
169
197 template <typename VectorType>
198 void
199 assemble_reduced_rhs(VectorType &reduced_rhs) const;
200
207
208private:
212 const MPI_Comm mpi_communicator;
213
219
224
229
233 std::unique_ptr<FunctionParser<spacedim>> coupling_rhs;
234
240};
241
242
243// Template specializations
244#ifndef DOXYGEN
245template <int reduced_dim, int dim, int spacedim, int n_components>
246template <typename MatrixType>
247inline void
249 assemble_coupling_matrix(MatrixType &coupling_matrix,
250 const DoFHandler<spacedim> &dh,
251 const AffineConstraints<double> &constraints) const
252{
253 const auto &fe = dh.get_fe();
254 const auto &immersed_fe = this->get_dof_handler().get_fe();
255
256 std::vector<types::global_dof_index> background_dof_indices(
257 fe.n_dofs_per_cell());
258
259 FullMatrix<double> local_coupling_matrix(fe.n_dofs_per_cell(),
260 immersed_fe.n_dofs_per_cell());
261
262 FullMatrix<double> local_coupling_matrix_transpose(
263 immersed_fe.n_dofs_per_cell(), fe.n_dofs_per_cell());
264
265 auto particle = this->get_particles().begin();
266 while (particle != this->get_particles().end())
267 {
268 const auto &cell = particle->get_surrounding_cell();
269 const auto dh_cell =
270 typename DoFHandler<spacedim>::cell_iterator(*cell, &dh);
271 dh_cell->get_dof_indices(background_dof_indices);
272
273 const auto pic = this->get_particles().particles_in_cell(cell);
274 Assert(pic.begin() == particle, ExcInternalError());
275
278 local_coupling_matrix = 0;
279 for (const auto &p : pic)
280 {
281 const auto [immersed_cell_id, immersed_q, section_q] =
283
284 const auto &background_p = p.get_reference_location();
285 const auto immersed_p = this->get_quadrature().point(immersed_q);
286 const auto &JxW = p.get_properties()[0];
287 last_cell_id = immersed_cell_id;
288 if (immersed_cell_id != previous_cell_id &&
289 previous_cell_id != numbers::invalid_unsigned_int)
290 {
291 // Distribute the matrix to the previous dofs
292 const auto &immersed_dof_indices =
293 this->get_dof_indices(previous_cell_id);
294 constraints.distribute_local_to_global(local_coupling_matrix,
295 background_dof_indices,
297 immersed_dof_indices,
298 coupling_matrix);
299 local_coupling_matrix = 0;
300 previous_cell_id = immersed_cell_id;
301 }
302
303 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
304 {
305 const auto comp_i = fe.system_to_component_index(i).first;
306 if (comp_i < n_components)
307 {
308 const auto v_i_comp_i = fe.shape_value(i, background_p);
309
310 for (unsigned int j = 0; j < immersed_fe.n_dofs_per_cell();
311 ++j)
312 {
313 const auto comp_j =
314 immersed_fe.system_to_component_index(j).first;
315
316 const auto phi_comp_j_comp_i =
317 this->get_reference_cross_section().shape_value(
318 comp_j, section_q, comp_i);
319
320 const auto w_j_comp_j =
321 immersed_fe.shape_value(j, immersed_p);
322
323 local_coupling_matrix(i, j) +=
324 v_i_comp_i * phi_comp_j_comp_i * w_j_comp_j * JxW;
325 }
326 }
327 }
328 }
329 const auto &immersed_dof_indices = this->get_dof_indices(last_cell_id);
330 constraints.distribute_local_to_global(local_coupling_matrix,
331 background_dof_indices,
333 immersed_dof_indices,
334 coupling_matrix);
335 particle = pic.end();
336 }
337 coupling_matrix.compress(VectorOperation::add);
338}
339
340template <int reduced_dim, int dim, int spacedim, int n_components>
341template <typename MatrixType>
342inline void
344 assemble_coupling_mass_matrix(MatrixType &mass_matrix) const
345{
346 AssertDimension(mass_matrix.m(), this->get_dof_handler().n_dofs());
347 AssertDimension(mass_matrix.n(), this->get_dof_handler().n_dofs());
348
349 mass_matrix = 0;
350 const auto &fe = this->get_dof_handler().get_fe();
351
352 FullMatrix<double> local_mass_matrix(fe.n_dofs_per_cell(),
353 fe.n_dofs_per_cell());
354 std::vector<types::global_dof_index> dof_indices(fe.n_dofs_per_cell());
356 this->get_quadrature(),
358
359
360 const auto &properties_fe = this->properties_dh.get_fe();
361 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
362 this->get_quadrature(),
364
365 // Find the index of the thickness field in the properties
366 const unsigned int thickness_field_index =
367 std::distance(this->properties_names.begin(),
368 std::find(this->properties_names.begin(),
369 this->properties_names.end(),
370 par.thickness_field_name));
371
372 const auto thickness_start =
373 thickness_field_index >= this->properties_names.size() ?
375 VTKUtils::get_block_indices(properties_fe)
376 .block_start(thickness_field_index);
377
378 FEValuesExtractors::Scalar thickness(thickness_start);
379
380 // Initialize the thickness values with the constant thickness
381 std::vector<double> thickness_values(
382 this->get_quadrature().size(),
383 par.tensor_product_space_parameters.thickness);
384
385 for (const auto &cell : this->get_dof_handler().active_cell_iterators())
386 if (cell->is_locally_owned())
387 {
388 fe_values.reinit(cell);
389 const auto &JxW = fe_values.get_JxW_values();
390
391 if (thickness_start != numbers::invalid_unsigned_int)
392 {
393 properties_fe_values.reinit(
394 cell->as_dof_handler_iterator(this->properties_dh));
395 properties_fe_values[thickness].get_function_values(
396 this->properties, thickness_values);
397 }
398
399 local_mass_matrix = 0;
400 for (const auto q : fe_values.quadrature_point_indices())
401 {
402 const auto section_measure =
403 this->get_reference_cross_section().measure(thickness_values[q]);
404
405 for (const auto i : fe_values.dof_indices())
406 {
407 const auto comp_i =
408 fe_values.get_fe().system_to_component_index(i).first;
409 for (const auto j : fe_values.dof_indices())
410 {
411 const auto comp_j =
412 fe_values.get_fe().system_to_component_index(j).first;
413 if (comp_i == comp_j)
414 local_mass_matrix(i, j) += fe_values.shape_value(i, q) *
415 fe_values.shape_value(j, q) *
416 JxW[q] * section_measure;
417 }
418 }
419 }
420 cell->get_dof_indices(dof_indices);
421 coupling_constraints.distribute_local_to_global(local_mass_matrix,
422 dof_indices,
423 mass_matrix);
424 }
425 mass_matrix.compress(VectorOperation::add);
426}
427
428
429
430template <int reduced_dim, int dim, int spacedim, int n_components>
431template <typename VectorType>
432inline void
434 VectorType &reduced_rhs) const
435{
436 FEValues<reduced_dim, spacedim> fe_values(this->get_dof_handler().get_fe(),
437 this->get_quadrature(),
441
442 Vector<double> local_rhs(this->get_dof_handler().get_fe().n_dofs_per_cell());
443 std::vector<Vector<double>> rhs_values(
444 this->get_quadrature().size(),
445 Vector<double>(this->get_reference_cross_section().n_selected_basis()));
446 std::vector<types::global_dof_index> dof_indices(
447 this->get_dof_handler().get_fe().n_dofs_per_cell());
448
449
450 const auto &properties_fe = this->properties_dh.get_fe();
451 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
452 this->get_quadrature(),
454
455 // Find the index of the thickness field in the properties
456 const unsigned int thickness_field_index =
457 std::distance(this->properties_names.begin(),
458 std::find(this->properties_names.begin(),
459 this->properties_names.end(),
460 par.thickness_field_name));
461
462 const auto thickness_start =
463 thickness_field_index >= this->properties_names.size() ?
465 VTKUtils::get_block_indices(properties_fe)
466 .block_start(thickness_field_index);
467 ;
468
469 FEValuesExtractors::Scalar thickness(thickness_start);
470
471 // Initialize the thickness values with the constant thickness
472 std::vector<double> thickness_values(
473 this->get_quadrature().size(),
474 par.tensor_product_space_parameters.thickness);
475
476 // VectorTools::create_right_hand_side(this->get_dof_handler(),
477 // this->get_quadrature(),
478 // *coupling_rhs,
479 // reduced_rhs,
480 // coupling_constraints);
481 for (const auto &cell : this->get_dof_handler().active_cell_iterators())
482 if (cell->is_locally_owned())
483 {
484 fe_values.reinit(cell);
485 const auto &JxW = fe_values.get_JxW_values();
486 const auto &q_points = fe_values.get_quadrature_points();
487 coupling_rhs->vector_value_list(q_points, rhs_values);
488
489
490 if (thickness_start != numbers::invalid_unsigned_int)
491 {
492 properties_fe_values.reinit(
493 cell->as_dof_handler_iterator(this->properties_dh));
494 properties_fe_values[thickness].get_function_values(
495 this->properties, thickness_values);
496 }
497
498 local_rhs = 0;
499 for (const auto q : fe_values.quadrature_point_indices())
500 for (const auto i : fe_values.dof_indices())
501 {
502 const auto comp_i =
503 fe_values.get_fe().system_to_component_index(i).first;
504 local_rhs(i) += rhs_values[q][comp_i] *
505 fe_values.shape_value(i, q) * JxW[q] *
506 this->get_reference_cross_section().measure(
507 thickness_values[q]);
508 }
509 cell->get_dof_indices(dof_indices);
510 coupling_constraints.distribute_local_to_global(local_rhs,
511 dof_indices,
512 reduced_rhs);
513 }
514
515 reduced_rhs.compress(VectorOperation::add);
516}
517#endif
518
519#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
SmartPointer< const parallel::TriangulationBase< spacedim > > background_tria
The triangulation of the background domain.
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.
ReducedCoupling(const 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.
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.
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.
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.
unsigned int pre_refinement
Number of pre-refinements to apply to the grid before distribution.