pi-DoMUS: Parallel Deal.II MUltiphysics Solver
navier_stokes.h
Go to the documentation of this file.
1 
71 #ifndef _pidomus_navier_stokes_h_
72 #define _pidomus_navier_stokes_h_
73 
74 #include "pde_system_interface.h"
75 
79 #include <deal.II/lac/solver_cg.h>
81 
82 template <int dim, int spacedim=dim, typename LAC=LATrilinos>
84  :
85  public PDESystemInterface<dim,spacedim,NavierStokes<dim,spacedim,LAC>, LAC>
86 {
87 
88 public:
90  NavierStokes (bool dynamic, bool convection);
91 
94 
95  template <typename EnergyType, typename ResidualType>
96  void
99  FEValuesCache<dim,spacedim> &scratch,
100  std::vector<EnergyType> &energies,
101  std::vector<std::vector<ResidualType>> &residuals,
102  bool compute_only_system_terms) const;
103 
104  void
106  const DoFHandler<dim,spacedim> &,
107  const std::vector<shared_ptr<LATrilinos::BlockMatrix>>,
110 
111  void
112  set_matrix_couplings(std::vector<std::string> &couplings) const;
113 
114 private:
118  bool dynamic;
119 
124  bool convection;
125 
129  std::string non_linear_term;
130 
134  bool linearize_in_time;
135 
139  std::string prec_name;
140 
144  double rho;
145 
149  double nu;
150 
154  double gamma;
155 
159  double gamma_p;
160 
164  bool compute_Mp;
165 
169  bool compute_Ap;
170 
174  bool invert_Mp;
175 
179  bool invert_Ap;
180 
184  double CG_solver_tolerance;
185 
189  double GMRES_solver_tolerance;
190 
194  int amg_smoother_sweeps;
195 
199  double amg_aggregation_threshold;
200 
204  bool amg_elliptic;
205 
209  bool amg_higher_order_elements;
210 
214  int amg_p_smoother_sweeps;
215 
219  double amg_p_aggregation_threshold;
220 
224  bool amg_p_elliptic;
225 
226  mutable shared_ptr<TrilinosWrappers::PreconditionAMG>
227  Amg_preconditioner;
228  mutable shared_ptr<TrilinosWrappers::PreconditionAMG>
229  Amg_preconditioner_2;
230  mutable shared_ptr<TrilinosWrappers::PreconditionJacobi>
231  jacobi_preconditioner;
232 };
233 
234 template <int dim, int spacedim, typename LAC>
236 NavierStokes(bool dynamic, bool convection)
237  :
238  PDESystemInterface<dim,spacedim,NavierStokes<dim,spacedim,LAC>, LAC>(
239  "Navier Stokes Interface",
240  dim+1,
241  3,
242  "FESystem[FE_Q(2)^d-FE_Q(1)]",
243  "u,u,p",
244  "1,0"),
245  dynamic(dynamic),
246  convection(convection),
247  compute_Mp(false),
248  compute_Ap(false)
249 {
250  this->init();
251 }
252 
253 template <int dim, int spacedim, typename LAC>
256 {
258  declare_parameters(prm);
259  this->add_parameter(prm, &prec_name, "Preconditioner","default",
260  Patterns::Selection("default|identity|low-nu|cah-cha"),
261  "Available preconditioners: \n"
262  " - default -> S^-1 = nu * Mp^-1 \n"
263  " - identity -> S^-1 = identity \n"
264  " - low-nu -> S^-1 = rho * alpha * Ap^-1 \n"
265  " - cah-cha -> S^-1 = nu * Mp^-1 + rho * alpha * Ap^-1 ");
266  this->add_parameter(prm, &dynamic,
267  "Enable dynamic term (\\partial_t u)", "true",
268  Patterns::Bool(),
269  "Enable the dynamic term of the equation.");
270  this->add_parameter(prm, &convection,
271  "Enable convection term ((\\nabla u)u)", "true",
272  Patterns::Bool(),
273  "Enable the convection term of the equation. Set it false if you want to solve Stokes Equation.");
274  this->add_parameter(prm, &non_linear_term, "Non linear term","grad_linear",
275  Patterns::Selection("fully_non_linear|grad_linear|u_linear|RHS"),
276  "Available options: \n"
277  " fully_non_linear\n"
278  "grad_linear\n"
279  "u_linear\n"
280  "RHS\n");
281  this->add_parameter(prm, &linearize_in_time,
282  "Linearize using time", "true",
283  Patterns::Bool(),
284  "If true use the solution of the previous time step\n"
285  "to linearize the non-linear term, otherwise use the\n" "solution of the previous step (of an iterative methos).");
286  this->add_parameter(prm, &gamma,
287  "div-grad stabilization parameter", "0.0",
288  Patterns::Double(0.0),
289  "");
290  this->add_parameter(prm, &gamma_p,
291  "p-q stabilization parameter", "0.0",
292  Patterns::Double(0.0),
293  "");
294  this->add_parameter(prm, &rho,
295  "rho [kg m^3]", "1.0",
296  Patterns::Double(0.0),
297  "Density");
298  this->add_parameter(prm, &nu,
299  "nu [Pa s]", "1.0",
300  Patterns::Double(0.0),
301  "Viscosity");
302  this->add_parameter(prm, &invert_Ap,
303  "Invert Ap using inverse_operator", "true", Patterns::Bool());
304  this->add_parameter(prm, &invert_Mp,
305  "Invert Mp using inverse_operator", "true", Patterns::Bool());
306  this->add_parameter(prm, &CG_solver_tolerance,
307  "CG Solver tolerance", "1e-8",
308  Patterns::Double(0.0));
309  this->add_parameter(prm, &GMRES_solver_tolerance,
310  "GMRES Solver tolerance", "1e-8",
311  Patterns::Double(0.0));
312  this->add_parameter(prm, &amg_smoother_sweeps,
313  "Amg Smoother Sweeps","2", Patterns::Integer(0));
314  this->add_parameter(prm, &amg_aggregation_threshold,
315  "Amg Aggregation Threshold", "0.02", Patterns::Double(0.0));
316  this->add_parameter(prm, &amg_elliptic,
317  "Amg Elliptic", "true", Patterns::Bool());
318  this->add_parameter(prm, &amg_higher_order_elements,
319  "Amg High Order Elements", "true", Patterns::Bool());
320  this->add_parameter(prm, &amg_p_smoother_sweeps,
321  "Amg P Smoother Sweeps","2", Patterns::Integer(0));
322  this->add_parameter(prm, &amg_p_aggregation_threshold,
323  "Amg P Aggregation Threshold", "0.02", Patterns::Double(0.0));
324  this->add_parameter(prm, &amg_p_elliptic,
325  "Amg P Elliptic", "true", Patterns::Bool());
326 }
327 
328 template <int dim, int spacedim, typename LAC>
331 {
332  if (prec_name == "default")
333  compute_Mp = true;
334  else if (prec_name == "low-nu")
335  compute_Ap = true;
336  else if (prec_name == "cah-cha")
337  {
338  compute_Mp = true;
339  compute_Ap = true;
340  }
341 
342  // p-q stabilization term:
343  if (gamma_p!=0.0)
344  compute_Mp = true;
345 }
346 
347 template <int dim, int spacedim, typename LAC>
349 set_matrix_couplings(std::vector<std::string> &couplings) const
350 {
351  couplings[0] = "1,1;1,0";
352  couplings[1] = "0,0;0,1";
353  couplings[2] = "0,0;0,1";
354 };
355 
356 template <int dim, int spacedim, typename LAC>
357 template <typename EnergyType, typename ResidualType>
358 void
361  FEValuesCache<dim,spacedim> &fe_cache,
362  std::vector<EnergyType> &,
363  std::vector<std::vector<ResidualType> > &residual,
364  bool compute_only_system_terms) const
365 {
366  const FEValuesExtractors::Vector velocity(0);
367  const FEValuesExtractors::Scalar pressure(dim);
368 
369  ResidualType et = this->alpha;
370  double dummy = 0.0;
371  // dummy number to define the type of variables
372  this->reinit (et, cell, fe_cache);
373 
374  // Velocity:
375  auto &us = fe_cache.get_values("solution", "u", velocity, et);
376  auto &div_us = fe_cache.get_divergences("solution", "div_u", velocity,et);
377  auto &grad_us = fe_cache.get_gradients("solution", "grad_u", velocity,et);
378  auto &sym_grad_us = fe_cache.get_symmetric_gradients("solution", "sym_grad_u", velocity,et);
379  auto &us_dot = fe_cache.get_values("solution_dot", "u_dot", velocity, et);
380 
381  auto &u_olds = fe_cache.get_values("explicit_solution", "u", velocity, dummy);
382  auto &grad_u_olds = fe_cache.get_gradients("explicit_solution", "grad_u", velocity, dummy);
383 
384  fe_cache.cache_local_solution_vector("prev_solution", *this->solution, dummy);
385  auto &u_prevs = fe_cache.get_values("prev_solution", "u", velocity, dummy);
386  auto &grad_u_prevs = fe_cache.get_gradients("prev_solution", "grad_u", velocity, dummy);
387 
388  // Pressure:
389  auto &ps = fe_cache.get_values("solution", "p", pressure, et);
390  auto &ps_dot = fe_cache.get_values("solution_dot", "p_dot", pressure, et);
391  auto &grad_ps = fe_cache.get_gradients("solution", "grad_p", pressure, et);
392 
393  const unsigned int n_quad_points = us.size();
394  auto &JxW = fe_cache.get_JxW_values();
395 
396  auto &fev = fe_cache.get_current_fe_values();
397 
398  for (unsigned int quad=0; quad<n_quad_points; ++quad)
399  {
400  const ResidualType &p = ps[quad];
401  const ResidualType &p_dot = ps_dot[quad];
402  const Tensor<1, dim, ResidualType> &grad_p = grad_ps[quad];
403  const Tensor<1, dim, ResidualType> &u = us[quad];
404  const Tensor<1, dim, ResidualType> &u_dot = us_dot[quad];
405  const Tensor<2, dim, ResidualType> &grad_u = grad_us[quad];
406  const Tensor<2, dim, ResidualType> &sym_grad_u = sym_grad_us[quad];
407  const ResidualType &div_u = div_us[quad];
408 
409  const Tensor<1, dim, ResidualType> &u_old = u_olds[quad];
410  const Tensor<2, dim, ResidualType> &grad_u_old = grad_u_olds[quad];
411 
412  const Tensor<1, dim, ResidualType> &u_prev = u_prevs[quad];
413  const Tensor<2, dim, ResidualType> &grad_u_prev = grad_u_prevs[quad];
414 
415  for (unsigned int i=0; i<residual[0].size(); ++i)
416  {
417  // Velocity:
418  auto v = fev[velocity ].value(i,quad);
419  auto div_v = fev[velocity ].divergence(i,quad);
420  auto grad_v = fev[ velocity ].gradient(i,quad);
421  auto sym_grad_v = fev[ velocity ].symmetric_gradient(i,quad);
422 
423  // Pressure:
424  auto q = fev[ pressure ].value(i,quad);
425  auto grad_q = fev[ pressure ].gradient(i,quad);
426 
427  // Non-linear term:
429  ResidualType res = 0.0;
430 
431  // Time derivative:
432  if (dynamic)
433  res += rho * u_dot * v;
434 
435  // Convection:
436  if (convection)
437  {
440 
441  if (linearize_in_time)
442  {
443  gradoldu=grad_u_old;
444  oldu=u_old;
445  }
446  else
447  {
448  gradoldu=grad_u_prev;
449  oldu=u_prev;
450  }
451 
452  if (non_linear_term=="fully_non_linear")
453  Np_term = grad_u * u;
454  else if (non_linear_term=="grad_linear")
455  Np_term = gradoldu * u;
456  else if (non_linear_term=="u_linear")
457  Np_term = grad_u * oldu;
458  else if (non_linear_term=="RHS")
459  Np_term = gradoldu * oldu;
460 
461  res += rho * scalar_product(Np_term,v);
462  }
463  // grad-div stabilization term:
464  if (gamma!=0.0)
465  res += gamma * div_u * div_v;
466 
467  // Diffusion term:
468  res += nu * scalar_product(sym_grad_u, sym_grad_v);
469 
470  // Pressure term:
471  res -= p * div_v;
472 
473  // Incompressible constraint:
474  res -= div_u * q;
475 
476  residual[0][i] += res * JxW[q];
477 
478  // Mp preconditioner:
479  if (!compute_only_system_terms && compute_Mp)
480  residual[1][i] += p * q * JxW[q];
481 
482  // Ap preconditioner:
483  if (!compute_only_system_terms && compute_Ap)
484  residual[2][i] += grad_p * grad_q * JxW[q];
485  }
486  }
487  (void)compute_only_system_terms;
488 }
489 
490 
491 template <int dim, int spacedim, typename LAC>
492 void
494  const DoFHandler<dim,spacedim> &dh,
495  const std::vector<shared_ptr<LATrilinos::BlockMatrix>> matrices,
498 {
499  auto aplha = this->alpha;
500 
501  typedef LATrilinos::VectorType::BlockType BVEC;
502  typedef LATrilinos::VectorType VEC;
503 
504  static ReductionControl solver_control_cg(matrices[0]->m(), CG_solver_tolerance);
505  static SolverCG<BVEC> solver_CG(solver_control_cg);
506 
507  static ReductionControl solver_control_gmres(matrices[0]->m(), GMRES_solver_tolerance);
508  static SolverGMRES<BVEC> solver_GMRES(solver_control_gmres);
509 
510 
511  // SYSTEM MATRIX:
512  auto A = linear_operator<BVEC>( matrices[0]->block(0,0) );
513  auto Bt = linear_operator<BVEC>( matrices[0]->block(0,1) );
514  auto B = linear_operator<BVEC>( matrices[0]->block(1,0) );
515  auto C = linear_operator<BVEC>( matrices[0]->block(1,1) );
516  auto ZeroP = null_operator(C);
517 
518  if (gamma_p!=0.0)
519  C = linear_operator<BVEC>( matrices[1]->block(1,1) );
520  else
521  C = ZeroP;
522 
523  // ASSEMBLE THE PROBLEM:
524  system_op = block_operator<2, 2, VEC>({{
525  {{ A, Bt }} ,
526  {{ B, C }}
527  }
528  });
529 
530  std::vector<std::vector<bool>> constant_modes;
531  FEValuesExtractors::Vector velocity_components(0);
532  DoFTools::extract_constant_modes (dh, dh.get_fe().component_mask(velocity_components),
533  constant_modes);
535  Amg_data.constant_modes = constant_modes;
536  Amg_data.elliptic = amg_elliptic;
537  Amg_data.higher_order_elements = amg_higher_order_elements;
538  Amg_data.smoother_sweeps = amg_smoother_sweeps;
539  Amg_data.aggregation_threshold = amg_aggregation_threshold;
540 
541  std::vector<std::vector<bool> > constant_modes_p;
542  FEValuesExtractors::Scalar pressure_components(dim);
543  DoFTools::extract_constant_modes (dh, dh.get_fe().component_mask(pressure_components),
544  constant_modes_p);
546  Amg_data_p.constant_modes = constant_modes_p;
547  Amg_data_p.elliptic = amg_p_elliptic;
548  Amg_data_p.smoother_sweeps = amg_p_smoother_sweeps;
549  Amg_data_p.aggregation_threshold = amg_p_aggregation_threshold;
550 
551 
552  Amg_preconditioner.reset (new TrilinosWrappers::PreconditionAMG());
553  Amg_preconditioner->initialize (matrices[0]->block(0,0), Amg_data);
554  auto A_inv = inverse_operator( A, solver_GMRES, *Amg_preconditioner);
555 
556  LinearOperator<BVEC> Schur_inv;
557  LinearOperator<BVEC> Ap, Ap_inv, Mp, Mp_inv;
558 
559  if (compute_Mp)
560  {
561  Mp = linear_operator<BVEC>( matrices[1]->block(1,1) );
562  jacobi_preconditioner.reset (new TrilinosWrappers::PreconditionJacobi());
563  jacobi_preconditioner->initialize (matrices[1]->block(1,1), 1.4);
564  Mp_inv = inverse_operator( Mp, solver_CG, *jacobi_preconditioner);
565  }
566  if (compute_Ap)
567  {
568  Mp = linear_operator<BVEC>( matrices[2]->block(1,1) );
569  Amg_preconditioner_2.reset (new TrilinosWrappers::PreconditionAMG());
570  Amg_preconditioner_2->initialize (matrices[2]->block(1,1), Amg_data_p);
571  if (invert_Ap)
572  {
573  Ap_inv = inverse_operator( Ap, solver_CG, *Amg_preconditioner_2);
574  }
575  else
576  {
577  Ap_inv = linear_operator<BVEC>(matrices[2]->block(1,1), *Amg_preconditioner_2);
578  }
579  }
580 
581  LinearOperator<BVEC> P00,P01,P10,P11;
582 
583 
584  if (prec_name=="default")
585  Schur_inv = (gamma + nu) * Mp_inv;
586  else if (prec_name=="low-nu")
587  Schur_inv = aplha * rho * Ap_inv;
588  else if (prec_name=="identity")
589  Schur_inv = identity_operator((C).reinit_range_vector);
590  else if (prec_name=="cha-cha")
591  Schur_inv = (gamma + nu) * Mp_inv + aplha * rho * Ap_inv;
592 
593  P00 = A_inv;
594  P01 = A_inv * Bt * Schur_inv;
595  P10 = null_operator(B);
596  P11 = -1 * Schur_inv;
597 
598  prec_op = block_operator<2, 2, VEC>({{
599  {{ P00, P01 }} ,
600  {{ P10, P11 }}
601  }
602  });
603 }
604 
605 // template class NavierStokes <2,2, LADealII>;
606 // template class NavierStokes <2,2, LATrilinos>;
607 // template class NavierStokes <3,3, LADealII>;
608 // template class NavierStokes <3,3, LATrilinos>;
609 
610 #endif
611 
Definition: lac_type.h:33
void declare_parameters(ParameterHandler &prm)
Definition: navier_stokes.h:255
std::vector< std::vector< bool > > constant_modes
This interface solves a Navier Stokes Equation: where .
Definition: navier_stokes.h:83
ActiveSelector::active_cell_iterator active_cell_iterator
void set_matrix_couplings(std::vector< std::string > &couplings) const
Definition: navier_stokes.h:349
This is the class that users should derive from.
Definition: pde_system_interface.h:46
void compute_system_operators(const DoFHandler< dim, spacedim > &, const std::vector< shared_ptr< LATrilinos::BlockMatrix >>, LinearOperator< LATrilinos::VectorType > &, LinearOperator< LATrilinos::VectorType > &) const
Definition: navier_stokes.h:493
LinearOperator< Range, Domain > null_operator(const LinearOperator< Range, Domain > &op)
void parse_parameters_call_back()
Definition: navier_stokes.h:330
LinearOperator< typename Solver::vector_type, typename Solver::vector_type > inverse_operator(const LinearOperator< typename Solver::vector_type, typename Solver::vector_type > &op, Solver &solver, const Preconditioner &preconditioner)
LinearOperator< Range, Range > identity_operator(const std::function< void(Range &, bool)> &reinit_vector)
VectorType
~NavierStokes()
Definition: navier_stokes.h:89
void energies_and_residuals(const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, FEValuesCache< dim, spacedim > &scratch, std::vector< EnergyType > &energies, std::vector< std::vector< ResidualType >> &residuals, bool compute_only_system_terms) const
void extract_constant_modes(const DoFHandlerType &dof_handler, const ComponentMask &component_mask, std::vector< std::vector< bool > > &constant_modes)
NavierStokes(bool dynamic, bool convection)
Definition: navier_stokes.h:236
const FiniteElement< dim, spacedim > & get_fe() const