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