Fluid structure interaction suite
linear_elasticity.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2022 by Luca Heltai
4 //
5 // This file is part of the FSI-suite platform, based on the deal.II library.
6 //
7 // The FSI-suite platform is free software; you can use it, redistribute it,
8 // and/or modify it under the terms of the GNU Lesser General Public License as
9 // published by the Free Software Foundation; either version 3.0 of the License,
10 // or (at your option) any later version. The full text of the license can be
11 // found in the file LICENSE at the top level of the FSI-suite platform
12 // distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include "pdes/linear_elasticity.h"
17 
19 
21 
22 using namespace dealii;
23 
24 namespace PDEs
25 {
26  template <int dim, int spacedim, class LacType>
28  : LinearProblem<dim, spacedim, LacType>(
29  ParsedTools::Components::blocks_to_names({"W"}, {spacedim}),
30  "LinearElasticity")
31  , lambda("/LinearElasticity/Lame coefficients", "1.0", "lambda")
32  , mu("/LinearElasticity/Lame coefficients", "1.0", "mu")
33  , displacement(0)
34  {
35  this->output_results_call_back.connect([&]() { postprocess(); });
36  this->check_consistency_call_back.connect([&]() {
38  this->evolution_type != EvolutionType::transient,
39  ExcMessage(
40  "This code won't produce correct results in transient simulations. "
41  "Run the wave_equation code instead."));
42  });
43  }
44 
45 
46 
47  template <int dim, int spacedim, class LacType>
48  void
51  ScratchData &scratch,
52  CopyData &copy)
53  {
54  auto &cell_matrix = copy.matrices[0];
55  auto &cell_rhs = copy.vectors[0];
56 
57  cell->get_dof_indices(copy.local_dof_indices[0]);
58 
59  const auto &fe_values = scratch.reinit(cell);
60  cell_matrix = 0;
61  cell_rhs = 0;
62 
63  for (const unsigned int q_index : fe_values.quadrature_point_indices())
64  {
65  for (const unsigned int i : fe_values.dof_indices())
66  {
67  const auto x = fe_values.quadrature_point(q_index);
68  const auto &eps_v =
69  fe_values[displacement].symmetric_gradient(i, q_index);
70  const auto &div_v = fe_values[displacement].divergence(i, q_index);
71 
72  for (const unsigned int j : fe_values.dof_indices())
73  {
74  const auto &eps_u =
75  fe_values[displacement].symmetric_gradient(j, q_index);
76  const auto &div_u =
77  fe_values[displacement].divergence(j, q_index);
78  cell_matrix(i, j) += (2 * mu.value(x) * eps_v * eps_u +
79  lambda.value(x) * div_v * div_u) *
80  fe_values.JxW(q_index); // dx
81  }
82 
83  cell_rhs(i) +=
84  (fe_values.shape_value(i, q_index) * // phi_i(x_q)
85  this->forcing_term.value(x,
86  this->finite_element()
87  .system_to_component_index(i)
88  .first) * // f(x_q)
89  fe_values.JxW(q_index)); // dx
90  }
91  }
92  }
93 
94 
95 
96  template <int dim, int spacedim, class LacType>
97  void
99  {
100  TimerOutput::Scope timer_section(this->timer, "solve");
101  const auto A = linear_operator<VectorType>(this->matrix.block(0, 0));
102  this->preconditioner.initialize(this->matrix.block(0, 0));
103  const auto Ainv = this->inverse_operator(A, this->preconditioner);
104  this->solution.block(0) = Ainv * this->rhs.block(0);
105  this->constraints.distribute(this->solution);
106  this->locally_relevant_solution = this->solution;
107  }
108 
109 
110 
111  template <int dim, int spacedim, class LacType>
112  void
114  {
115  // Construct an object that will integrate on the faces only
116  std::map<types::boundary_id, Tensor<1, spacedim>> forces;
117 
118  const auto face_integrator = [&](const auto &cell,
119  const auto &face,
120  auto &scratch,
121  auto &data) {
122  data[cell->face(face)->boundary_id()] = Tensor<1, spacedim>();
123 
124  auto &f = data[cell->face(face)->boundary_id()];
125 
126  const auto &fe_face_values = scratch.reinit(cell, face);
127  scratch.extract_local_dof_values("solution",
128  this->locally_relevant_solution);
129  const auto &eps_u =
130  scratch.get_symmetric_gradients("solution", displacement);
131 
132  const auto &div_u = scratch.get_divergences("solution", displacement);
133 
134  const auto &n = scratch.get_normal_vectors();
135  const auto &JxW = scratch.get_JxW_values();
136 
137  for (unsigned int q = 0; q < n.size(); ++q)
138  f +=
139  (2 * mu.value(fe_face_values.quadrature_point(q)) * eps_u[q] * n[q] +
140  lambda.value(fe_face_values.quadrature_point(q)) * div_u[q] * n[q]) *
141  JxW[q];
142  };
143 
144  const auto copyer = [&](const auto &data) {
145  for (const auto &[id, f] : data)
146  {
147  if (forces.find(id) == forces.end())
148  forces[id] = f;
149  else
150  forces[id] += f;
151  };
152  };
153 
154  Quadrature<dim> quadrature_formula =
156  this->triangulation, this->finite_element().tensor_degree() + 1);
157 
158  Quadrature<dim - 1> face_quadrature_formula =
160  this->triangulation, this->finite_element().tensor_degree() + 1);
161 
162  ScratchData scratch(*this->mapping,
163  this->finite_element(),
164  quadrature_formula,
166  face_quadrature_formula,
170 
171 
172  using CellFilter = FilteredIterator<
174 
176  this->dof_handler.begin_active()),
178  this->dof_handler.end()),
179  {},
180  copyer,
181  scratch,
182  forces,
184  face_integrator);
185 
186  deallog << "Forces: " << std::endl;
187  for (const auto &[id, force] : forces)
188  deallog << "ID " << id << ": " << force << std::endl;
189  }
190 
191 
192 
196 
200 } // namespace PDEs
void reinit(const Triangulation< dim, spacedim > &tria)
virtual void solve() override
Make sure we initialize the right type of linear solver.
typename LinearProblem< dim, spacedim, LacType >::ScratchData ScratchData
typename LinearProblem< dim, spacedim, LacType >::CopyData CopyData
virtual void assemble_system_one_cell(const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, ScratchData &scratch, CopyData &copy) override
Explicitly assemble the LinearElasticity problem on a single cell.
void postprocess()
Compute integrals normal stress on Dirichlet faces, and average displacement on Neumann faces.
Construct a LinearProblem.
Point< 2 > first
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const Preconditioner &preconditioner)
void mesh_loop(const CellIteratorType &begin, const CellIteratorType &end, const CellWorkerFunctionType &cell_worker, const CopierType &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const BoundaryWorkerFunctionType &boundary_worker=BoundaryWorkerFunctionType(), const FaceWorkerFunctionType &face_worker=FaceWorkerFunctionType(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
update_values
update_normal_vectors
update_JxW_values
update_gradients
update_quadrature_points
update_default
LogStream deallog
PDEs::LinearElasticity< dim, spacedim, LAC::LATrilinos > LinearElasticity
We collect in this namespace all PDEs that are relevant to Fluid Structure Interaction Problems.
Quadrature< dim - 1 > get_face_quadrature(const Triangulation< dim, spacedim > &tria, const unsigned int degree)
Return a Quadrature object that can be used on the given Triangulation faces.
std::string blocks_to_names(const std::vector< std::string > &components, const std::vector< unsigned int > &multiplicities)
Build component names from block names and multiplicities.
Definition: components.cc:40
Quadrature< dim > get_cell_quadrature(const Triangulation< dim, spacedim > &tria, const unsigned int degree)
Return a Quadrature object that can be used on the given Triangulation cells.
We collect in this namespace some wrappers around commonly used deal.II classes, derived from the Par...
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation