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