ExaDG
Loading...
Searching...
No Matches
operator.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2023 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_ACOUSTIC_CONSERVATION_EQUATIONS_SPATIAL_DISCRETIZATION_OPERATORS_OPERATOR_H_
23#define EXADG_ACOUSTIC_CONSERVATION_EQUATIONS_SPATIAL_DISCRETIZATION_OPERATORS_OPERATOR_H_
24
25// deal.II
26#include <deal.II/lac/la_parallel_block_vector.h>
27
28// ExaDG
29#include <exadg/acoustic_conservation_equations/spatial_discretization/operators/weak_boundary_conditions.h>
30#include <exadg/acoustic_conservation_equations/user_interface/boundary_descriptor.h>
31#include <exadg/acoustic_conservation_equations/user_interface/enum_types.h>
32#include <exadg/matrix_free/integrators.h>
33#include <exadg/operators/integrator_flags.h>
34#include <exadg/operators/mapping_flags.h>
35
36namespace ExaDG
37{
38namespace Acoustics
39{
40namespace Operators
41{
42template<int dim, typename Number>
43class Kernel
44{
45 using scalar = dealii::VectorizedArray<Number>;
46 using vector = dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>;
47
48 using CellIntegratorP = CellIntegrator<dim, 1, Number>;
49 using CellIntegratorU = CellIntegrator<dim, dim, Number>;
50
51public:
52 static MappingFlags
53 get_mapping_flags()
54 {
55 MappingFlags flags;
56
57 flags.cells = dealii::update_JxW_values | dealii::update_gradients;
58 flags.inner_faces = dealii::update_JxW_values | dealii::update_normal_vectors;
59 flags.boundary_faces =
60 dealii::update_JxW_values | dealii::update_quadrature_points | dealii::update_normal_vectors;
61
62 return flags;
63 }
64
65 /*
66 * Volume flux for the momentum equation, i.e., the term occurring in the volume integral for
67 * weak formulation (performing integration-by-parts)
68 */
69 inline DEAL_II_ALWAYS_INLINE //
70 vector
71 get_volume_flux_weak_momentum(CellIntegratorU const & velocity, unsigned int const q) const
72 {
73 // minus sign due to integration by parts
74 return -velocity.get_value(q);
75 }
76
77 /*
78 * Volume flux for the momentum equation, i.e., the term occurring in the volume integral for
79 * strong formulation (integration-by-parts performed twice)
80 */
81 inline DEAL_II_ALWAYS_INLINE //
82 scalar
83 get_volume_flux_strong_momentum(CellIntegratorU const & velocity, unsigned int const q) const
84 {
85 return velocity.get_divergence(q);
86 }
87
88
89 /*
90 * Volume flux for the mass equation, i.e., the term occurring in the volume integral for
91 * weak formulation (performing integration-by-parts)
92 */
93 inline DEAL_II_ALWAYS_INLINE //
94 scalar
95 get_volume_flux_weak_mass(CellIntegratorP const & pressure, unsigned int const q) const
96 {
97 // minus sign due to integration by parts
98 return -pressure.get_value(q);
99 }
100
101 /*
102 * Volume flux for the mass equation, i.e., the term occurring in the volume integral for
103 * strong formulation (integration-by-parts performed twice)
104 */
105 inline DEAL_II_ALWAYS_INLINE //
106 vector
107 get_volume_flux_strong_mass(CellIntegratorP const & pressure, unsigned int const q) const
108 {
109 return pressure.get_gradient(q);
110 }
111
112 /*
113 * Lax Friedrichs flux for the momentum equation.
114 */
115 inline DEAL_II_ALWAYS_INLINE //
116 vector
117 calculate_lax_friedrichs_flux_momentum(vector const & rho_um,
118 vector const & rho_up,
119 Number const & gamma,
120 scalar const & pm,
121 scalar const & pp,
122 vector const & n) const
123 {
124 return Number{0.5} * (rho_um + rho_up) + gamma * (pm - pp) * n;
125 }
126
127 /*
128 * Lax Friedrichs flux for the mass equation.
129 */
130 inline DEAL_II_ALWAYS_INLINE //
131 scalar
132 calculate_lax_friedrichs_flux_mass(scalar const & pm,
133 scalar const & pp,
134 Number const & tau,
135 vector const & rho_um,
136 vector const & rho_up,
137 vector const & n) const
138 {
139 return Number{0.5} * (pm + pp) + tau * (rho_um - rho_up) * n;
140 }
141};
142
143} // namespace Operators
144
145template<int dim>
146struct OperatorData
147{
148 OperatorData()
149 : dof_index_pressure(0),
150 dof_index_velocity(1),
151 quad_index(0),
152 block_index_pressure(0),
153 block_index_velocity(1),
154 formulation(Formulation::SkewSymmetric),
155 bc(nullptr),
156 speed_of_sound(-1.0)
157 {
158 }
159
160 unsigned int dof_index_pressure;
161 unsigned int dof_index_velocity;
162
163 unsigned int quad_index;
164
165 unsigned int block_index_pressure;
166 unsigned int block_index_velocity;
167
168 Formulation formulation;
169
170 std::shared_ptr<BoundaryDescriptor<dim> const> bc;
171
172 double speed_of_sound;
173};
174
175template<int dim, typename Number>
176class Operator
177{
178 using This = Operator<dim, Number>;
179
180 using BlockVectorType = dealii::LinearAlgebra::distributed::BlockVector<Number>;
181
182 using scalar = dealii::VectorizedArray<Number>;
183 using vector = dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>;
184
185 using Range = std::pair<unsigned int, unsigned int>;
186
187 using CellIntegratorU = CellIntegrator<dim, dim, Number>;
188 using CellIntegratorP = CellIntegrator<dim, 1, Number>;
189
190 using FaceIntegratorU = FaceIntegrator<dim, dim, Number>;
191 using FaceIntegratorP = FaceIntegrator<dim, 1, Number>;
192
193public:
194 Operator() : evaluation_time(Number{0.0}), tau(Number{0.0}), gamma(Number{0.0})
195 {
196 }
197
198 void
199 initialize(dealii::MatrixFree<dim, Number> const & matrix_free_in,
200 OperatorData<dim> const & data_in)
201 {
202 // Set Matrixfree and OperatorData.
203 matrix_free = &matrix_free_in;
204 data = data_in;
205
206 // Precompute numbers that are needed in kernels.
207 tau = (Number)(0.5 * data_in.speed_of_sound);
208 gamma = (Number)(0.5 / data_in.speed_of_sound);
209
210 // Set integration flags.
211 if(data_in.formulation == Formulation::Weak)
212 {
213 integrator_flags_p.cell_evaluate = dealii::EvaluationFlags::values;
214 integrator_flags_p.cell_integrate = dealii::EvaluationFlags::gradients;
215 integrator_flags_p.face_evaluate = dealii::EvaluationFlags::values;
216 integrator_flags_p.face_integrate = dealii::EvaluationFlags::values;
217
218 integrator_flags_u.cell_evaluate = dealii::EvaluationFlags::values;
219 integrator_flags_u.cell_integrate = dealii::EvaluationFlags::gradients;
220 integrator_flags_u.face_evaluate = dealii::EvaluationFlags::values;
221 integrator_flags_u.face_integrate = dealii::EvaluationFlags::values;
222 }
223 else if(data_in.formulation == Formulation::Strong)
224 {
225 integrator_flags_p.cell_evaluate = dealii::EvaluationFlags::gradients;
226 integrator_flags_p.cell_integrate = dealii::EvaluationFlags::values;
227 integrator_flags_p.face_evaluate = dealii::EvaluationFlags::values;
228 integrator_flags_p.face_integrate = dealii::EvaluationFlags::values;
229
230 integrator_flags_u.cell_evaluate = dealii::EvaluationFlags::gradients;
231 integrator_flags_u.cell_integrate = dealii::EvaluationFlags::values;
232 integrator_flags_u.face_evaluate = dealii::EvaluationFlags::values;
233 integrator_flags_u.face_integrate = dealii::EvaluationFlags::values;
234 }
235 else if(data_in.formulation == Formulation::SkewSymmetric)
236 {
237 integrator_flags_p.cell_evaluate = dealii::EvaluationFlags::gradients;
238 integrator_flags_p.cell_integrate = dealii::EvaluationFlags::gradients;
239 integrator_flags_p.face_evaluate = dealii::EvaluationFlags::values;
240 integrator_flags_p.face_integrate = dealii::EvaluationFlags::values;
241
242 integrator_flags_u.cell_evaluate = dealii::EvaluationFlags::values;
243 integrator_flags_u.cell_integrate = dealii::EvaluationFlags::values;
244 integrator_flags_u.face_evaluate = dealii::EvaluationFlags::values;
245 integrator_flags_u.face_integrate = dealii::EvaluationFlags::values;
246 }
247 else
248 {
249 AssertThrow(false, dealii::ExcMessage("Not implemented."));
250 }
251 }
252
253 void
254 evaluate(BlockVectorType & dst, BlockVectorType const & src, double const time) const
255 {
256 do_evaluate(dst, src, time, true);
257 }
258
259 void
260 evaluate_add(BlockVectorType & dst, BlockVectorType const & src, double const time) const
261 {
262 do_evaluate(dst, src, time, true);
263 }
264
265private:
266 void
267 do_evaluate(BlockVectorType & dst,
268 BlockVectorType const & src,
269 double const time,
270 bool const zero_dst_vector) const
271 {
272 evaluation_time = (Number)time;
273
274 matrix_free->loop(&This::cell_loop,
275 &This::face_loop,
276 &This::boundary_face_loop,
277 this,
278 dst,
279 src,
280 zero_dst_vector,
281 dealii::MatrixFree<dim, Number>::DataAccessOnFaces::values,
282 dealii::MatrixFree<dim, Number>::DataAccessOnFaces::values);
283 }
284
285 void
286 do_cell_integral(CellIntegratorP & pressure, CellIntegratorU & velocity) const
287 {
288 if(data.formulation == Formulation::Weak)
289 {
290 for(unsigned int q : pressure.quadrature_point_indices())
291 {
292 vector const flux_momentum = kernel.get_volume_flux_weak_momentum(velocity, q);
293 scalar const flux_mass = kernel.get_volume_flux_weak_mass(pressure, q);
294
295 pressure.submit_gradient(flux_momentum, q);
296 velocity.submit_divergence(flux_mass, q);
297 }
298 }
299 else if(data.formulation == Formulation::Strong)
300 {
301 for(unsigned int q : pressure.quadrature_point_indices())
302 {
303 scalar const flux_momentum = kernel.get_volume_flux_strong_momentum(velocity, q);
304 vector const flux_mass = kernel.get_volume_flux_strong_mass(pressure, q);
305
306 pressure.submit_value(flux_momentum, q);
307 velocity.submit_value(flux_mass, q);
308 }
309 }
310 else if(data.formulation == Formulation::SkewSymmetric)
311 {
312 for(unsigned int q : pressure.quadrature_point_indices())
313 {
314 vector const flux_momentum = kernel.get_volume_flux_weak_momentum(velocity, q);
315 vector const flux_mass = kernel.get_volume_flux_strong_mass(pressure, q);
316
317 pressure.submit_gradient(flux_momentum, q);
318 velocity.submit_value(flux_mass, q);
319 }
320 }
321 else
322 {
323 AssertThrow(false, dealii::ExcMessage("Not implemented."));
324 }
325 }
326
327
328 template<bool weight_neighbor, // = false for cell centric loops and boundary loops
329 typename ExteriorFaceIntegratorP,
330 typename ExteriorFaceIntegratorU>
331 void
332 do_face_integral(FaceIntegratorP & pressure_m,
333 ExteriorFaceIntegratorP & pressure_p,
334 FaceIntegratorU & velocity_m,
335 ExteriorFaceIntegratorU & velocity_p) const
336 {
337 for(unsigned int q : pressure_m.quadrature_point_indices())
338 {
339 scalar const pm = pressure_m.get_value(q);
340 scalar const pp = pressure_p.get_value(q);
341 vector const rho_um = velocity_m.get_value(q);
342 vector const rho_up = velocity_p.get_value(q);
343 vector const n = pressure_m.normal_vector(q);
344
345 vector const flux_momentum =
346 kernel.calculate_lax_friedrichs_flux_momentum(rho_um, rho_up, gamma, pm, pp, n);
347
348 scalar const flux_mass =
349 kernel.calculate_lax_friedrichs_flux_mass(pm, pp, tau, rho_um, rho_up, n);
350
351 if(data.formulation == Formulation::Weak)
352 {
353 scalar const flux_momentum_weak = flux_momentum * n;
354 vector const flux_mass_weak = flux_mass * n;
355
356 pressure_m.submit_value(flux_momentum_weak, q);
357 velocity_m.submit_value(flux_mass_weak, q);
358
359 if constexpr(weight_neighbor)
360 {
361 // minus signs since n⁺ = - n⁻
362 pressure_p.submit_value(-flux_momentum_weak, q);
363 velocity_p.submit_value(-flux_mass_weak, q);
364 }
365 }
366 else if(data.formulation == Formulation::Strong)
367 {
368 pressure_m.submit_value((flux_momentum - rho_um) * n, q);
369 velocity_m.submit_value((flux_mass - pm) * n, q);
370
371 if constexpr(weight_neighbor)
372 {
373 // minus signs since n⁺ = - n⁻
374 pressure_p.submit_value((rho_up - flux_momentum) * n, q);
375 velocity_p.submit_value((pp - flux_mass) * n, q);
376 }
377 }
378 else if(data.formulation == Formulation::SkewSymmetric)
379 {
380 scalar const flux_momentum_weak = flux_momentum * n;
381
382 pressure_m.submit_value(flux_momentum_weak, q);
383 velocity_m.submit_value((flux_mass - pm) * n, q);
384
385 if constexpr(weight_neighbor)
386 {
387 // minus signs since n⁺ = - n⁻
388 pressure_p.submit_value(-flux_momentum_weak, q);
389 velocity_p.submit_value((pp - flux_mass) * n, q);
390 }
391 }
392 else
393 {
394 AssertThrow(false, dealii::ExcMessage("Not implemented."));
395 }
396 }
397 }
398
399 void
400 cell_loop(dealii::MatrixFree<dim, Number> const & matrix_free_in,
401 BlockVectorType & dst,
402 BlockVectorType const & src,
403 Range const & cell_range) const
404 {
405 CellIntegratorP pressure(matrix_free_in, data.dof_index_pressure, data.quad_index);
406 CellIntegratorU velocity(matrix_free_in, data.dof_index_velocity, data.quad_index);
407
408 for(unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
409 {
410 pressure.reinit(cell);
411 pressure.gather_evaluate(src.block(data.block_index_pressure),
412 integrator_flags_p.cell_evaluate);
413
414 velocity.reinit(cell);
415 velocity.gather_evaluate(src.block(data.block_index_velocity),
416 integrator_flags_u.cell_evaluate);
417
418 do_cell_integral(pressure, velocity);
419
420 pressure.integrate_scatter(integrator_flags_p.cell_integrate,
421 dst.block(data.block_index_pressure));
422 velocity.integrate_scatter(integrator_flags_u.cell_integrate,
423 dst.block(data.block_index_velocity));
424 }
425 }
426
427 void
428 face_loop(dealii::MatrixFree<dim, Number> const & matrix_free_in,
429 BlockVectorType & dst,
430 BlockVectorType const & src,
431 Range const & face_range) const
432 {
433 FaceIntegratorP pressure_m(matrix_free_in, true, data.dof_index_pressure, data.quad_index);
434 FaceIntegratorP pressure_p(matrix_free_in, false, data.dof_index_pressure, data.quad_index);
435
436 FaceIntegratorU velocity_m(matrix_free_in, true, data.dof_index_velocity, data.quad_index);
437 FaceIntegratorU velocity_p(matrix_free_in, false, data.dof_index_velocity, data.quad_index);
438
439 for(unsigned int face = face_range.first; face < face_range.second; face++)
440 {
441 pressure_m.reinit(face);
442 pressure_m.gather_evaluate(src.block(data.block_index_pressure),
443 integrator_flags_p.face_evaluate);
444 pressure_p.reinit(face);
445 pressure_p.gather_evaluate(src.block(data.block_index_pressure),
446 integrator_flags_p.face_evaluate);
447
448 velocity_m.reinit(face);
449 velocity_m.gather_evaluate(src.block(data.block_index_velocity),
450 integrator_flags_u.face_evaluate);
451 velocity_p.reinit(face);
452 velocity_p.gather_evaluate(src.block(data.block_index_velocity),
453 integrator_flags_u.face_evaluate);
454
455 do_face_integral<true>(pressure_m, pressure_p, velocity_m, velocity_p);
456
457 pressure_m.integrate_scatter(integrator_flags_p.face_integrate,
458 dst.block(data.block_index_pressure));
459 pressure_p.integrate_scatter(integrator_flags_p.face_integrate,
460 dst.block(data.block_index_pressure));
461
462 velocity_m.integrate_scatter(integrator_flags_u.face_integrate,
463 dst.block(data.block_index_velocity));
464 velocity_p.integrate_scatter(integrator_flags_u.face_integrate,
465 dst.block(data.block_index_velocity));
466 }
467 }
468
469 void
470 boundary_face_loop(dealii::MatrixFree<dim, Number> const & matrix_free_in,
471 BlockVectorType & dst,
472 BlockVectorType const & src,
473 Range const & face_range) const
474 {
475 FaceIntegratorP pressure_m(matrix_free_in, true, data.dof_index_pressure, data.quad_index);
476 BoundaryFaceIntegratorP<dim, Number> pressure_p(pressure_m, *data.bc);
477
478 FaceIntegratorU velocity_m(matrix_free_in, true, data.dof_index_velocity, data.quad_index);
479 BoundaryFaceIntegratorU<dim, Number> velocity_p(velocity_m,
480 pressure_m,
481 data.speed_of_sound,
482 *data.bc);
483
484 for(unsigned int face = face_range.first; face < face_range.second; face++)
485 {
486 pressure_m.reinit(face);
487 pressure_m.gather_evaluate(src.block(data.block_index_pressure),
488 integrator_flags_p.face_evaluate);
489 pressure_p.reinit(face, evaluation_time);
490
491 velocity_m.reinit(face);
492 velocity_m.gather_evaluate(src.block(data.block_index_velocity),
493 integrator_flags_u.face_evaluate);
494 velocity_p.reinit(face, evaluation_time);
495
496 do_face_integral<false>(pressure_m, pressure_p, velocity_m, velocity_p);
497
498 pressure_m.integrate_scatter(integrator_flags_p.face_integrate,
499 dst.block(data.block_index_pressure));
500 velocity_m.integrate_scatter(integrator_flags_u.face_integrate,
501 dst.block(data.block_index_velocity));
502 }
503 }
504
506
507 mutable Number evaluation_time;
508
509 dealii::ObserverPointer<dealii::MatrixFree<dim, Number> const> matrix_free;
511
512 Number tau;
513 Number gamma;
514
515 IntegratorFlags integrator_flags_p;
516 IntegratorFlags integrator_flags_u;
517};
518
519} // namespace Acoustics
520} // namespace ExaDG
521
522#endif /* EXADG_ACOUSTIC_CONSERVATION_EQUATIONS_SPATIAL_DISCRETIZATION_OPERATORS_OPERATOR_H_ */
Definition weak_boundary_conditions.h:121
Definition weak_boundary_conditions.h:154
Definition operator.h:44
Definition driver.cpp:33
Definition operator.h:147
Definition integrator_flags.h:31
Definition mapping_flags.h:31