ExaDG
Loading...
Searching...
No Matches
viscous_operator.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2021 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_VISCOUS_OPERATOR_H_
23#define INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_VISCOUS_OPERATOR_H_
24
25#include <exadg/grid/grid_data.h>
26#include <exadg/incompressible_navier_stokes/spatial_discretization/operators/weak_boundary_conditions.h>
27#include <exadg/incompressible_navier_stokes/user_interface/parameters.h>
28#include <exadg/matrix_free/integrators.h>
29#include <exadg/operators/interior_penalty_parameter.h>
30#include <exadg/operators/operator_base.h>
31#include <exadg/operators/variable_coefficients.h>
32
33namespace ExaDG
34{
35namespace IncNS
36{
37namespace Operators
38{
39struct ViscousKernelData
40{
41 ViscousKernelData()
42 : IP_factor(1.0),
43 viscosity(1.0),
44 formulation_viscous_term(FormulationViscousTerm::DivergenceFormulation),
45 penalty_term_div_formulation(PenaltyTermDivergenceFormulation::Symmetrized),
46 IP_formulation(InteriorPenaltyFormulation::SIPG),
47 viscosity_is_variable(false),
48 variable_normal_vector(false)
49 {
50 }
51
52 double IP_factor;
53 double viscosity;
54 FormulationViscousTerm formulation_viscous_term;
55 PenaltyTermDivergenceFormulation penalty_term_div_formulation;
56 InteriorPenaltyFormulation IP_formulation;
57 bool viscosity_is_variable;
58 bool variable_normal_vector;
59};
60
61template<int dim, typename Number>
62class ViscousKernel
63{
64private:
65 typedef dealii::VectorizedArray<Number> scalar;
66 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
67 typedef dealii::Tensor<2, dim, dealii::VectorizedArray<Number>> tensor;
68
69 typedef CellIntegrator<dim, dim, Number> IntegratorCell;
70 typedef FaceIntegrator<dim, dim, Number> IntegratorFace;
71
72public:
73 ViscousKernel() : quad_index(0), degree(1), tau(dealii::make_vectorized_array<Number>(0.0))
74 {
75 }
76
77 void
78 reinit(dealii::MatrixFree<dim, Number> const & matrix_free,
79 ViscousKernelData const & data,
80 unsigned int const dof_index,
81 unsigned int const quad_index)
82 {
83 this->data = data;
84
85 this->quad_index = quad_index;
86
87 dealii::FiniteElement<dim> const & fe = matrix_free.get_dof_handler(dof_index).get_fe();
88 this->degree = fe.degree;
89
90 calculate_penalty_parameter(matrix_free, dof_index);
91
92 AssertThrow(data.viscosity >= 0.0, dealii::ExcMessage("Viscosity is not set!"));
93
94 if(data.viscosity_is_variable)
95 {
96 // allocate vectors for variable coefficients and initialize with constant viscosity
97 viscosity_coefficients.initialize(matrix_free, quad_index, true, false);
98 viscosity_coefficients.set_coefficients(data.viscosity);
99 }
100 }
101
102 void
103 calculate_penalty_parameter(dealii::MatrixFree<dim, Number> const & matrix_free,
104 unsigned int const dof_index)
105 {
106 IP::calculate_penalty_parameter<dim, Number>(array_penalty_parameter, matrix_free, dof_index);
107 }
108
109 ViscousKernelData const &
110 get_data() const
111 {
112 return this->data;
113 }
114
115 unsigned int
116 get_quad_index() const
117 {
118 return this->quad_index;
119 }
120
121 unsigned int
122 get_degree() const
123 {
124 return this->degree;
125 }
126
127 void
128 set_constant_coefficient(Number const & constant_coefficient)
129 {
130 viscosity_coefficients.set_coefficients(constant_coefficient);
131 }
132
133 void
134 set_coefficient_cell(unsigned int const cell, unsigned int const q, scalar const & value)
135 {
136 viscosity_coefficients.set_coefficient_cell(cell, q, value);
137 }
138
139 scalar
140 get_coefficient_face(unsigned int const face, unsigned int const q)
141 {
142 return viscosity_coefficients.get_coefficient_face(face, q);
143 }
144
145 void
146 set_coefficient_face(unsigned int const face, unsigned int const q, scalar const & value)
147 {
148 viscosity_coefficients.set_coefficient_face(face, q, value);
149 }
150
151 scalar
152 get_coefficient_face_neighbor(unsigned int const face, unsigned int const q)
153 {
154 return viscosity_coefficients.get_coefficient_face_neighbor(face, q);
155 }
156
157 void
158 set_coefficient_face_neighbor(unsigned int const face, unsigned int const q, scalar const & value)
159 {
160 viscosity_coefficients.set_coefficient_face_neighbor(face, q, value);
161 }
162
164 get_integrator_flags() const
165 {
166 IntegratorFlags flags;
167
168 flags.cell_evaluate = dealii::EvaluationFlags::gradients;
169 flags.cell_integrate = dealii::EvaluationFlags::gradients;
170
171 flags.face_evaluate = dealii::EvaluationFlags::values | dealii::EvaluationFlags::gradients;
172 flags.face_integrate = dealii::EvaluationFlags::values | dealii::EvaluationFlags::gradients;
173
174 return flags;
175 }
176
177 static MappingFlags
178 get_mapping_flags(bool const compute_interior_face_integrals,
179 bool const compute_boundary_face_integrals)
180 {
181 MappingFlags flags;
182
183 flags.cells = dealii::update_JxW_values | dealii::update_gradients;
184 if(compute_interior_face_integrals)
185 flags.inner_faces =
186 dealii::update_JxW_values | dealii::update_gradients | dealii::update_normal_vectors;
187 if(compute_boundary_face_integrals)
188 flags.boundary_faces = dealii::update_JxW_values | dealii::update_gradients |
189 dealii::update_normal_vectors | dealii::update_quadrature_points;
190
191 return flags;
192 }
193
194 void
195 reinit_face(IntegratorFace & integrator_m,
196 IntegratorFace & integrator_p,
197 unsigned int const dof_index) const
198 {
199 tau = std::max(integrator_m.read_cell_data(array_penalty_parameter),
200 integrator_p.read_cell_data(array_penalty_parameter)) *
201 IP::get_penalty_factor<dim, Number>(
202 degree,
204 integrator_m.get_matrix_free().get_dof_handler(dof_index).get_triangulation()),
205 data.IP_factor);
206 }
207
208 void
209 reinit_boundary_face(IntegratorFace & integrator_m, unsigned int const dof_index) const
210 {
211 tau = integrator_m.read_cell_data(array_penalty_parameter) *
212 IP::get_penalty_factor<dim, Number>(
213 degree,
215 integrator_m.get_matrix_free().get_dof_handler(dof_index).get_triangulation()),
216 data.IP_factor);
217 }
218
219 void
220 reinit_face_cell_based(dealii::types::boundary_id const boundary_id,
221 IntegratorFace & integrator_m,
222 IntegratorFace & integrator_p,
223 unsigned int const dof_index) const
224 {
225 if(boundary_id == dealii::numbers::internal_face_boundary_id) // internal face
226 {
227 tau = std::max(integrator_m.read_cell_data(array_penalty_parameter),
228 integrator_p.read_cell_data(array_penalty_parameter)) *
229 IP::get_penalty_factor<dim, Number>(
230 degree,
232 integrator_m.get_matrix_free().get_dof_handler(dof_index).get_triangulation()),
233 data.IP_factor);
234 }
235 else // boundary face
236 {
237 tau = integrator_m.read_cell_data(array_penalty_parameter) *
238 IP::get_penalty_factor<dim, Number>(
239 degree,
241 integrator_m.get_matrix_free().get_dof_handler(dof_index).get_triangulation()),
242 data.IP_factor);
243 }
244 }
245
246 /*
247 * This functions return the viscosity for a given cell in a given quadrature point
248 */
249 inline DEAL_II_ALWAYS_INLINE //
250 scalar
251 get_viscosity_cell(unsigned int const cell, unsigned int const q) const
252 {
253 scalar viscosity = dealii::make_vectorized_array<Number>(data.viscosity);
254
255 if(data.viscosity_is_variable)
256 {
257 viscosity = viscosity_coefficients.get_coefficient_cell(cell, q);
258 }
259
260 return viscosity;
261 }
262
263 /*
264 * This function calculates the average viscosity for interior faces.
265 */
266 inline DEAL_II_ALWAYS_INLINE //
267 scalar
268 calculate_average_viscosity(unsigned int const face, unsigned int const q) const
269 {
270 scalar average_viscosity = dealii::make_vectorized_array<Number>(0.0);
271
272 scalar coefficient_face = viscosity_coefficients.get_coefficient_face(face, q);
273 scalar coefficient_face_neighbor =
274 viscosity_coefficients.get_coefficient_face_neighbor(face, q);
275
276 // harmonic mean (harmonic weighting according to Schott and Rasthofer et al. (2015))
277 average_viscosity = 2.0 * coefficient_face * coefficient_face_neighbor /
278 (coefficient_face + coefficient_face_neighbor);
279
280 // arithmetic mean
281 // average_viscosity = 0.5 * (coefficient_face + coefficient_face_neighbor);
282
283 // maximum value
284 // average_viscosity = std::max(coefficient_face, coefficient_face_neighbor);
285
286 return average_viscosity;
287 }
288
289 /*
290 * This function returns the viscosity for interior faces.
291 */
292 inline DEAL_II_ALWAYS_INLINE //
293 scalar
294 get_viscosity_interior_face(unsigned int const face, unsigned int const q) const
295 {
296 scalar viscosity = dealii::make_vectorized_array<Number>(data.viscosity);
297
298 if(data.viscosity_is_variable)
299 {
300 viscosity = calculate_average_viscosity(face, q);
301 }
302
303 return viscosity;
304 }
305
306 /*
307 * This function returns the viscosity for boundary faces.
308 */
309 inline DEAL_II_ALWAYS_INLINE //
310 scalar
311 get_viscosity_boundary_face(unsigned int const face, unsigned int const q) const
312 {
313 scalar viscosity = dealii::make_vectorized_array<Number>(data.viscosity);
314
315 if(data.viscosity_is_variable)
316 {
317 viscosity = viscosity_coefficients.get_coefficient_face(face, q);
318 }
319
320 return viscosity;
321 }
322
323 /*
324 * Volume flux, i.e., the term occurring in the volume integral
325 */
326 inline DEAL_II_ALWAYS_INLINE //
327 tensor
328 get_volume_flux(tensor const & gradient, scalar const & viscosity) const
329 {
330 if(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation)
331 {
332 return viscosity * (gradient + transpose(gradient));
333 }
334 else if(data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation)
335 {
336 return viscosity * gradient;
337 }
338 else
339 {
340 AssertThrow(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation or
341 data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation,
342 dealii::ExcMessage("Specified formulation of viscous term is not implemented."));
343
344 return tensor();
345 }
346 }
347
352 inline DEAL_II_ALWAYS_INLINE //
353 tensor
354 calculate_gradient_flux(vector const & value_m,
355 vector const & value_p,
356 vector const & normal,
357 scalar const & viscosity) const
358 {
359 tensor flux;
360
361 vector jump_value = value_m - value_p;
362 tensor jump_tensor = outer_product(jump_value, normal);
363
364 if(data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation)
365 {
366 if(data.IP_formulation == InteriorPenaltyFormulation::NIPG)
367 {
368 flux = 0.5 * viscosity * jump_tensor;
369 }
370 else if(data.IP_formulation == InteriorPenaltyFormulation::SIPG)
371 {
372 flux = -0.5 * viscosity * jump_tensor;
373 }
374 else
375 {
376 AssertThrow(
377 false, dealii::ExcMessage("Specified interior penalty formulation is not implemented."));
378 }
379 }
380 else if(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation)
381 {
382 if(data.IP_formulation == InteriorPenaltyFormulation::NIPG)
383 {
384 flux = 0.5 * viscosity * (jump_tensor + transpose(jump_tensor));
385 }
386 else if(data.IP_formulation == InteriorPenaltyFormulation::SIPG)
387 {
388 flux = -0.5 * viscosity * (jump_tensor + transpose(jump_tensor));
389 }
390 else
391 {
392 AssertThrow(
393 false, dealii::ExcMessage("Specified interior penalty formulation is not implemented."));
394 }
395 }
396 else
397 {
398 AssertThrow(false,
399 dealii::ExcMessage("Specified formulation of viscous term is not implemented."));
400 }
401
402 return flux;
403 }
404
405 /*
406 * This function calculates the gradient in normal direction on element e
407 * depending on the formulation of the viscous term.
408 */
409 template<typename Integrator>
410 inline DEAL_II_ALWAYS_INLINE //
411 vector
412 calculate_normal_gradient(unsigned int const q, Integrator & integrator) const
413 {
414 tensor gradient;
415
416 if(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation)
417 {
418 /*
419 * F = 2 * nu * symmetric_gradient
420 * = 2.0 * nu * 1/2 (grad(u) + grad(u)^T)
421 */
422 gradient = dealii::make_vectorized_array<Number>(2.0) * integrator.get_symmetric_gradient(q);
423 }
424 else if(data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation)
425 {
426 /*
427 * F = nu * grad(u)
428 */
429 gradient = integrator.get_gradient(q);
430 }
431 else
432 {
433 AssertThrow(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation or
434 data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation,
435 dealii::ExcMessage("Specified formulation of viscous term is not implemented."));
436 }
437
438 vector normal_gradient = gradient * integrator.get_normal_vector(q);
439
440 return normal_gradient;
441 }
442
443
450 inline DEAL_II_ALWAYS_INLINE //
451 vector
452 calculate_value_flux(vector const & normal_gradient_m,
453 vector const & normal_gradient_p,
454 vector const & value_m,
455 vector const & value_p,
456 vector const & normal,
457 scalar const & viscosity) const
458 {
459 vector flux;
460
461 vector jump_value = value_m - value_p;
462 vector average_normal_gradient = 0.5 * (normal_gradient_m + normal_gradient_p);
463
464 if(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation)
465 {
466 if(data.penalty_term_div_formulation == PenaltyTermDivergenceFormulation::Symmetrized)
467 {
468 flux = viscosity * average_normal_gradient -
469 viscosity * tau * (jump_value + (jump_value * normal) * normal);
470 }
471 else if(data.penalty_term_div_formulation == PenaltyTermDivergenceFormulation::NotSymmetrized)
472 {
473 flux = viscosity * average_normal_gradient - viscosity * tau * jump_value;
474 }
475 else
476 {
477 AssertThrow(
478 data.penalty_term_div_formulation == PenaltyTermDivergenceFormulation::Symmetrized or
479 data.penalty_term_div_formulation == PenaltyTermDivergenceFormulation::NotSymmetrized,
480 dealii::ExcMessage("Specified formulation of viscous term is not implemented."));
481 }
482 }
483 else if(data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation)
484 {
485 flux = viscosity * average_normal_gradient - viscosity * tau * jump_value;
486 }
487 else
488 {
489 AssertThrow(data.formulation_viscous_term == FormulationViscousTerm::DivergenceFormulation or
490 data.formulation_viscous_term == FormulationViscousTerm::LaplaceFormulation,
491 dealii::ExcMessage("Specified formulation of viscous term is not implemented."));
492 }
493
494 return flux;
495 }
496
497 // clang-format off
498 /*
499 * This function calculates the interior velocity gradient in normal
500 * direction depending on the operator type.
501 *
502 * The variable normal_gradient_m has the meaning of F(u⁻)*n with
503 *
504 * Divergence formulation: F(u) = F_nu(u) / nu = nu * ( grad(u) + grad(u)^T )
505 * Laplace formulation: F(u) = F_nu(u) / nu = nu * grad(u)
506 *
507 */
508 // clang-format on
509 template<typename Integrator>
510 inline DEAL_II_ALWAYS_INLINE //
511 vector
512 calculate_interior_normal_gradient(unsigned int const q,
513 Integrator const & integrator,
514 OperatorType const & operator_type) const
515 {
516 vector normal_gradient_m;
517
518 if(operator_type == OperatorType::full or operator_type == OperatorType::homogeneous)
519 {
520 normal_gradient_m = calculate_normal_gradient(q, integrator);
521 }
522 else if(operator_type == OperatorType::inhomogeneous)
523 {
524 // do nothing, normal_gradient_m is already initialized with 0
525 }
526 else
527 {
528 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
529 }
530
531 return normal_gradient_m;
532 }
533
534private:
535 ViscousKernelData data;
536
537 unsigned int quad_index;
538
539 unsigned int degree;
540
541 dealii::AlignedVector<scalar> array_penalty_parameter;
542
543 mutable scalar tau;
544
545 VariableCoefficients<dealii::VectorizedArray<Number>> viscosity_coefficients;
546};
547
548} // namespace Operators
549
550template<int dim>
551struct ViscousOperatorData : public OperatorBaseData
552{
553 ViscousOperatorData() : OperatorBaseData()
554 {
555 }
556
558
559 std::shared_ptr<BoundaryDescriptorU<dim> const> bc;
560};
561
562template<int dim, typename Number>
563class ViscousOperator : public OperatorBase<dim, Number, dim>
564{
565public:
566 typedef dealii::VectorizedArray<Number> scalar;
567 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
568 typedef dealii::Tensor<2, dim, dealii::VectorizedArray<Number>> tensor;
569
570 typedef OperatorBase<dim, Number, dim> Base;
571
572 typedef typename Base::VectorType VectorType;
573 typedef typename Base::Range Range;
574 typedef typename Base::IntegratorCell IntegratorCell;
575 typedef typename Base::IntegratorFace IntegratorFace;
576
577 void
578 initialize(dealii::MatrixFree<dim, Number> const & matrix_free,
579 dealii::AffineConstraints<Number> const & affine_constraints,
580 ViscousOperatorData<dim> const & data,
581 std::shared_ptr<Operators::ViscousKernel<dim, Number>> viscous_kernel);
582
583 void
584 update();
585
586private:
587 void
588 reinit_face_derived(IntegratorFace & integrator_m,
589 IntegratorFace & integrator_p,
590 unsigned int const face) const final;
591
592 void
593 reinit_boundary_face_derived(IntegratorFace & integrator_m, unsigned int const face) const final;
594
595 void
596 reinit_face_cell_based_derived(IntegratorFace & integrator_m,
597 IntegratorFace & integrator_p,
598 unsigned int const cell,
599 unsigned int const face,
600 dealii::types::boundary_id const boundary_id) const final;
601
602 void
603 do_cell_integral(IntegratorCell & integrator) const final;
604
605 void
606 do_face_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
607
608 void
609 do_face_int_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
610
611 void
612 do_face_ext_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
613
614 void
615 do_boundary_integral(IntegratorFace & integrator,
616 OperatorType const & operator_type,
617 dealii::types::boundary_id const & boundary_id) const final;
618
619 ViscousOperatorData<dim> operator_data;
620
621 std::shared_ptr<Operators::ViscousKernel<dim, Number>> kernel;
622};
623
624} // namespace IncNS
625} // namespace ExaDG
626
627#endif /* INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_VISCOUS_OPERATOR_H_ \
628 */
Definition viscous_operator.h:63
DEAL_II_ALWAYS_INLINE vector calculate_value_flux(vector const &normal_gradient_m, vector const &normal_gradient_p, vector const &value_m, vector const &value_p, vector const &normal, scalar const &viscosity) const
Definition viscous_operator.h:452
DEAL_II_ALWAYS_INLINE tensor calculate_gradient_flux(vector const &value_m, vector const &value_p, vector const &normal, scalar const &viscosity) const
Definition viscous_operator.h:354
Definition viscous_operator.h:564
Definition driver.cpp:33
ElementType get_element_type(dealii::Triangulation< dim > const &tria)
Definition grid_data.h:70
Definition viscous_operator.h:40
Definition viscous_operator.h:552
Definition integrator_flags.h:30
Definition mapping_flags.h:31