ExaDG
Loading...
Searching...
No Matches
convective_operator.h
1/*
2 * convective_operator.h
3 *
4 * Created on: Nov 5, 2018
5 * Author: fehn
6 */
7
8#ifndef INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_
9#define INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_
10
11#include <exadg/incompressible_navier_stokes/spatial_discretization/operators/weak_boundary_conditions.h>
12#include <exadg/incompressible_navier_stokes/user_interface/parameters.h>
13#include <exadg/matrix_free/integrators.h>
14#include <exadg/operators/operator_base.h>
15
16namespace ExaDG
17{
18namespace IncNS
19{
20namespace Operators
21{
23{
25 : formulation(FormulationConvectiveTerm::DivergenceFormulation),
26 upwind_factor(1.0),
27 use_outflow_bc(false),
28 type_dirichlet_bc(TypeDirichletBCs::Mirror),
29 ale(false)
30 {
31 }
32
33 FormulationConvectiveTerm formulation;
34
35 double upwind_factor;
36
37 bool use_outflow_bc;
38
39 TypeDirichletBCs type_dirichlet_bc;
40
41 bool ale;
42};
43
44template<int dim, typename Number>
46{
47public:
49
50
51private:
52 typedef dealii::VectorizedArray<Number> scalar;
53 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
54 typedef dealii::Tensor<2, dim, dealii::VectorizedArray<Number>> tensor;
55
56 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
57
58 typedef CellIntegrator<dim, dim, Number> IntegratorCell;
59 typedef FaceIntegrator<dim, dim, Number> IntegratorFace;
60
61public:
62 void
63 reinit(dealii::MatrixFree<dim, Number> const & matrix_free,
64 ConvectiveKernelData const & data,
65 unsigned int const dof_index,
66 unsigned int const quad_index_linearized,
67 bool const use_own_velocity_storage)
68 {
69 this->data = data;
70
71 // integrators for linearized problem
72 integrator_velocity =
73 std::make_shared<IntegratorCell>(matrix_free, dof_index, quad_index_linearized);
74 integrator_velocity_m =
75 std::make_shared<IntegratorFace>(matrix_free, true, dof_index, quad_index_linearized);
76 integrator_velocity_p =
77 std::make_shared<IntegratorFace>(matrix_free, false, dof_index, quad_index_linearized);
78
79 if(data.ale)
80 {
81 integrator_grid_velocity =
82 std::make_shared<IntegratorCell>(matrix_free, dof_index, quad_index_linearized);
83 integrator_grid_velocity_face =
84 std::make_shared<IntegratorFace>(matrix_free, true, dof_index, quad_index_linearized);
85 }
86
87 if(use_own_velocity_storage)
88 {
89 velocity.reset();
90 matrix_free.initialize_dof_vector(velocity.own(), dof_index);
91 }
92
93 if(data.ale)
94 {
95 matrix_free.initialize_dof_vector(grid_velocity.own(), dof_index);
96
97 AssertThrow(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation,
98 dealii::ExcMessage(
99 "ALE formulation can only be used in combination with ConvectiveFormulation"));
100 }
101 }
102
103 static MappingFlags
104 get_mapping_flags()
105 {
106 MappingFlags flags;
107
108 flags.cells = dealii::update_JxW_values | dealii::update_gradients;
109 flags.inner_faces = dealii::update_JxW_values | dealii::update_normal_vectors;
110 flags.boundary_faces = dealii::update_JxW_values | dealii::update_normal_vectors;
111
112 return flags;
113 }
114
115 /*
116 * IntegratorFlags valid for both the nonlinear convective operator and the linearized convective
117 * operator
118 */
120 get_integrator_flags() const
121 {
122 IntegratorFlags flags;
123
124 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
125 {
126 flags.cell_evaluate = dealii::EvaluationFlags::values;
127 flags.cell_integrate = dealii::EvaluationFlags::gradients;
128
129 flags.face_evaluate = dealii::EvaluationFlags::values;
130 flags.face_integrate = dealii::EvaluationFlags::values;
131 }
132 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
133 {
134 flags.cell_evaluate = dealii::EvaluationFlags::values | dealii::EvaluationFlags::gradients;
135 flags.cell_integrate = dealii::EvaluationFlags::values;
136
137 flags.face_evaluate = dealii::EvaluationFlags::values;
138 flags.face_integrate = dealii::EvaluationFlags::values;
139 }
140 else
141 {
142 AssertThrow(false, dealii::ExcMessage("Not implemented."));
143 }
144
145 return flags;
146 }
147
149 get_data() const
150 {
151 return this->data;
152 }
153
154 VectorType const &
155 get_velocity() const
156 {
157 return *velocity;
158 }
159
160 void
161 set_velocity_copy(VectorType const & src)
162 {
163 velocity.own() = src;
164
165 velocity->update_ghost_values();
166 }
167
168 void
169 set_velocity_ptr(VectorType const & src)
170 {
171 velocity.reset(src);
172
173 velocity->update_ghost_values();
174 }
175
176 void
177 set_grid_velocity_ptr(VectorType const & src)
178 {
179 grid_velocity.reset(src);
180
181 grid_velocity->update_ghost_values();
182 }
183
184 VectorType const &
185 get_grid_velocity() const
186 {
187 return *grid_velocity;
188 }
189
190 inline DEAL_II_ALWAYS_INLINE //
191 vector
192 get_velocity_cell(unsigned int const q) const
193 {
194 return integrator_velocity->get_value(q);
195 }
196
197 inline DEAL_II_ALWAYS_INLINE //
198 tensor
199 get_velocity_gradient_cell(unsigned int const q) const
200 {
201 return integrator_velocity->get_gradient(q);
202 }
203
204 inline DEAL_II_ALWAYS_INLINE //
205 vector
206 get_velocity_m(unsigned int const q) const
207 {
208 return integrator_velocity_m->get_value(q);
209 }
210
211 inline DEAL_II_ALWAYS_INLINE //
212 vector
213 get_velocity_p(unsigned int const q) const
214 {
215 return integrator_velocity_p->get_value(q);
216 }
217
218 // grid velocity cell
219 inline DEAL_II_ALWAYS_INLINE //
220 vector
221 get_grid_velocity_cell(unsigned int const q) const
222 {
223 return integrator_grid_velocity->get_value(q);
224 }
225
226 // grid velocity face (the grid velocity is continuous
227 // so that we need only one function instead of minus and
228 // plus functions)
229 inline DEAL_II_ALWAYS_INLINE //
230 vector
231 get_grid_velocity_face(unsigned int const q) const
232 {
233 return integrator_grid_velocity_face->get_value(q);
234 }
235
236 // linearized operator
237 void
238 reinit_cell(unsigned int const cell) const
239 {
240 integrator_velocity->reinit(cell);
241
242 if(data.ale)
243 integrator_grid_velocity->reinit(cell);
244
245 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
246 {
247 integrator_velocity->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
248 }
249 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
250 {
251 integrator_velocity->gather_evaluate(*velocity,
252 dealii::EvaluationFlags::values |
253 dealii::EvaluationFlags::gradients);
254
255 if(data.ale)
256 integrator_grid_velocity->gather_evaluate(*grid_velocity, dealii::EvaluationFlags::values);
257 }
258 else
259 {
260 AssertThrow(false, dealii::ExcMessage("Not implemented."));
261 }
262 }
263
264 void
265 reinit_face(unsigned int const face) const
266 {
267 integrator_velocity_m->reinit(face);
268 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
269
270 integrator_velocity_p->reinit(face);
271 integrator_velocity_p->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
272
273 if(data.ale)
274 {
275 integrator_grid_velocity_face->reinit(face);
276 integrator_grid_velocity_face->gather_evaluate(*grid_velocity,
277 dealii::EvaluationFlags::values);
278 }
279 }
280
281 void
282 reinit_boundary_face(unsigned int const face) const
283 {
284 integrator_velocity_m->reinit(face);
285 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
286
287 if(data.ale)
288 {
289 integrator_grid_velocity_face->reinit(face);
290 integrator_grid_velocity_face->gather_evaluate(*grid_velocity,
291 dealii::EvaluationFlags::values);
292 }
293 }
294
295 void
296 reinit_face_cell_based(unsigned int const cell,
297 unsigned int const face,
298 dealii::types::boundary_id const boundary_id) const
299 {
300 integrator_velocity_m->reinit(cell, face);
301 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
302
303 if(data.ale)
304 {
305 integrator_grid_velocity_face->reinit(cell, face);
306 integrator_grid_velocity_face->gather_evaluate(*grid_velocity,
307 dealii::EvaluationFlags::values);
308 }
309
310 if(boundary_id == dealii::numbers::internal_face_boundary_id) // internal face
311 {
312 // TODO: Matrix-free implementation in deal.II does currently not allow to access data of
313 // the neighboring element in case of cell-based face loops.
314 // integrator_velocity_p->reinit(cell, face);
315 // integrator_velocity_p->gather_evaluate(velocity,dealii::EvaluationFlags::values);
316 }
317 }
318
319 /*
320 * Volume flux, i.e., the term occurring in the volume integral. The volume flux depends on the
321 * formulation used for the convective term, and is therefore implemented separately for the
322 * different formulations
323 */
324 inline DEAL_II_ALWAYS_INLINE //
325 tensor
326 get_volume_flux_linearized_divergence_formulation(vector const & delta_u,
327 unsigned int const q) const
328 {
329 vector u = get_velocity_cell(q);
330 tensor F = outer_product(u, delta_u);
331
332 // minus sign due to integration by parts
333 return -(F + transpose(F));
334 }
335
336 inline DEAL_II_ALWAYS_INLINE //
337 vector
338 get_volume_flux_linearized_convective_formulation(vector const & delta_u,
339 tensor const & grad_delta_u,
340 unsigned int const q) const
341 {
342 // w = u
343 vector w = get_velocity_cell(q);
344 tensor grad_u = get_velocity_gradient_cell(q);
345
346 // w = u - u_grid
347 if(data.ale)
348 w -= get_grid_velocity_cell(q);
349
350 // plus sign since the strong formulation is used, i.e.
351 // integration by parts is performed twice
352 vector F = grad_u * delta_u + grad_delta_u * w;
353
354 return F;
355 }
356
357 /*
358 * Calculates the flux for nonlinear operator on interior faces. This function is needed for
359 * face-centric loops and the flux is therefore computed on both sides of an interior face. The
360 * interior flux (element m) is the first element in the tuple, the exterior flux (element p,
361 * neighbor) is the second element in the tuple.
362 */
363 inline DEAL_II_ALWAYS_INLINE //
364 std::tuple<vector, vector>
365 calculate_flux_nonlinear_interior_and_neighbor(vector const & uM,
366 vector const & uP,
367 vector const & normalM,
368 vector const & u_grid) const
369 {
370 vector flux_m, flux_p;
371
372 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
373 {
374 vector flux = calculate_lax_friedrichs_flux(uM, uP, normalM);
375
376 flux_m = flux;
377 flux_p = -flux; // opposite signs since n⁺ = - n⁻
378 }
379 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
380 {
381 vector flux;
382 scalar average_u_normal = 0.5 * (uM + uP) * normalM;
383 if(data.ale)
384 average_u_normal -= u_grid * normalM;
385
386 flux = calculate_upwind_flux(uM, uP, average_u_normal);
387
388 // a second term is needed since the strong formulation is implemented (integration by parts
389 // twice)
390 flux_m = flux - average_u_normal * uM;
391 flux_p = -flux + average_u_normal * uP; // opposite signs since n⁺ = - n⁻
392 }
393 else
394 {
395 AssertThrow(false, dealii::ExcMessage("Not implemented."));
396 }
397
398 return std::make_tuple(flux_m, flux_p);
399 }
400
401 /*
402 * Calculates the flux for nonlinear operator on boundary faces. The flux computation used on
403 * interior faces has to be "corrected" if a special outflow boundary condition is used on Neumann
404 * boundaries that is able to deal with backflow.
405 */
406 inline DEAL_II_ALWAYS_INLINE //
407 vector
408 calculate_flux_nonlinear_boundary(vector const & uM,
409 vector const & uP,
410 vector const & normalM,
411 vector const & u_grid,
412 BoundaryTypeU const & boundary_type) const
413 {
414 vector flux;
415
416 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
417 {
418 flux = calculate_lax_friedrichs_flux(uM, uP, normalM);
419
420 if(boundary_type == BoundaryTypeU::Neumann and data.use_outflow_bc == true)
421 apply_outflow_bc(flux, uM * normalM);
422 }
423 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
424 {
425 scalar average_u_normal = 0.5 * (uM + uP) * normalM;
426 if(data.ale)
427 average_u_normal -= u_grid * normalM;
428
429 flux = calculate_upwind_flux(uM, uP, average_u_normal);
430
431 if(boundary_type == BoundaryTypeU::Neumann and data.use_outflow_bc == true)
432 {
433 if(data.ale == false)
434 apply_outflow_bc(flux, uM * normalM);
435 else
436 apply_outflow_bc(flux, (uM - u_grid) * normalM);
437 }
438
439 // second term appears since the strong formulation is implemented (integration by parts
440 // is performed twice)
441 flux = flux - average_u_normal * uM;
442 }
443 else
444 {
445 AssertThrow(false, dealii::ExcMessage("Not implemented."));
446 }
447
448 return flux;
449 }
450
451 /*
452 * Calculates the flux for linearized operator on interior faces. This function is needed for
453 * face-centric loops and the flux is therefore computed on both sides of an interior face. The
454 * interior flux (element m) is the first element in the tuple, the exterior flux (element p,
455 * neighbor) is the second element in the tuple.
456 */
457 inline DEAL_II_ALWAYS_INLINE //
458 std::tuple<vector, vector>
459 calculate_flux_linearized_interior_and_neighbor(vector const & uM,
460 vector const & uP,
461 vector const & delta_uM,
462 vector const & delta_uP,
463 vector const & normalM,
464 unsigned int const q) const
465 {
466 vector fluxM, fluxP;
467
468 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
469 {
470 fluxM = calculate_lax_friedrichs_flux_linearized(uM, uP, delta_uM, delta_uP, normalM);
471 fluxP = -fluxM;
472 }
473 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
474 {
475 vector u_grid;
476 if(data.ale)
477 u_grid = get_grid_velocity_face(q);
478
479 vector flux = calculate_upwind_flux_linearized(uM, uP, u_grid, delta_uM, delta_uP, normalM);
480
481 scalar average_u_normal = 0.5 * (uM + uP) * normalM;
482 if(data.ale)
483 average_u_normal -= u_grid * normalM;
484
485 scalar average_delta_u_normal = 0.5 * (delta_uM + delta_uP) * normalM;
486
487 // second term appears since the strong formulation is implemented (integration by parts
488 // is performed twice)
489 fluxM = flux - average_u_normal * delta_uM - average_delta_u_normal * uM;
490 // opposite signs since n⁺ = - n⁻
491 fluxP = -flux + average_u_normal * delta_uP + average_delta_u_normal * uP;
492 }
493 else
494 {
495 AssertThrow(false, dealii::ExcMessage("Not implemented."));
496 }
497
498 return std::make_tuple(fluxM, fluxP);
499 }
500
501 /*
502 * Calculates the flux for linearized operator on interior faces. Only the flux on element e⁻ is
503 * computed.
504 */
505 inline DEAL_II_ALWAYS_INLINE //
506 vector
507 calculate_flux_linearized_interior(vector const & uM,
508 vector const & uP,
509 vector const & delta_uM,
510 vector const & delta_uP,
511 vector const & normalM,
512 unsigned int const q) const
513 {
514 vector flux;
515
516 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
517 {
518 flux = calculate_lax_friedrichs_flux_linearized(uM, uP, delta_uM, delta_uP, normalM);
519 }
520 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
521 {
522 vector u_grid;
523 if(data.ale)
524 u_grid = get_grid_velocity_face(q);
525
526 flux = calculate_upwind_flux_linearized(uM, uP, u_grid, delta_uM, delta_uP, normalM);
527
528 scalar average_u_normal = 0.5 * (uM + uP) * normalM;
529
530 if(data.ale)
531 average_u_normal -= u_grid * normalM;
532
533 scalar average_delta_u_normal = 0.5 * (delta_uM + delta_uP) * normalM;
534
535 // second term appears since the strong formulation is implemented (integration by parts
536 // is performed twice)
537 flux = flux - average_u_normal * delta_uM - average_delta_u_normal * uM;
538 }
539 else
540 {
541 AssertThrow(false, dealii::ExcMessage("Not implemented."));
542 }
543
544 return flux;
545 }
546
547 /*
548 * Calculates the flux for linearized operator on boundary faces. The only reason why this
549 * function has to be implemented separately is the fact that the flux computation used on
550 * interior faces has to be "corrected" if a special outflow boundary condition is used on Neumann
551 * boundaries that is able to deal with backflow.
552 */
553 inline DEAL_II_ALWAYS_INLINE //
554 vector
555 calculate_flux_linearized_boundary(vector const & uM,
556 vector const & uP,
557 vector const & delta_uM,
558 vector const & delta_uP,
559 vector const & normalM,
560 BoundaryTypeU const & boundary_type,
561 unsigned int const q) const
562 {
563 vector flux;
564
565 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
566 {
567 flux = calculate_lax_friedrichs_flux_linearized(uM, uP, delta_uM, delta_uP, normalM);
568
569 if(boundary_type == BoundaryTypeU::Neumann and data.use_outflow_bc == true)
570 apply_outflow_bc(flux, uM * normalM);
571 }
572 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
573 {
574 vector u_grid;
575 if(data.ale)
576 u_grid = get_grid_velocity_face(q);
577
578 flux = calculate_upwind_flux_linearized(uM, uP, u_grid, delta_uM, delta_uP, normalM);
579
580 if(boundary_type == BoundaryTypeU::Neumann and data.use_outflow_bc == true)
581 apply_outflow_bc(flux, uM * normalM);
582
583 scalar average_u_normal = 0.5 * (uM + uP) * normalM;
584 if(data.ale)
585 average_u_normal -= u_grid * normalM;
586
587 scalar average_delta_u_normal = 0.5 * (delta_uM + delta_uP) * normalM;
588
589 // second term appears since the strong formulation is implemented (integration by parts
590 // is performed twice)
591 flux = flux - average_u_normal * delta_uM - average_delta_u_normal * uM;
592 }
593 else
594 {
595 AssertThrow(false, dealii::ExcMessage("Not implemented."));
596 }
597
598 return flux;
599 }
600
601 /*
602 * Lax-Friedrichs flux (divergence formulation)
603 * Calculation of lambda according to Shahbazi et al.:
604 * lambda = max ( max |lambda(flux_jacobian_M)| , max |lambda(flux_jacobian_P)| )
605 * = max ( | 2*(uM)^T*normal | , | 2*(uP)^T*normal | )
606 */
607 inline DEAL_II_ALWAYS_INLINE //
608 scalar
609 calculate_lambda(scalar const & uM_n, scalar const & uP_n) const
610 {
611 return data.upwind_factor * 2.0 * std::max(std::abs(uM_n), std::abs(uP_n));
612 }
613
614 /*
615 * Calculate Lax-Friedrichs flux for nonlinear operator (divergence formulation).
616 */
617 inline DEAL_II_ALWAYS_INLINE //
618 vector
619 calculate_lax_friedrichs_flux(vector const & uM,
620 vector const & uP,
621 vector const & normalM) const
622 {
623 scalar uM_n = uM * normalM;
624 scalar uP_n = uP * normalM;
625
626 vector average_normal_flux =
627 dealii::make_vectorized_array<Number>(0.5) * (uM * uM_n + uP * uP_n);
628
629 vector jump_value = uM - uP;
630
631 scalar lambda = calculate_lambda(uM_n, uP_n);
632
633 return (average_normal_flux + 0.5 * lambda * jump_value);
634 }
635
636 /*
637 * Calculate Lax-Friedrichs flux for nonlinear operator (linear transport).
638 */
639 inline DEAL_II_ALWAYS_INLINE //
640 vector
641 calculate_lax_friedrichs_flux_linear_transport(vector const & uM,
642 vector const & uP,
643 vector const & wM,
644 vector const & wP,
645 vector const & normalM) const
646 {
647 scalar wM_n = wM * normalM;
648 scalar wP_n = wP * normalM;
649
650 vector average_normal_flux =
651 dealii::make_vectorized_array<Number>(0.5) * (uM * wM_n + uP * wP_n);
652
653 vector jump_value = uM - uP;
654
655 scalar lambda = calculate_lambda(wM_n, wP_n);
656
657 return (average_normal_flux + 0.5 * lambda * jump_value);
658 }
659
660 /*
661 * Calculate Lax-Friedrichs flux for linearized operator (divergence formulation).
662 */
663 inline DEAL_II_ALWAYS_INLINE //
664 vector
665 calculate_lax_friedrichs_flux_linearized(vector const & uM,
666 vector const & uP,
667 vector const & delta_uM,
668 vector const & delta_uP,
669 vector const & normalM) const
670 {
671 scalar uM_n = uM * normalM;
672 scalar uP_n = uP * normalM;
673
674 scalar delta_uM_n = delta_uM * normalM;
675 scalar delta_uP_n = delta_uP * normalM;
676
677 vector average_normal_flux =
678 dealii::make_vectorized_array<Number>(0.5) *
679 (uM * delta_uM_n + delta_uM * uM_n + uP * delta_uP_n + delta_uP * uP_n);
680
681 vector jump_value = delta_uM - delta_uP;
682
683 scalar lambda = calculate_lambda(uM_n, uP_n);
684
685 return (average_normal_flux + 0.5 * lambda * jump_value);
686 }
687
688 /*
689 * Calculate upwind flux for nonlinear operator (convective formulation).
690 */
691 inline DEAL_II_ALWAYS_INLINE //
692 vector
693 calculate_upwind_flux(vector const & uM,
694 vector const & uP,
695 scalar const & average_normal_velocity) const
696 {
697 vector average_velocity = 0.5 * (uM + uP);
698
699 vector jump_value = uM - uP;
700
701 return (average_normal_velocity * average_velocity +
702 data.upwind_factor * 0.5 * std::abs(average_normal_velocity) * jump_value);
703 }
704
705 /*
706 * outflow BC according to Gravemeier et al. (2012)
707 */
708 inline DEAL_II_ALWAYS_INLINE //
709 void
710 apply_outflow_bc(vector & flux, scalar const & uM_n) const
711 {
712 // we need a factor indicating whether we have inflow or outflow
713 // on the Neumann part of the boundary.
714 // outflow: factor = 1.0 (do nothing, neutral element of multiplication)
715 // inflow: factor = 0.0 (set convective flux to zero)
716 scalar outflow_indicator = dealii::make_vectorized_array<Number>(1.0);
717
718 for(unsigned int v = 0; v < dealii::VectorizedArray<Number>::size(); ++v)
719 {
720 if(uM_n[v] < 0.0) // backflow at outflow boundary
721 outflow_indicator[v] = 0.0;
722 }
723
724 // set flux to zero in case of backflow
725 flux = outflow_indicator * flux;
726 }
727
728 /*
729 * Calculate upwind flux for linearized operator (convective formulation).
730 */
731 inline DEAL_II_ALWAYS_INLINE //
732 vector
733 calculate_upwind_flux_linearized(vector const & uM,
734 vector const & uP,
735 vector const & u_grid,
736 vector const & delta_uM,
737 vector const & delta_uP,
738 vector const & normalM) const
739 {
740 vector average_velocity = 0.5 * (uM + uP);
741 vector delta_average_velocity = 0.5 * (delta_uM + delta_uP);
742
743 scalar average_normal_velocity = average_velocity * normalM;
744 if(data.ale)
745 average_normal_velocity -= u_grid * normalM;
746
747 scalar delta_average_normal_velocity = delta_average_velocity * normalM;
748
749 vector jump_value = delta_uM - delta_uP;
750
751 return (average_normal_velocity * delta_average_velocity +
752 delta_average_normal_velocity * average_velocity +
753 data.upwind_factor * 0.5 * std::abs(average_normal_velocity) * jump_value);
754 }
755
756 /*
757 * Velocity:
758 *
759 * Linearized convective operator (= homogeneous operator):
760 * Dirichlet boundary: delta_u⁺ = - delta_u⁻ or 0
761 * Neumann boundary: delta_u⁺ = + delta_u⁻
762 * symmetry boundary: delta_u⁺ = delta_u⁻ - 2 (delta_u⁻*n)n
763 */
764 inline DEAL_II_ALWAYS_INLINE //
765 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
766 calculate_exterior_value_linearized(
767 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> & delta_uM,
768 unsigned int const q,
769 FaceIntegrator<dim, dim, Number> & integrator,
770 BoundaryTypeU const & boundary_type) const
771 {
772 // element e⁺
773 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> delta_uP;
774
775 if(boundary_type == BoundaryTypeU::Dirichlet or boundary_type == BoundaryTypeU::DirichletCached)
776 {
777 if(data.type_dirichlet_bc == TypeDirichletBCs::Mirror)
778 {
779 delta_uP = -delta_uM;
780 }
781 else if(data.type_dirichlet_bc == TypeDirichletBCs::Direct)
782 {
783 // delta_uP = 0
784 // do nothing, delta_uP is already initialized with zero
785 }
786 else
787 {
788 AssertThrow(
789 false,
790 dealii::ExcMessage(
791 "Type of imposition of Dirichlet BC's for convective term is not implemented."));
792 }
793 }
794 else if(boundary_type == BoundaryTypeU::Neumann)
795 {
796 delta_uP = delta_uM;
797 }
798 else if(boundary_type == BoundaryTypeU::Symmetry)
799 {
800 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> normalM =
801 integrator.get_normal_vector(q);
802 delta_uP = delta_uM - 2. * (delta_uM * normalM) * normalM;
803 }
804 else
805 {
806 AssertThrow(false,
807 dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
808 }
809
810 return delta_uP;
811 }
812
813private:
815
816 lazy_ptr<VectorType> velocity;
817 lazy_ptr<VectorType> grid_velocity;
818
819 std::shared_ptr<IntegratorCell> integrator_velocity;
820 std::shared_ptr<IntegratorFace> integrator_velocity_m;
821 std::shared_ptr<IntegratorFace> integrator_velocity_p;
822
823 std::shared_ptr<IntegratorCell> integrator_grid_velocity;
824 std::shared_ptr<IntegratorFace> integrator_grid_velocity_face;
825};
826
827
828} // namespace Operators
829
830template<int dim>
832{
833 ConvectiveOperatorData() : OperatorBaseData(), quad_index_nonlinear(0)
834 {
835 }
836
837 /*
838 * Needs ConvectiveKernelData since it is not possible to remove all kernel parameters from
839 * function do_cell_integral(), i.e. the parameter FormulationConvectiveTerm is explicitly needed
840 * by ConvectiveOperator.
841 */
843
844 /*
845 * In addition to the quad_index in OperatorBaseData (which denotes the quadrature index for the
846 * linearized problem), an additional quadrature index has to be specified for the convective
847 * operator evaluation in case of explicit time integration or nonlinear residual evaluation).
848 */
849 unsigned int quad_index_nonlinear;
850
851 std::shared_ptr<BoundaryDescriptorU<dim> const> bc;
852};
853
854
855
856template<int dim, typename Number>
857class ConvectiveOperator : public OperatorBase<dim, Number, dim>
858{
859public:
860 typedef dealii::VectorizedArray<Number> scalar;
861 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
862 typedef dealii::Tensor<2, dim, dealii::VectorizedArray<Number>> tensor;
863
865
867
868 typedef typename Base::VectorType VectorType;
869 typedef typename Base::Range Range;
870 typedef typename Base::IntegratorCell IntegratorCell;
871 typedef typename Base::IntegratorFace IntegratorFace;
872
874 {
875 }
876
877 void
878 set_velocity_copy(VectorType const & src) const;
879
880 void
881 set_velocity_ptr(VectorType const & src) const;
882
883 dealii::LinearAlgebra::distributed::Vector<Number> const &
884 get_velocity() const;
885
886 void
887 initialize(dealii::MatrixFree<dim, Number> const & matrix_free,
888 dealii::AffineConstraints<Number> const & affine_constraints,
889 ConvectiveOperatorData<dim> const & data,
890 std::shared_ptr<Operators::ConvectiveKernel<dim, Number>> kernel);
891
892 /*
893 * Evaluate nonlinear operator.
894 */
895 void
896 evaluate_nonlinear_operator(VectorType & dst, VectorType const & src, Number const time) const;
897
898 void
899 evaluate_nonlinear_operator_add(VectorType & dst,
900 VectorType const & src,
901 Number const time) const;
902
903 // these functions are not implemented for the convective operator. They only have to exist
904 // due to the definition of the base class.
905 void
906 rhs(VectorType & dst) const final;
907
908 void
909 rhs_add(VectorType & dst) const final;
910
911 void
912 evaluate(VectorType & dst, VectorType const & src) const final;
913
914 void
915 evaluate_add(VectorType & dst, VectorType const & src) const final;
916
917private:
918 /*
919 * Evaluation of nonlinear operator.
920 */
921 void
922 cell_loop_nonlinear_operator(dealii::MatrixFree<dim, Number> const & matrix_free,
923 VectorType & dst,
924 VectorType const & src,
925 Range const & cell_range) const;
926
927 void
928 face_loop_nonlinear_operator(dealii::MatrixFree<dim, Number> const & matrix_free,
929 VectorType & dst,
930 VectorType const & src,
931 Range const & face_range) const;
932
933 void
934 boundary_face_loop_nonlinear_operator(dealii::MatrixFree<dim, Number> const & matrix_free,
935 VectorType & dst,
936 VectorType const & src,
937 Range const & face_range) const;
938
939 void
940 do_cell_integral_nonlinear_operator(IntegratorCell & integrator,
941 IntegratorCell & integrator_u_grid) const;
942
943 void
944 do_face_integral_nonlinear_operator(IntegratorFace & integrator_m,
945 IntegratorFace & integrator_p,
946 IntegratorFace & integrator_grid_velocity) const;
947
948 void
949 do_boundary_integral_nonlinear_operator(IntegratorFace & integrator,
950 IntegratorFace & integrator_grid_velocity,
951 dealii::types::boundary_id const & boundary_id) const;
952
953 /*
954 * Linearized operator.
955 */
956
957 // Note: this function can only be used for the linearized operator.
958 void
959 reinit_cell_derived(IntegratorCell & integrator, unsigned int const cell) const final;
960
961 // Note: this function can only be used for the linearized operator.
962 void
963 reinit_face_derived(IntegratorFace & integrator_m,
964 IntegratorFace & integrator_p,
965 unsigned int const face) const final;
966
967 // Note: this function can only be used for the linearized operator.
968 void
969 reinit_boundary_face_derived(IntegratorFace & integrator_m, unsigned int const face) const final;
970
971 // Note: this function can only be used for the linearized operator.
972 void
973 reinit_face_cell_based_derived(IntegratorFace & integrator_m,
974 IntegratorFace & integrator_p,
975 unsigned int const cell,
976 unsigned int const face,
977 dealii::types::boundary_id const boundary_id) const final;
978
979 // linearized operator
980 void
981 do_cell_integral(IntegratorCell & integrator) const final;
982
983 // linearized operator
984 void
985 do_face_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
986
987 // linearized operator
988 void
989 do_face_int_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
990
991 // linearized operator
992
993 // TODO
994 // This function is currently only needed due to limitations of deal.II which do
995 // currently not allow to access neighboring data in case of cell-based face loops.
996 // Once this functionality is available, this function should be removed again.
997 void
998 do_face_int_integral_cell_based(IntegratorFace & integrator_m,
999 IntegratorFace & integrator_p) const final;
1000
1001 // linearized operator
1002 void
1003 do_face_ext_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
1004
1005 // linearized operator
1006 void
1007 do_boundary_integral(IntegratorFace & integrator,
1008 OperatorType const & operator_type,
1009 dealii::types::boundary_id const & boundary_id) const final;
1010
1011 ConvectiveOperatorData<dim> operator_data;
1012
1013 std::shared_ptr<Operators::ConvectiveKernel<dim, Number>> kernel;
1014};
1015
1016} // namespace IncNS
1017} // namespace ExaDG
1018
1019
1020#endif /* INCLUDE_EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_ \
1021 */
Definition convective_operator.h:858
Definition convective_operator.h:46
Definition operator_base.h:98
Definition lazy_ptr.h:29
Definition driver.cpp:33
Definition convective_operator.h:832
Definition convective_operator.h:23
Definition integrator_flags.h:30
Definition mapping_flags.h:31
Definition operator_base.h:59