|
| 1 | +/*! \addtogroup equations |
| 2 | + * @{ |
| 3 | + */ |
| 4 | + |
| 5 | +/** |
| 6 | + * Navier Stokes Equation using Chorin-Temam projection method |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef _pidomus_navier_stokes_h_ |
| 10 | +#define _pidomus_navier_stokes_h_ |
| 11 | + |
| 12 | +#include "pde_system_interface.h" |
| 13 | + |
| 14 | +#include <deal.II/grid/filtered_iterator.h> |
| 15 | + |
| 16 | +#include <deal.II/base/work_stream.h> |
| 17 | + |
| 18 | +#include <deal.II/lac/solver_cg.h> |
| 19 | +#include <deal.II/lac/solver_gmres.h> |
| 20 | + |
| 21 | +#include <deal2lkit/sacado_tools.h> |
| 22 | +#include <deal2lkit/parsed_preconditioner/amg.h> |
| 23 | +#include <deal2lkit/parsed_preconditioner/jacobi.h> |
| 24 | + |
| 25 | +//////////////////////////////////////////////////////////////////////////////// |
| 26 | +/// Navier Stokes interface: |
| 27 | + |
| 28 | +template <int dim, int spacedim=dim, typename LAC=LATrilinos> |
| 29 | +class NavierStokes |
| 30 | + : |
| 31 | + public PDESystemInterface<dim,spacedim,NavierStokes<dim,spacedim,LAC>, LAC> |
| 32 | +{ |
| 33 | + |
| 34 | +public: |
| 35 | + ~NavierStokes () {}; |
| 36 | + NavierStokes (); |
| 37 | + |
| 38 | + void declare_parameters (ParameterHandler &prm); |
| 39 | + |
| 40 | + template <typename EnergyType, typename ResidualType> |
| 41 | + void |
| 42 | + energies_and_residuals( |
| 43 | + const typename DoFHandler<dim,spacedim>::active_cell_iterator &cell, |
| 44 | + FEValuesCache<dim,spacedim> &scratch, |
| 45 | + std::vector<EnergyType> &energies, |
| 46 | + std::vector<std::vector<ResidualType>> &residuals, |
| 47 | + bool compute_only_system_terms) const; |
| 48 | + |
| 49 | + void |
| 50 | + compute_system_operators( |
| 51 | + const std::vector<shared_ptr<LATrilinos::BlockMatrix>>, |
| 52 | + LinearOperator<LATrilinos::VectorType> &, |
| 53 | + LinearOperator<LATrilinos::VectorType> &, |
| 54 | + LinearOperator<LATrilinos::VectorType> &) const; |
| 55 | + |
| 56 | + void |
| 57 | + set_matrix_couplings(std::vector<std::string> &couplings) const; |
| 58 | + |
| 59 | +private: |
| 60 | + |
| 61 | + /** |
| 62 | + * AMG preconditioner for velocity-velocity matrix. |
| 63 | + */ |
| 64 | + mutable ParsedJacobiPreconditioner AMG_u; |
| 65 | + |
| 66 | + /** |
| 67 | + * AMG preconditioner for velocity-velocity matrix. |
| 68 | + */ |
| 69 | + mutable ParsedJacobiPreconditioner AMG_v; |
| 70 | + |
| 71 | + /** |
| 72 | + * AMG preconditioner for velocity-velocity matrix. |
| 73 | + */ |
| 74 | + mutable ParsedAMGPreconditioner AMG_p; |
| 75 | + |
| 76 | + // PHYSICAL PARAMETERS: |
| 77 | + //////////////////////////////////////////// |
| 78 | + |
| 79 | + /** |
| 80 | + * Density |
| 81 | + */ |
| 82 | + double rho; |
| 83 | + |
| 84 | + /** |
| 85 | + * Viscosity |
| 86 | + */ |
| 87 | + double nu; |
| 88 | + |
| 89 | + double initial_delta_t; |
| 90 | + /** |
| 91 | + * Solver tolerance for CG |
| 92 | + */ |
| 93 | + double CG_solver_tolerance; |
| 94 | + |
| 95 | + /** |
| 96 | + * Solver tolerance for GMRES |
| 97 | + */ |
| 98 | + double GMRES_solver_tolerance; |
| 99 | +}; |
| 100 | + |
| 101 | +template <int dim, int spacedim, typename LAC> |
| 102 | +NavierStokes<dim,spacedim, LAC>:: |
| 103 | +NavierStokes() |
| 104 | + : |
| 105 | + PDESystemInterface<dim,spacedim,NavierStokes<dim,spacedim,LAC>, LAC>( |
| 106 | + "Navier Stokes Interface", |
| 107 | + dim+dim+1, |
| 108 | + 1, |
| 109 | + "FESystem[FE_Q(2)^d-FE_Q(1)-FE_Q(2)^d]", |
| 110 | + (dim==3)?"v,v,v,p,u,u,u":"v,v,p,u,u", |
| 111 | + "1,0,1"), |
| 112 | + AMG_u("Prec for u", 1.4), |
| 113 | + AMG_v("Prec for v", 1.4), |
| 114 | + AMG_p("AMG for p") |
| 115 | +{ |
| 116 | + this->init(); |
| 117 | +} |
| 118 | + |
| 119 | +template <int dim, int spacedim, typename LAC> |
| 120 | +void NavierStokes<dim,spacedim,LAC>:: |
| 121 | +set_matrix_couplings(std::vector<std::string> &couplings) const |
| 122 | +{ |
| 123 | + couplings[0] = "1,1,1;1,1,1;1,1,1"; |
| 124 | +} |
| 125 | + |
| 126 | +template <int dim, int spacedim, typename LAC> |
| 127 | +void NavierStokes<dim,spacedim,LAC>:: |
| 128 | +declare_parameters (ParameterHandler &prm) |
| 129 | +{ |
| 130 | + PDESystemInterface<dim,spacedim, NavierStokes<dim,spacedim,LAC>,LAC>:: |
| 131 | + declare_parameters(prm); |
| 132 | + this->add_parameter(prm, &rho, |
| 133 | + "rho [kg m^3]", "1.0", |
| 134 | + Patterns::Double(0.0), |
| 135 | + "Density"); |
| 136 | + this->add_parameter(prm, &nu, |
| 137 | + "nu [Pa s]", "1.0", |
| 138 | + Patterns::Double(0.0), |
| 139 | + "Viscosity"); |
| 140 | + this->add_parameter(prm, &initial_delta_t, |
| 141 | + "initial delta t", "1e-1", |
| 142 | + Patterns::Double(0.0), |
| 143 | + "Initial Delta t"); |
| 144 | + this->add_parameter(prm, &CG_solver_tolerance, |
| 145 | + "CG Solver tolerance", "1e-8", |
| 146 | + Patterns::Double(0.0)); |
| 147 | + this->add_parameter(prm, &GMRES_solver_tolerance, |
| 148 | + "GMRES Solver tolerance", "1e-8", |
| 149 | + Patterns::Double(0.0)); |
| 150 | +} |
| 151 | + |
| 152 | +template <int dim, int spacedim, typename LAC> |
| 153 | +template <typename EnergyType, typename ResidualType> |
| 154 | +void |
| 155 | +NavierStokes<dim,spacedim,LAC>:: |
| 156 | +energies_and_residuals(const typename DoFHandler<dim,spacedim>::active_cell_iterator &cell, |
| 157 | + FEValuesCache<dim,spacedim> &fe_cache, |
| 158 | + std::vector<EnergyType> &, |
| 159 | + std::vector<std::vector<ResidualType> > &residual, |
| 160 | + bool compute_only_system_terms) const |
| 161 | +{ |
| 162 | + const FEValuesExtractors::Vector aux_velocity(0); |
| 163 | + const FEValuesExtractors::Scalar pressure(dim); |
| 164 | + const FEValuesExtractors::Vector velocity(dim+1); |
| 165 | + |
| 166 | + ResidualType et = 0; |
| 167 | + double dummy = 0.0; |
| 168 | + |
| 169 | + this->reinit (et, cell, fe_cache); |
| 170 | + |
| 171 | + // Velocity: |
| 172 | + auto &us = fe_cache.get_values("solution", "u", velocity, et); |
| 173 | + auto &ues = fe_cache.get_values("explicit_solution", "ue", velocity, dummy); |
| 174 | + auto &grad_ues = fe_cache.get_gradients("explicit_solution", "grad_u", velocity, dummy); |
| 175 | + auto &div_us = fe_cache.get_divergences("solution", "div_u", velocity, et); |
| 176 | + auto &sym_grad_ues = fe_cache.get_symmetric_gradients("explicit_solution", "sym_grad_ue", velocity, dummy); |
| 177 | + |
| 178 | + auto &vs = fe_cache.get_values("solution", "v", aux_velocity, et); |
| 179 | + auto &ves = fe_cache.get_values("explicit_solution", "ve", aux_velocity, dummy); |
| 180 | + auto &sym_grad_vs = fe_cache.get_symmetric_gradients("solution", "sym_grad_v", aux_velocity, et); |
| 181 | + auto &grad_vs = fe_cache.get_gradients("solution", "grad_v", aux_velocity, et); |
| 182 | + auto &div_vs = fe_cache.get_divergences("solution", "div_v", aux_velocity, et); |
| 183 | + |
| 184 | + // Pressure: |
| 185 | + auto &ps = fe_cache.get_values("solution", "p", pressure, et); |
| 186 | + auto &pes = fe_cache.get_values("explicit_solution", "pe", pressure, dummy); |
| 187 | + auto &grad_ps = fe_cache.get_gradients("solution", "grad_p", pressure,et); |
| 188 | + auto &grad_pes = fe_cache.get_gradients("explicit_solution", "grad_pe", pressure,dummy); |
| 189 | + |
| 190 | + |
| 191 | + const unsigned int n_quad_points = us.size(); |
| 192 | + auto &JxW = fe_cache.get_JxW_values(); |
| 193 | + const auto delta_t = this->get_timestep() != this->get_timestep() ? initial_delta_t : this->get_timestep() ; |
| 194 | + auto &fev = fe_cache.get_current_fe_values(); |
| 195 | + |
| 196 | + for (unsigned int quad=0; quad<n_quad_points; ++quad) |
| 197 | + { |
| 198 | + // // Delta Pressure: |
| 199 | + // const ResidualType &dp = dps[quad]; |
| 200 | + // const Tensor<1, dim, ResidualType> &grad_dp = grad_dps[quad]; |
| 201 | + |
| 202 | + // Pressure: |
| 203 | + const ResidualType &p = ps[quad]; |
| 204 | + const double &pe = pes[quad]; |
| 205 | + const Tensor<1, dim, ResidualType> &grad_p = grad_ps[quad]; |
| 206 | + const Tensor<1, dim, double> &grad_pe = grad_pes[quad]; |
| 207 | + |
| 208 | + // Velocity: |
| 209 | + const Tensor<1, dim, ResidualType> &u = us[quad]; |
| 210 | + const Tensor<1, dim, double> &ue = ues[quad]; |
| 211 | + const Tensor<2, dim, double> &grad_ue = grad_ues[quad]; |
| 212 | + const ResidualType &div_u = div_us[quad]; |
| 213 | + |
| 214 | + const Tensor<1, dim, ResidualType> &v = vs[quad]; |
| 215 | + const Tensor<1, dim, double> vd = SacadoTools::to_double(v); |
| 216 | + const Tensor<2, dim, ResidualType> &grad_v = grad_vs[quad]; |
| 217 | + const Tensor<2, dim, ResidualType> &sym_grad_v = sym_grad_vs[quad]; |
| 218 | + const Tensor<2, dim, double> &sym_grad_ue = sym_grad_ues[quad]; |
| 219 | + const Tensor<1, dim, double> &ve = ves[quad]; |
| 220 | + const ResidualType &div_v = div_vs[quad]; |
| 221 | + |
| 222 | + for (unsigned int i=0; i<residual[0].size(); ++i) |
| 223 | + { |
| 224 | + // Velocity: |
| 225 | + auto v_test = fev[ aux_velocity ].value(i,quad); |
| 226 | + auto sym_grad_v_test = fev[ aux_velocity ].symmetric_gradient(i,quad); |
| 227 | + |
| 228 | + |
| 229 | + auto u_test = fev[ velocity ].value(i,quad); |
| 230 | + auto div_u_test = fev[ velocity ].divergence(i,quad); |
| 231 | + auto sym_grad_ue_test = fev[ velocity ].symmetric_gradient(i,quad); |
| 232 | + |
| 233 | + // Pressure: |
| 234 | + auto p_test = fev[ pressure ].value(i,quad); |
| 235 | + auto grad_p_test = fev[ pressure ].gradient(i,quad); |
| 236 | + |
| 237 | + ResidualType res = 0.0; |
| 238 | + |
| 239 | + res += ((v-ue)/delta_t)*v_test; |
| 240 | + res += (ue * grad_ue )*v_test; |
| 241 | + res += nu * scalar_product( sym_grad_ue, |
| 242 | + sym_grad_ue_test); |
| 243 | + |
| 244 | + /* res += (ue * grad_v )*v_test; */ |
| 245 | + /* res += nu * scalar_product( sym_grad_v, */ |
| 246 | + /* sym_grad_v_test); */ |
| 247 | + |
| 248 | + |
| 249 | + res += grad_p*grad_p_test + (rho/delta_t)*(div_v * p_test); |
| 250 | + |
| 251 | +// Updating of the solution: |
| 252 | + res += (u - v + (delta_t/rho) *grad_p)*u_test; |
| 253 | + |
| 254 | + residual[0][i] += res * JxW[quad]; |
| 255 | + } |
| 256 | + } |
| 257 | + (void)compute_only_system_terms; |
| 258 | +} |
| 259 | + |
| 260 | + |
| 261 | +template <int dim, int spacedim, typename LAC> |
| 262 | +void |
| 263 | +NavierStokes<dim,spacedim,LAC>::compute_system_operators( |
| 264 | + const std::vector<shared_ptr<LATrilinos::BlockMatrix>> matrices, |
| 265 | + LinearOperator<LATrilinos::VectorType> &system_op, |
| 266 | + LinearOperator<LATrilinos::VectorType> &prec_op, |
| 267 | + LinearOperator<LATrilinos::VectorType> &prec_op_finer) const |
| 268 | +{ |
| 269 | + const unsigned int num_blocks = 3; |
| 270 | + typedef LATrilinos::VectorType::BlockType BVEC; |
| 271 | + typedef LATrilinos::VectorType VEC; |
| 272 | + |
| 273 | + static ReductionControl solver_control(matrices[0]->m(), CG_solver_tolerance); |
| 274 | + static SolverCG<BVEC> solver_CG(solver_control); |
| 275 | + |
| 276 | + const DoFHandler<dim,spacedim> &dh = this->get_dof_handler(); |
| 277 | + const ParsedFiniteElement<dim,spacedim> fe = this->pfe; |
| 278 | + AMG_v.initialize_preconditioner( matrices[0]->block(0,0)); //, fe, dh); |
| 279 | + AMG_p.initialize_preconditioner<dim, spacedim>( matrices[0]->block(1,1), fe, dh); |
| 280 | + AMG_u.initialize_preconditioner( matrices[0]->block(2,2)); //, fe, dh); |
| 281 | + |
| 282 | + //////////////////////////////////////////////////////////////////////////// |
| 283 | + // SYSTEM MATRIX: |
| 284 | + //////////////////////////////////////////////////////////////////////////// |
| 285 | + std::array<std::array<LinearOperator< BVEC >, num_blocks>, num_blocks> S; |
| 286 | + for (unsigned int i = 0; i<num_blocks; ++i) |
| 287 | + for (unsigned int j = 0; j<num_blocks; ++j) |
| 288 | + S[i][j] = linear_operator< BVEC >(matrices[0]->block(i,j) ); |
| 289 | + system_op = BlockLinearOperator< VEC >(S); |
| 290 | + |
| 291 | + |
| 292 | + //////////////////////////////////////////////////////////////////////////// |
| 293 | + // PRECONDITIONER MATRIX: |
| 294 | + //////////////////////////////////////////////////////////////////////////// |
| 295 | + auto Av = linear_operator<BVEC>(matrices[0]->block(0,0)); |
| 296 | + auto Av_inv = inverse_operator(Av, solver_CG, AMG_v); |
| 297 | + |
| 298 | + auto Ap = linear_operator<BVEC>(matrices[0]->block(1,1)); |
| 299 | + auto Ap_inv = inverse_operator(Ap, solver_CG, AMG_p); |
| 300 | + |
| 301 | + auto Au = linear_operator<BVEC>(matrices[0]->block(2,2)); |
| 302 | + auto Au_inv = inverse_operator(Au, solver_CG, AMG_u); |
| 303 | + |
| 304 | + // Preconditioner |
| 305 | + ////////////////////////////// |
| 306 | + |
| 307 | + BlockLinearOperator<VEC> diag_inv |
| 308 | + = block_diagonal_operator<num_blocks, VEC>( |
| 309 | + { |
| 310 | + { |
| 311 | + Av_inv, Ap_inv, Au_inv |
| 312 | + } |
| 313 | + } |
| 314 | + ); |
| 315 | + prec_op = diag_inv; |
| 316 | + |
| 317 | + /* prec_op = block_forward_substitution( */ |
| 318 | + /* BlockLinearOperator< VEC >(S), */ |
| 319 | + /* diag_inv); */ |
| 320 | +} |
| 321 | + |
| 322 | +#endif |
| 323 | + |
| 324 | +/*! @} */ |
0 commit comments