Fluid structure interaction suite
distributed_lagrange.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 
17 
18 #include <deal.II/base/logstream.h>
19 
21 
24 
25 #include <fstream>
26 #include <iostream>
27 
28 #include "lac_initializer.h"
29 
30 using namespace dealii;
31 
32 namespace PDEs
33 {
34  template <int dim, int spacedim, typename LacType>
36  : ParameterAcceptor("Distributed Lagrange")
37  , space("u", "Space")
38  , space_cache(space.triangulation)
39  , embedded("w", "Embedded")
40  , embedded_cache(embedded.triangulation)
41  , coupling("/Coupling")
42  , mass_solver("/Mass solver")
43  {}
44 
45 
46 
47  template <int dim, int spacedim, typename LacType>
48  void
50  {
51  TimerOutput::Scope timer_section(space.timer, "generate_grids_and_fes");
52  space.grid_generator.generate(space.triangulation);
53  embedded.grid_generator.generate(embedded.triangulation);
54  coupling.initialize(space_cache,
55  space.dof_handler,
56  space.constraints,
57  embedded_cache,
58  embedded.dof_handler,
59  embedded.constraints);
60  coupling.adjust_grid_refinements(space.triangulation,
61  embedded.triangulation,
62  true);
63  }
64 
65 
66 
67  template <int dim, int spacedim, typename LacType>
68  void
70  {
71  space.setup_system();
72  embedded.setup_system();
73 
74  const auto row_indices = space.dof_handler.locally_owned_dofs();
75  const auto col_indices = embedded.dof_handler.locally_owned_dofs();
76 
77  LAC::Initializer init(row_indices,
78  IndexSet(),
79  space.mpi_communicator,
80  col_indices);
81 
82  DynamicSparsityPattern dsp(space.dof_handler.n_dofs(),
83  embedded.dof_handler.n_dofs(),
84  row_indices);
85 
86  coupling.assemble_sparsity(dsp);
87 
89  row_indices,
90  space.mpi_communicator,
91  space.locally_relevant_dofs[0]);
92 
93  coupling_matrix.reinit(row_indices,
94  col_indices,
95  dsp,
96  space.mpi_communicator);
97  }
98 
99 
100 
101  template <int dim, int spacedim, typename LacType>
102  void
104  {
105  {
106  TimerOutput::Scope timer_section(space.timer,
107  "Assemble stiffness system");
108  // Stiffness matrix and rhs
110  *space.mapping,
111  space.finite_element(),
112  space.cell_quadrature,
115 
117  space.finite_element().n_dofs_per_cell());
118 
119  for (const auto &cell : space.dof_handler.active_cell_iterators())
120  if (cell->is_locally_owned())
121  {
122  auto &cell_matrix = copy.matrices[0];
123  auto &cell_rhs = copy.vectors[0];
124  cell_matrix = 0;
125  cell_rhs = 0;
126  const auto &fe_values = scratch.reinit(cell);
127  cell->get_dof_indices(copy.local_dof_indices[0]);
128 
129  for (const unsigned int q_index :
130  fe_values.quadrature_point_indices())
131  {
132  for (const unsigned int i : fe_values.dof_indices())
133  {
134  for (const unsigned int j : fe_values.dof_indices())
135  cell_matrix(i, j) +=
136  (fe_values.shape_grad(i, q_index) * // grad phi_i(x_q)
137  fe_values.shape_grad(j, q_index) * // grad phi_j(x_q)
138  fe_values.JxW(q_index)); // dx
139  cell_rhs(i) +=
140  (fe_values.shape_value(i, q_index) * // phi_i(x_q)
141  space.forcing_term.value(
142  fe_values.quadrature_point(q_index)) * // f(x_q)
143  fe_values.JxW(q_index)); // dx
144  }
145  }
146 
147  space.constraints.distribute_local_to_global(
148  copy.matrices[0],
149  copy.vectors[0],
150  copy.local_dof_indices[0],
151  space.matrix,
152  space.rhs);
153  }
154 
155  space.matrix.compress(VectorOperation::add);
156  space.rhs.compress(VectorOperation::add);
157  }
158  {
159  TimerOutput::Scope timer_section(space.timer, "Assemble coupling system");
160  coupling_matrix = 0.0;
161  coupling.assemble_matrix(coupling_matrix);
162  coupling_matrix.compress(VectorOperation::add);
163  }
164  {
165  // Embedded mass matrix and rhs
167  *embedded.mapping,
168  embedded.finite_element(),
169  embedded.cell_quadrature,
172 
174  embedded.finite_element().n_dofs_per_cell());
175 
176  for (const auto &cell : embedded.dof_handler.active_cell_iterators())
177  if (cell->is_locally_owned())
178  {
179  auto &cell_matrix = copy.matrices[0];
180  auto &cell_rhs = copy.vectors[0];
181  cell_matrix = 0;
182  cell_rhs = 0;
183  const auto &fe_values = scratch.reinit(cell);
184  cell->get_dof_indices(copy.local_dof_indices[0]);
185 
186  for (const unsigned int q_index :
187  fe_values.quadrature_point_indices())
188  {
189  for (const unsigned int i : fe_values.dof_indices())
190  {
191  for (const unsigned int j : fe_values.dof_indices())
192  cell_matrix(i, j) +=
193  (fe_values.shape_value(i, q_index) * // phi_i(x_q)
194  fe_values.shape_value(j, q_index) * // phi_j(x_q)
195  fe_values.JxW(q_index)); // dx
196  cell_rhs(i) +=
197  (fe_values.shape_value(i, q_index) * // phi_i(x_q)
198  embedded.forcing_term.value(
199  fe_values.quadrature_point(q_index)) * // f(x_q)
200  fe_values.JxW(q_index)); // dx
201  }
202  }
203 
204  embedded.constraints.distribute_local_to_global(
205  copy.matrices[0],
206  copy.vectors[0],
207  copy.local_dof_indices[0],
208  embedded.matrix,
209  embedded.rhs);
210  }
211 
212  embedded.matrix.compress(VectorOperation::add);
213  embedded.rhs.compress(VectorOperation::add);
214  // The rhs of the Lagrange multiplier as a function to plot
215  VectorTools::interpolate(embedded.dof_handler,
216  embedded.forcing_term,
217  embedded.solution);
218  embedded.solution.compress(VectorOperation::insert);
219  }
220  }
221 
222 
223 
224  template <int dim, int spacedim, typename LacType>
225  void
227  {
228  TimerOutput::Scope timer_section(space.timer, "Solve system");
229 
230  using BVec = typename LacType::BlockVector;
231  using Vec = typename BVec::BlockType;
232  using LinOp = LinearOperator<Vec>;
233  using BlockLinOp = BlockLinearOperator<BVec>;
234 
235  auto A = linear_operator<Vec>(space.matrix.block(0, 0));
236  auto Bt = linear_operator<Vec>(coupling_matrix);
237  auto B = transpose_operator(Bt);
238  auto A_inv = A;
239  auto M = linear_operator<Vec>(embedded.matrix.block(0, 0));
240  auto M_inv = M;
241 
242  space.preconditioner.initialize(space.matrix.block(0, 0));
243  A_inv = space.inverse_operator(A, space.preconditioner);
244 
245  embedded.preconditioner.initialize(embedded.matrix.block(0, 0));
246  auto M_prec = linear_operator<Vec>(M, embedded.preconditioner);
247  M_inv = mass_solver(M, M_prec);
248 
249  auto &lambda = embedded.solution.block(0);
250  auto &embedded_rhs = embedded.rhs.block(0);
251  auto &solution = space.solution.block(0);
252  auto &rhs = space.rhs.block(0);
253 
254  auto S = B * A_inv * Bt;
255  auto S_prec = identity_operator(S);
256  auto S_inv = embedded.inverse_operator(S, M_inv);
257 
258  lambda = S_inv * (B * A_inv * rhs - embedded_rhs);
259  solution = A_inv * (rhs - Bt * lambda);
260 
261  // Distribute all constraints.
262  embedded.constraints.distribute(lambda);
263  embedded.locally_relevant_solution = embedded.solution;
264  space.constraints.distribute(solution);
265  space.locally_relevant_solution = space.solution;
266  }
267 
268 
269 
270  template <int dim, int spacedim, typename LacType>
271  void
273  const unsigned int cycle)
274  {
275  space.output_results(cycle);
276  embedded.output_results(cycle);
277  }
278 
279 
280 
281  template <int dim, int spacedim, typename LacType>
282  void
284  {
285  deallog.depth_console(space.verbosity_level);
286  generate_grids();
287  for (const auto &cycle : space.grid_refinement.get_refinement_cycles())
288  {
289  deallog.push("Cycle " + Utilities::int_to_string(cycle));
290  setup_system();
291  assemble_system();
292  solve();
293  space.estimate(space.error_per_cell);
294  embedded.estimate(embedded.error_per_cell);
295  output_results(cycle);
296  if (cycle < space.grid_refinement.get_n_refinement_cycles() - 1)
297  {
298  space.mark(space.error_per_cell);
299  space.refine();
300  embedded.triangulation.refine_global(1);
301  coupling.adjust_grid_refinements(space.triangulation,
302  embedded.triangulation,
303  false);
304  }
305  deallog.pop();
306  }
307  if (space.mpi_rank == 0)
308  {
309  space.error_table.output_table(std::cout);
310  embedded.error_table.output_table(std::cout);
311  }
312  }
313 
314  // template class DistributedLagrange<1, 2>;
315  // template class DistributedLagrange<2, 2>;
316  // template class DistributedLagrange<2, 3>;
317  // template class DistributedLagrange<3, 3>;
318 
323 
328 } // namespace PDEs
void push(const std::string &text)
unsigned int depth_console(const unsigned int n)
void pop()
const FEValues< dim, spacedim > & reinit(const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell)
General class, used to initialize different types of block vectors, block atrices and block sparsity ...
void output_results(const unsigned int cycle)
LinearOperator< Range, Range, Payload > identity_operator(const std::function< void(Range &, bool)> &reinit_vector)
LinearOperator< Domain, Range, Payload > transpose_operator(const LinearOperator< Range, Domain, Payload > &op)
update_values
update_JxW_values
update_gradients
update_quadrature_points
LogStream deallog
void distribute_sparsity_pattern(DynamicSparsityPattern &dsp, const IndexSet &locally_owned_rows, const MPI_Comm mpi_comm, const IndexSet &locally_relevant_rows)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
void interpolate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const ComponentMask &component_mask={})
PDEs::DistributedLagrange< dim, spacedim, LAC::LATrilinos > DistributedLagrange
We collect in this namespace all PDEs that are relevant to Fluid Structure Interaction Problems.
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation