Fluid structure interaction suite
linear_visco_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 // ---------------------------------------------------------------------
16 
18 
20 
22 
23 using namespace dealii;
24 
25 namespace PDEs
26 {
27  template <int dim, int spacedim, class LacType>
29  : LinearProblem<dim, spacedim, LacType>(
30  ParsedTools::Components::blocks_to_names({"U"}, {spacedim}),
31  "LinearViscoElasticity")
32  , displacement(0)
33  , constants_0("/LinearViscoElasticity/Constants 0",
34  {"mu", "lambda", "eta", "kappa"},
35  {1.0, 1.0, 0.0, 0.0},
36  {"First Lame coefficient",
37  "Second Lame coefficient",
38  "Shear viscosity",
39  "Bulk viscosity"})
40  , constants_1("/LinearViscoElasticity/Constants 1",
41  {"mu", "lambda", "eta", "kappa"},
42  {0.0, 0.0, 1.0, 1.0},
43  {"First Lame coefficient",
44  "Second Lame coefficient",
45  "Shear viscosity",
46  "Bulk viscosity"})
47  , material_ids_0({0})
48  , eulerian_mapping(this->dof_handler, "/LinearViscoElasticity/Mapping")
49  {
50  this->add_parameter("Material ids of region 0", material_ids_0);
51  this->add_parameter("Material ids of region 1", material_ids_1);
52 
53  this->output_results_call_back.connect([&]() { postprocess(); });
54  this->check_consistency_call_back.connect([&]() {
56  this->evolution_type != EvolutionType::transient,
57  ExcMessage(
58  "This code won't produce correct results in transient simulations. "
59  "Run the wave_equation code instead."));
60  // const auto m = this->triangulation().get_material_ids();
61 
62  auto all_m = material_ids_0;
63  all_m.insert(material_ids_1.begin(), material_ids_1.end());
64 
65  AssertThrow(all_m.size() ==
66  (material_ids_0.size() + material_ids_1.size()),
67  ExcMessage("You cannot assign the same material id to two "
68  "different regions"));
69 
70  // AssertThrow(m.size() == (material_ids_0.size() +
71  // material_ids_1.size()),
72  // ExcMessage(
73  // "The mesh must have the same number of material ids "
74  // "as the number of material ids you specified "
75  // "in the parameter file"));
76  });
77 
78  this->setup_system_call_back.connect([&]() {
79  // Make sure we only setup the displacement vector once
80  if (current_cycle == 0)
81  {
82  current_displacement_locally_relevant.reinit(
83  this->locally_relevant_solution);
84  current_displacement.reinit(this->solution);
85  eulerian_mapping.initialize(current_displacement,
86  current_displacement_locally_relevant);
87  }
88  });
89 
90  this->advance_time_call_back.connect(
91  [&](const auto &t, const auto &dt, const auto &n) {
92  this->current_time = t;
93  this->dt = dt;
94  this->current_cycle = n;
95  });
96 
97  this->add_data_vector.connect([&](auto &d) {
98  d.add_data_vector(current_displacement_locally_relevant,
100  {spacedim}),
101  dealii::DataOut<dim, spacedim>::type_dof_data);
102  });
103  }
104 
105 
106 
107  template <int dim, int spacedim, class LacType>
108  void
110  {
111  TimerOutput::Scope timer_section(this->timer, "assemble_system");
112  Quadrature<dim> quadrature_formula =
114  this->triangulation, this->finite_element().tensor_degree() + 1);
115 
116 
117  ScratchData scratch(this->finite_element(),
118  quadrature_formula,
120 
121  ScratchData mapped_scratch(eulerian_mapping(),
122  this->finite_element(),
123  quadrature_formula,
126 
127  CopyData copy(this->finite_element().n_dofs_per_cell());
128 
129  this->rhs = 0;
130  this->matrix = 0;
131 
132  for (const auto &cell : this->dof_handler.active_cell_iterators())
133  if (cell->is_locally_owned())
134  {
135  auto &cell_matrix = copy.matrices[0];
136  auto &cell_rhs = copy.vectors[0];
137 
138  cell->get_dof_indices(copy.local_dof_indices[0]);
139 
140  const auto &fe_values = scratch.reinit(cell);
141  const auto &mapped_fe_values = mapped_scratch.reinit(cell);
142 
143  cell_matrix = 0;
144  cell_rhs = 0;
145 
146  scratch.extract_local_dof_values(
147  "Wn", this->current_displacement_locally_relevant);
148  const auto &div_Wn = scratch.get_divergences("Wn", displacement);
149  const auto &eps_Wn =
150  scratch.get_symmetric_gradients("Wn", displacement);
151 
152  const ParsedTools::Constants &c =
153  (material_ids_0.find(cell->material_id()) != material_ids_0.end()) ?
154  constants_0 :
155  constants_1;
156 
157  static const auto identity = unit_symmetric_tensor<spacedim>();
158 
159  for (const unsigned int q_index :
160  fe_values.quadrature_point_indices())
161  for (const unsigned int i : fe_values.dof_indices())
162  {
163  const auto x = mapped_fe_values.quadrature_point(q_index);
164 
165  // Lagrangian
166  const auto &eps_V =
167  fe_values[displacement].symmetric_gradient(i, q_index);
168 
169  // Eulerian
170  const auto eps_v =
171  mapped_fe_values[displacement].symmetric_gradient(i, q_index);
172 
173  for (const unsigned int j : fe_values.dof_indices())
174  {
175  // Elastic part.
176  const auto &eps_W =
177  fe_values[displacement].symmetric_gradient(j, q_index);
178  const auto &div_W =
179  fe_values[displacement].divergence(j, q_index);
180 
181  const auto P_el = this->dt * 2 * c["mu"] * eps_W +
182  c["lambda"] * div_W * identity;
183 
184  const auto &eps_u =
185  mapped_fe_values[displacement].symmetric_gradient(
186  j, q_index);
187 
188  const auto &div_u =
189  mapped_fe_values[displacement].divergence(j, q_index);
190 
191  const auto sigma_vis =
192  2 * c["eta"] * eps_u + c["kappa"] * div_u * identity;
193 
194  cell_matrix(i, j) +=
195  (scalar_product(sigma_vis, eps_v) *
196  mapped_fe_values.JxW(q_index) + // dx
197  scalar_product(P_el, eps_V) *
198  fe_values.JxW(q_index)); // dX
199  }
200 
201  const auto Pn = 2 * c["mu"] * eps_Wn[q_index] +
202  c["lambda"] * div_Wn[q_index] * identity;
203 
204  cell_rhs(i) +=
205  (-scalar_product(Pn, eps_V) * fe_values.JxW(q_index) + // dX
206  mapped_fe_values.shape_value(i, q_index) * // phi_i(x_q)
207  this->forcing_term.value(x,
208  this->finite_element()
209  .system_to_component_index(i)
210  .first) * // f(x_q)
211  fe_values.JxW(q_index)); // dx
212  }
213  this->constraints.distribute_local_to_global(
214  cell_matrix,
215  cell_rhs,
216  copy.local_dof_indices[0],
217  this->matrix,
218  this->rhs);
219  }
220  this->matrix.compress(VectorOperation::add);
221  this->rhs.compress(VectorOperation::add);
222  }
223 
224 
225 
226  template <int dim, int spacedim, class LacType>
227  void
229  {
230  TimerOutput::Scope timer_section(this->timer, "solve");
231  const auto A = linear_operator<VectorType>(this->matrix.block(0, 0));
232  this->preconditioner.initialize(this->matrix.block(0, 0));
233  const auto Ainv = this->inverse_operator(A, this->preconditioner);
234  this->solution.block(0) = Ainv * this->rhs.block(0);
235  this->constraints.distribute(this->solution);
236  this->locally_relevant_solution = this->solution;
237  current_displacement.sadd(1.0, dt, this->solution);
238  current_displacement_locally_relevant = current_displacement;
239  }
240 
241 
242 
243  template <int dim, int spacedim, class LacType>
244  void
246  {
247  TimerOutput::Scope timer_section(this->timer, "post_process");
248  Quadrature<dim> quadrature_formula =
250  this->triangulation, this->finite_element().tensor_degree() + 1);
251 
252  ScratchData scratch(this->finite_element(),
253  quadrature_formula,
255 
256  ScratchData mapped_scratch(eulerian_mapping(),
257  this->finite_element(),
258  quadrature_formula,
261 
262  static std::ofstream outfile("visco_elastic_energies.txt");
263  if (current_cycle == 0)
264  outfile
265  << "# t \t E_pot[0] \t E_pot[1] \t Diss[0] \t Diss[1] \t Ext[0] \t Ext[1]"
266  << std::endl;
267 
268  // One per material
269  std::vector<double> potential_energy(2, 0.0);
270  std::vector<double> dissipation(2, 0.0);
271  std::vector<double> external_energy(2, 0.0);
272 
273  for (const auto &cell : this->dof_handler.active_cell_iterators())
274  if (cell->is_locally_owned())
275  {
276  const auto &fe_values = scratch.reinit(cell);
277  const auto &mapped_fe_values = mapped_scratch.reinit(cell);
278 
279  scratch.extract_local_dof_values(
280  "Wn", this->current_displacement_locally_relevant);
281  mapped_scratch.extract_local_dof_values(
282  "Un", this->locally_relevant_solution);
283 
284  const auto &div_Wn = scratch.get_divergences("Wn", displacement);
285  const auto &eps_Wn =
286  scratch.get_symmetric_gradients("Wn", displacement);
287 
288 
289  const auto &un = mapped_scratch.get_values("Un", displacement);
290  const auto &div_un =
291  mapped_scratch.get_divergences("Un", displacement);
292  const auto &eps_un =
293  mapped_scratch.get_symmetric_gradients("Un", displacement);
294 
295  const auto id =
296  material_ids_0.find(cell->material_id()) != material_ids_0.end() ?
297  0 :
298  1;
299 
300  const ParsedTools::Constants &c =
301  (id == 0 ? constants_0 : constants_1);
302 
303  for (const unsigned int q_index :
304  fe_values.quadrature_point_indices())
305  {
306  potential_energy[id] +=
307  c["mu"] * scalar_product(eps_Wn[q_index], eps_Wn[q_index]) +
308  0.5 * c["lambda"] * div_Wn[q_index] * div_Wn[q_index] *
309  fe_values.JxW(q_index);
310 
311  dissipation[id] +=
312  c["eta"] * scalar_product(eps_un[q_index], eps_un[q_index]) +
313  0.5 * c["kappa"] * div_un[q_index] * div_un[q_index] *
314  mapped_fe_values.JxW(q_index);
315 
316  for (unsigned int i = 0; i < spacedim; ++i)
317  external_energy[id] +=
318  un[q_index][i] *
319  this->forcing_term.value(
320  mapped_fe_values.quadrature_point(q_index), i) *
321  mapped_fe_values.JxW(q_index);
322  }
323  }
324 
325  // Sum over all processors
327  this->mpi_communicator,
328  ArrayView<double>(potential_energy));
330  this->mpi_communicator,
331  ArrayView<double>(dissipation));
333  this->mpi_communicator,
334  ArrayView<double>(external_energy));
335 
336  outfile << current_time << " \t " << potential_energy[0] << " \t "
337  << potential_energy[1] << " \t " << dissipation[0] << " \t "
338  << dissipation[1] << " \t "
339  << external_energy[0] + external_energy[1] << std::endl;
340  }
341 
342 
343 
347 
351 } // namespace PDEs
Construct a LinearProblem.
typename LinearProblem< dim, spacedim, LacType >::CopyData CopyData
typename LinearProblem< dim, spacedim, LacType >::ScratchData ScratchData
virtual void solve() override
Make sure we initialize the right type of linear solver.
void postprocess()
Compute energy integrals.
virtual void assemble_system() override
Explicitly assemble the LinearViscoElasticity problem.
A wrapper for physical constants to be shared among functions and classes.
Definition: constants.h:44
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)
update_values
update_JxW_values
update_gradients
update_quadrature_points
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
T sum(const T &t, const MPI_Comm mpi_communicator)
PDEs::LinearViscoElasticity< dim, spacedim, LAC::LATrilinos > LinearViscoElasticity
We collect in this namespace all PDEs that are relevant to Fluid Structure Interaction Problems.
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