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_CONVECTION_DIFFUSION_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_
23#define EXADG_CONVECTION_DIFFUSION_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_
24
25// ExaDG
26#include <exadg/convection_diffusion/user_interface/boundary_descriptor.h>
27#include <exadg/convection_diffusion/user_interface/parameters.h>
28#include <exadg/functions_and_boundary_conditions/evaluate_functions.h>
29#include <exadg/matrix_free/integrators.h>
30#include <exadg/operators/operator_base.h>
31
32// C/C++
33#include <memory>
34
35namespace ExaDG
36{
37namespace ConvDiff
38{
39namespace Operators
40{
41template<int dim>
42struct ConvectiveKernelData
43{
44 ConvectiveKernelData()
45 : formulation(FormulationConvectiveTerm::DivergenceFormulation),
46 velocity_type(TypeVelocityField::Function),
47 dof_index_velocity(1),
48 numerical_flux_formulation(NumericalFluxConvectiveOperator::Undefined)
49 {
50 }
51
52 // formulation
53 FormulationConvectiveTerm formulation;
54
55 // analytical vs. numerical velocity field
56 TypeVelocityField velocity_type;
57
58 // TypeVelocityField::DoFVector
59 unsigned int dof_index_velocity;
60
61 // TypeVelocityField::Function
62 std::shared_ptr<dealii::Function<dim>> velocity;
63
64 // numerical flux (e.g., central flux vs. Lax-Friedrichs flux)
65 NumericalFluxConvectiveOperator numerical_flux_formulation;
66};
67
68template<int dim, typename Number>
70{
71private:
72 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
73
74 typedef CellIntegrator<dim, dim, Number> CellIntegratorVelocity;
75 typedef FaceIntegrator<dim, dim, Number> FaceIntegratorVelocity;
76
77 typedef dealii::VectorizedArray<Number> scalar;
78 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
79
80 typedef CellIntegrator<dim, 1, Number> IntegratorCell;
81 typedef FaceIntegrator<dim, 1, Number> IntegratorFace;
82
83public:
84 void
85 reinit(dealii::MatrixFree<dim, Number> const & matrix_free,
86 ConvectiveKernelData<dim> const & data_in,
87 unsigned int const quad_index,
88 bool const use_own_velocity_storage)
89 {
90 data = data_in;
91
92 if(data.velocity_type == TypeVelocityField::DoFVector)
93 {
94 integrator_velocity =
95 std::make_shared<CellIntegratorVelocity>(matrix_free, data.dof_index_velocity, quad_index);
96
97 integrator_velocity_m = std::make_shared<FaceIntegratorVelocity>(matrix_free,
98 true,
99 data.dof_index_velocity,
100 quad_index);
101
102 integrator_velocity_p = std::make_shared<FaceIntegratorVelocity>(matrix_free,
103 false,
104 data.dof_index_velocity,
105 quad_index);
106
107 if(use_own_velocity_storage)
108 {
109 velocity.reset();
110 matrix_free.initialize_dof_vector(velocity.own(), data.dof_index_velocity);
111 }
112 }
113 }
114
116 get_integrator_flags() const
117 {
118 IntegratorFlags flags;
119
120 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
121 {
122 flags.cell_evaluate = dealii::EvaluationFlags::values;
123 flags.cell_integrate = dealii::EvaluationFlags::gradients;
124 }
125 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
126 {
127 flags.cell_evaluate = dealii::EvaluationFlags::gradients;
128 flags.cell_integrate = dealii::EvaluationFlags::values;
129 }
130 else
131 {
132 AssertThrow(false, dealii::ExcMessage("Not implemented."));
133 }
134
135 flags.face_evaluate = dealii::EvaluationFlags::values;
136 flags.face_integrate = dealii::EvaluationFlags::values;
137
138 return flags;
139 }
140
141 static MappingFlags
142 get_mapping_flags()
143 {
144 MappingFlags flags;
145
146 flags.cells = dealii::update_gradients | dealii::update_JxW_values |
147 dealii::update_quadrature_points; // q-points due to analytical velocity field
148 flags.inner_faces = dealii::update_JxW_values | dealii::update_quadrature_points |
149 dealii::update_normal_vectors; // q-points due to analytical velocity field
150 flags.boundary_faces =
151 dealii::update_JxW_values | dealii::update_quadrature_points | dealii::update_normal_vectors;
152
153 return flags;
154 }
155
156 dealii::LinearAlgebra::distributed::Vector<Number> const &
157 get_velocity() const
158 {
159 return *velocity;
160 }
161
162 void
163 set_velocity_copy(VectorType const & velocity_in) const
164 {
165 AssertThrow(data.velocity_type == TypeVelocityField::DoFVector,
166 dealii::ExcMessage("Invalid parameter velocity_type."));
167
168 velocity.own() = velocity_in;
169
170 velocity->update_ghost_values();
171 }
172
173 void
174 set_velocity_ptr(VectorType const & velocity_in) const
175 {
176 AssertThrow(data.velocity_type == TypeVelocityField::DoFVector,
177 dealii::ExcMessage("Invalid parameter velocity_type."));
178
179 velocity.reset(velocity_in);
180
181 velocity->update_ghost_values();
182 }
183
184 void
185 reinit_cell(unsigned int const cell) const
186 {
187 if(data.velocity_type == TypeVelocityField::DoFVector)
188 {
189 integrator_velocity->reinit(cell);
190 integrator_velocity->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
191 }
192 }
193
194 void
195 reinit_face(unsigned int const face) const
196 {
197 if(data.velocity_type == TypeVelocityField::DoFVector)
198 {
199 integrator_velocity_m->reinit(face);
200 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
201
202 integrator_velocity_p->reinit(face);
203 integrator_velocity_p->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
204 }
205 }
206
207 void
208 reinit_boundary_face(unsigned int const face) const
209 {
210 if(data.velocity_type == TypeVelocityField::DoFVector)
211 {
212 integrator_velocity_m->reinit(face);
213 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
214 }
215 }
216
217 void
218 reinit_face_cell_based(unsigned int const cell,
219 unsigned int const face,
220 dealii::types::boundary_id const boundary_id) const
221 {
222 if(data.velocity_type == TypeVelocityField::DoFVector)
223 {
224 integrator_velocity_m->reinit(cell, face);
225 integrator_velocity_m->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
226
227 if(boundary_id == dealii::numbers::internal_face_boundary_id) // internal face
228 {
229 // TODO: Matrix-free implementation in deal.II does currently not allow to access data of
230 // the neighboring element in case of cell-based face loops.
231 // integrator_velocity_p->reinit(cell, face);
232 // integrator_velocity_p->gather_evaluate(*velocity, dealii::EvaluationFlags::values);
233 }
234 }
235 }
236
237 /*
238 * This function calculates the numerical flux using the central flux.
239 */
240 inline DEAL_II_ALWAYS_INLINE //
241 scalar
242 calculate_central_flux(scalar const & value_m,
243 scalar const & value_p,
244 scalar const & normal_velocity) const
245 {
246 scalar average_value = 0.5 * (value_m + value_p);
247
248 return normal_velocity * average_value;
249 }
250
251 /*
252 * The same as above, but with discontinuous velocity field.
253 */
254 inline DEAL_II_ALWAYS_INLINE //
255 scalar
256 calculate_central_flux(scalar const & value_m,
257 scalar const & value_p,
258 scalar const & normal_velocity_m,
259 scalar const & normal_velocity_p) const
260 {
261 return 0.5 * (normal_velocity_m * value_m + normal_velocity_p * value_p);
262 }
263
264 /*
265 * This function calculates the numerical flux using the Lax-Friedrichs flux.
266 */
267 inline DEAL_II_ALWAYS_INLINE //
268 scalar
269 calculate_lax_friedrichs_flux(scalar const & value_m,
270 scalar const & value_p,
271 scalar const & normal_velocity) const
272 {
273 scalar average_value = 0.5 * (value_m + value_p);
274 scalar jump_value = value_m - value_p;
275 scalar lambda = std::abs(normal_velocity);
276
277 return normal_velocity * average_value + 0.5 * lambda * jump_value;
278 }
279
280 /*
281 * The same as above, but with discontinuous velocity field.
282 */
283 inline DEAL_II_ALWAYS_INLINE //
284 scalar
285 calculate_lax_friedrichs_flux(scalar const & value_m,
286 scalar const & value_p,
287 scalar const & normal_velocity_m,
288 scalar const & normal_velocity_p) const
289 {
290 scalar jump_value = value_m - value_p;
291 scalar lambda = std::max(std::abs(normal_velocity_m), std::abs(normal_velocity_p));
292
293 return 0.5 * (normal_velocity_m * value_m + normal_velocity_p * value_p) +
294 0.5 * lambda * jump_value;
295 }
296
297 /*
298 * This function calculates the numerical flux where the type of the numerical flux depends on the
299 * specified parameter. This function handles both analytical and numerical velocity fields.
300 */
301 inline DEAL_II_ALWAYS_INLINE //
302 scalar
303 calculate_flux(unsigned int const q,
304 IntegratorFace & integrator,
305 scalar const & value_m,
306 scalar const & value_p,
307 vector const & normal_m,
308 Number const & time,
309 bool const exterior_velocity_available) const
310 {
311 scalar flux = dealii::make_vectorized_array<Number>(0.0);
312
313 if(data.velocity_type == TypeVelocityField::Function)
314 {
315 dealii::Point<dim, scalar> q_points = integrator.quadrature_point(q);
316
317 vector velocity = FunctionEvaluator<1, dim, Number>::value(*(data.velocity), q_points, time);
318
319 scalar normal_velocity = velocity * normal_m;
320
321 // flux functions are the same for DivergenceFormulation and ConvectiveFormulation
322
323 if(data.numerical_flux_formulation == NumericalFluxConvectiveOperator::CentralFlux)
324 {
325 flux = calculate_central_flux(value_m, value_p, normal_velocity);
326 }
327 else if(data.numerical_flux_formulation == NumericalFluxConvectiveOperator::LaxFriedrichsFlux)
328 {
329 flux = calculate_lax_friedrichs_flux(value_m, value_p, normal_velocity);
330 }
331 }
332 else if(data.velocity_type == TypeVelocityField::DoFVector)
333 {
334 vector velocity_m = integrator_velocity_m->get_value(q);
335 vector velocity_p =
336 exterior_velocity_available ? integrator_velocity_p->get_value(q) : velocity_m;
337
338 scalar normal_velocity_m = velocity_m * normal_m;
339 scalar normal_velocity_p = velocity_p * normal_m;
340
341 if(data.formulation == FormulationConvectiveTerm::DivergenceFormulation)
342 {
343 if(data.numerical_flux_formulation == NumericalFluxConvectiveOperator::CentralFlux)
344 {
345 flux = calculate_central_flux(value_m, value_p, normal_velocity_m, normal_velocity_p);
346 }
347 else if(data.numerical_flux_formulation ==
348 NumericalFluxConvectiveOperator::LaxFriedrichsFlux)
349 {
350 flux =
351 calculate_lax_friedrichs_flux(value_m, value_p, normal_velocity_m, normal_velocity_p);
352 }
353 }
354 else if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
355 {
356 scalar normal_velocity = 0.5 * (normal_velocity_m + normal_velocity_p);
357
358 if(data.numerical_flux_formulation == NumericalFluxConvectiveOperator::CentralFlux)
359 {
360 flux = calculate_central_flux(value_m, value_p, normal_velocity);
361 }
362 else if(data.numerical_flux_formulation ==
363 NumericalFluxConvectiveOperator::LaxFriedrichsFlux)
364 {
365 flux = calculate_lax_friedrichs_flux(value_m, value_p, normal_velocity);
366 }
367 }
368 else
369 {
370 AssertThrow(false, dealii::ExcMessage("Not implemented."));
371 }
372 }
373 else
374 {
375 AssertThrow(false, dealii::ExcMessage("Not implemented."));
376 }
377
378 return flux;
379 }
380
381 inline DEAL_II_ALWAYS_INLINE //
382 vector
383 calculate_average_velocity(unsigned int const q,
384 IntegratorFace & integrator,
385 Number const & time,
386 bool const exterior_velocity_available) const
387 {
388 vector velocity;
389
390 if(data.velocity_type == TypeVelocityField::Function)
391 {
392 dealii::Point<dim, scalar> q_points = integrator.quadrature_point(q);
393
394 velocity = FunctionEvaluator<1, dim, Number>::value(*(data.velocity), q_points, time);
395 }
396 else if(data.velocity_type == TypeVelocityField::DoFVector)
397 {
398 vector velocity_m = integrator_velocity_m->get_value(q);
399 vector velocity_p =
400 exterior_velocity_available ? integrator_velocity_p->get_value(q) : velocity_m;
401
402 velocity = 0.5 * (velocity_m + velocity_p);
403 }
404 else
405 {
406 AssertThrow(false, dealii::ExcMessage("Not implemented."));
407 }
408
409 return velocity;
410 }
411
412 inline DEAL_II_ALWAYS_INLINE //
413 std::tuple<scalar, scalar>
414 calculate_flux_interior_and_neighbor(unsigned int const q,
415 IntegratorFace & integrator,
416 scalar const & value_m,
417 scalar const & value_p,
418 vector const & normal_m,
419 Number const & time,
420 bool const exterior_velocity_available) const
421 {
422 scalar fluxM =
423 calculate_flux(q, integrator, value_m, value_p, normal_m, time, exterior_velocity_available);
424 scalar fluxP = -fluxM;
425
426 if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
427 {
428 vector velocity =
429 calculate_average_velocity(q, integrator, time, exterior_velocity_available);
430 scalar normal_velocity = velocity * normal_m;
431
432 // second term appears since the strong formulation is implemented (integration by parts
433 // is performed twice)
434 fluxM = fluxM - normal_velocity * value_m;
435 // opposite signs since n⁺ = - n⁻
436 fluxP = fluxP + normal_velocity * value_p;
437 }
438
439 return std::make_tuple(fluxM, fluxP);
440 }
441
442 inline DEAL_II_ALWAYS_INLINE //
443 scalar
444 calculate_flux_interior(unsigned int const q,
445 IntegratorFace & integrator,
446 scalar const & value_m,
447 scalar const & value_p,
448 vector const & normal_m,
449 Number const & time,
450 bool const exterior_velocity_available) const
451 {
452 scalar flux =
453 calculate_flux(q, integrator, value_m, value_p, normal_m, time, exterior_velocity_available);
454
455 if(data.formulation == FormulationConvectiveTerm::ConvectiveFormulation)
456 {
457 vector velocity =
458 calculate_average_velocity(q, integrator, time, exterior_velocity_available);
459 scalar normal_velocity = velocity * normal_m;
460
461 // second term appears since the strong formulation is implemented (integration by parts
462 // is performed twice)
463 flux = flux - normal_velocity * value_m;
464 }
465
466 return flux;
467 }
468
469
470 /*
471 * Volume flux, i.e., the term occurring in the volume integral
472 */
473 inline DEAL_II_ALWAYS_INLINE //
474 vector
475 get_volume_flux_divergence_form(scalar const & value,
476 IntegratorCell & integrator,
477 unsigned int const q,
478 Number const & time) const
479 {
480 vector velocity;
481
482 if(data.velocity_type == TypeVelocityField::Function)
483 {
484 velocity = FunctionEvaluator<1, dim, Number>::value(*(data.velocity),
485 integrator.quadrature_point(q),
486 time);
487 }
488 else if(data.velocity_type == TypeVelocityField::DoFVector)
489 {
490 velocity = integrator_velocity->get_value(q);
491 }
492 else
493 {
494 AssertThrow(false, dealii::ExcMessage("Not implemented."));
495 }
496
497 return (-value * velocity);
498 }
499
500 inline DEAL_II_ALWAYS_INLINE //
501 scalar
502 get_volume_flux_convective_form(vector const & gradient,
503 IntegratorCell & integrator,
504 unsigned int const q,
505 Number const & time) const
506 {
507 vector velocity;
508
509 if(data.velocity_type == TypeVelocityField::Function)
510 {
511 velocity = FunctionEvaluator<1, dim, Number>::value(*(data.velocity),
512 integrator.quadrature_point(q),
513 time);
514 }
515 else if(data.velocity_type == TypeVelocityField::DoFVector)
516 {
517 velocity = integrator_velocity->get_value(q);
518 }
519 else
520 {
521 AssertThrow(false, dealii::ExcMessage("Not implemented."));
522 }
523
524 return (velocity * gradient);
525 }
526
527private:
529
530 mutable lazy_ptr<VectorType> velocity;
531
532 std::shared_ptr<CellIntegratorVelocity> integrator_velocity;
533 std::shared_ptr<FaceIntegratorVelocity> integrator_velocity_m;
534 std::shared_ptr<FaceIntegratorVelocity> integrator_velocity_p;
535};
536
537} // namespace Operators
538
539
540template<int dim>
541struct ConvectiveOperatorData : public OperatorBaseData
542{
543 ConvectiveOperatorData() : OperatorBaseData()
544 {
545 }
546
548
549 std::shared_ptr<BoundaryDescriptor<dim> const> bc;
550};
551
552template<int dim, typename Number>
553class ConvectiveOperator : public OperatorBase<dim, Number, 1>
554{
555private:
556 typedef OperatorBase<dim, Number, 1> Base;
557
558 typedef typename Base::IntegratorCell IntegratorCell;
559 typedef typename Base::IntegratorFace IntegratorFace;
560
561 typedef typename Base::VectorType VectorType;
562
563 typedef dealii::VectorizedArray<Number> scalar;
564 typedef dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> vector;
565
566public:
567 void
568 initialize(dealii::MatrixFree<dim, Number> const & matrix_free,
569 dealii::AffineConstraints<Number> const & affine_constraints,
570 ConvectiveOperatorData<dim> const & data,
571 std::shared_ptr<Operators::ConvectiveKernel<dim, Number>> kernel);
572
573 dealii::LinearAlgebra::distributed::Vector<Number> const &
574 get_velocity() const;
575
576 void
577 set_velocity_copy(VectorType const & velocity) const;
578
579 void
580 set_velocity_ptr(VectorType const & velocity) const;
581
582private:
583 void
584 reinit_cell_derived(IntegratorCell & integrator, unsigned int const cell) const final;
585
586 void
587 reinit_face_derived(IntegratorFace & integrator_m,
588 IntegratorFace & integrator_p,
589 unsigned int const face) const final;
590
591 void
592 reinit_boundary_face_derived(IntegratorFace & integrator_m, unsigned int const face) const final;
593
594 void
595 reinit_face_cell_based_derived(IntegratorFace & integrator_m,
596 IntegratorFace & integrator_p,
597 unsigned int const cell,
598 unsigned int const face,
599 dealii::types::boundary_id const boundary_id) const final;
600
601 void
602 do_cell_integral(IntegratorCell & integrator) const final;
603
604 void
605 do_face_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
606
607 void
608 do_face_int_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
609
610 void
611 do_face_ext_integral(IntegratorFace & integrator_m, IntegratorFace & integrator_p) const final;
612
613 void
614 do_boundary_integral(IntegratorFace & integrator_m,
615 OperatorType const & operator_type,
616 dealii::types::boundary_id const & boundary_id) const final;
617
618 // TODO can be removed later once matrix-free evaluation allows accessing neighboring data for
619 // cell-based face loops
620 void
621 do_face_int_integral_cell_based(IntegratorFace & integrator_m,
622 IntegratorFace & integrator_p) const final;
623
624 ConvectiveOperatorData<dim> operator_data;
625
626 std::shared_ptr<Operators::ConvectiveKernel<dim, Number>> kernel;
627};
628
629} // namespace ConvDiff
630} // namespace ExaDG
631
632#endif /* EXADG_CONVECTION_DIFFUSION_SPATIAL_DISCRETIZATION_OPERATORS_CONVECTIVE_OPERATOR_H_ */
Definition convective_operator.h:554
Definition convective_operator.h:70
Definition lazy_ptr.h:29
Definition driver.cpp:33
Definition convective_operator.h:542
Definition convective_operator.h:43
Definition integrator_flags.h:31
Definition mapping_flags.h:31