ExaDG
Loading...
Searching...
No Matches
weak_boundary_conditions.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_WEAK_BOUNDARY_CONDITIONS_H_
23#define EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_WEAK_BOUNDARY_CONDITIONS_H_
24
25// ExaDG
26#include <exadg/functions_and_boundary_conditions/evaluate_functions.h>
27#include <exadg/incompressible_navier_stokes/user_interface/boundary_descriptor.h>
28#include <exadg/incompressible_navier_stokes/user_interface/enum_types.h>
29#include <exadg/matrix_free/integrators.h>
30#include <exadg/operators/operator_type.h>
31
32namespace ExaDG
33{
34namespace IncNS
35{
36// clang-format off
37/*
38 * Velocity:
39 *
40 * The following two functions calculate the interior/exterior value for boundary faces depending on the
41 * operator type, the type of the boundary face and the given boundary conditions.
42 *
43 * +-------------------------+--------------------+------------------------------+
44 * | Dirichlet boundaries | Neumann boundaries | symmetry boundaries |
45 * +-------------------------+-------------------------+--------------------+------------------------------+
46 * | full operator | u⁺ = -u⁻ + 2g | u⁺ = u⁻ | u⁺ = u⁻ - 2 (u⁻*n)n |
47 * +-------------------------+-------------------------+--------------------+------------------------------+
48 * | homogeneous operator | u⁺ = -u⁻ | u⁺ = u⁻ | u⁺ = u⁻ - 2 (u⁻*n)n |
49 * +-------------------------+-------------------------+--------------------+------------------------------+
50 * | inhomogeneous operator | u⁺ = -u⁻ + 2g , u⁻ = 0 | u⁺ = u⁻ , u⁻ = 0 | u⁺ = u⁻ - 2 (u⁻*n)n , u⁻ = 0 |
51 * +-------------------------+-------------------------+--------------------+------------------------------+
52 *
53 */
54// clang-format on
55template<int dim, typename Number>
56inline DEAL_II_ALWAYS_INLINE //
57 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
58 calculate_interior_value(unsigned int const q,
59 FaceIntegrator<dim, dim, Number> const & integrator,
60 OperatorType const & operator_type)
61{
62 // element e⁻
63 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> value_m;
64
65 if(operator_type == OperatorType::full or operator_type == OperatorType::homogeneous)
66 {
67 value_m = integrator.get_value(q);
68 }
69 else if(operator_type == OperatorType::inhomogeneous)
70 {
71 // do nothing, value_m is already initialized with zeros
72 }
73 else
74 {
75 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
76 }
77
78 return value_m;
79}
80
81template<int dim, typename Number>
82inline DEAL_II_ALWAYS_INLINE //
83 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
84 calculate_exterior_value(dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> const & value_m,
85 unsigned int const q,
86 FaceIntegrator<dim, dim, Number> const & integrator,
87 OperatorType const & operator_type,
88 BoundaryTypeU const & boundary_type,
89 dealii::types::boundary_id const boundary_id,
90 std::shared_ptr<BoundaryDescriptorU<dim> const> boundary_descriptor,
91 double const & time)
92{
93 // element e⁺
94 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> value_p;
95
96 if(boundary_type == BoundaryTypeU::Dirichlet or boundary_type == BoundaryTypeU::DirichletCached)
97 {
98 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
99 {
100 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> g;
101
102 if(boundary_type == BoundaryTypeU::Dirichlet)
103 {
104 auto bc = boundary_descriptor->dirichlet_bc.find(boundary_id)->second;
105 auto q_points = integrator.quadrature_point(q);
106
107 g = FunctionEvaluator<1, dim, Number>::value(*bc, q_points, time);
108 }
109 else if(boundary_type == BoundaryTypeU::DirichletCached)
110 {
111 auto bc = boundary_descriptor->get_dirichlet_cached_data();
112 g = FunctionEvaluator<1, dim, Number>::value(*bc,
113 integrator.get_current_cell_index(),
114 q,
115 integrator.get_quadrature_index());
116 }
117 else
118 {
119 AssertThrow(false, dealii::ExcMessage("Not implemented."));
120 }
121
122 value_p = -value_m + dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>(2.0 * g);
123 }
124 else if(operator_type == OperatorType::homogeneous)
125 {
126 value_p = -value_m;
127 }
128 else
129 {
130 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
131 }
132 }
133 else if(boundary_type == BoundaryTypeU::Neumann)
134 {
135 value_p = value_m;
136 }
137 else if(boundary_type == BoundaryTypeU::Symmetry)
138 {
139 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> normal_m = integrator.normal_vector(q);
140
141 value_p = value_m - 2.0 * (value_m * normal_m) * normal_m;
142 }
143 else
144 {
145 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
146 }
147
148 return value_p;
149}
150
151/*
152 * This function calculates the exterior velocity on boundary faces
153 * according to:
154 *
155 * Dirichlet boundary: u⁺ = -u⁻ + 2g (mirror) or g (direct)
156 * Neumann boundary: u⁺ = u⁻
157 * symmetry boundary: u⁺ = u⁻ -(u⁻*n)n - (u⁻*n)n = u⁻ - 2 (u⁻*n)n
158 *
159 * The name "convective" indicates that this function is used when
160 * evaluating the convective operator.
161 *
162 * OperatorType:
163 * - To evaluate the nonlinear convective term (residual evaluation), use OperatorType::full.
164 * - To evaluate the linearization of the nonlinear convective term, use OperatorType::homogeneous.
165 * - To evaluate the linearly implicit convective term, use OperatorType::homogeneous for the
166 * "matrix-vector" product and OperatorType::inhomogeneous for the "rhs" contribution.
167 */
168template<int dim, typename Number>
169inline DEAL_II_ALWAYS_INLINE //
170 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
171 calculate_exterior_value_convective(
172 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> const & u_m,
173 unsigned int const q,
174 FaceIntegrator<dim, dim, Number> & integrator,
175 OperatorType const & operator_type,
176 BoundaryTypeU const & boundary_type,
177 TypeDirichletBCs const & type_dirichlet_bc,
178 dealii::types::boundary_id const boundary_id,
179 std::shared_ptr<BoundaryDescriptorU<dim> const> boundary_descriptor,
180 double const & time)
181{
182 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> u_p;
183
184 if(boundary_type == BoundaryTypeU::Dirichlet or boundary_type == BoundaryTypeU::DirichletCached)
185 {
186 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> g;
187
188 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
189 {
190 if(boundary_type == BoundaryTypeU::Dirichlet)
191 {
192 auto bc = boundary_descriptor->dirichlet_bc.find(boundary_id)->second;
193 auto q_points = integrator.quadrature_point(q);
194
195 g = FunctionEvaluator<1, dim, Number>::value(*bc, q_points, time);
196 }
197 else if(boundary_type == BoundaryTypeU::DirichletCached)
198 {
199 auto bc = boundary_descriptor->get_dirichlet_cached_data();
200 g = FunctionEvaluator<1, dim, Number>::value(*bc,
201 integrator.get_current_cell_index(),
202 q,
203 integrator.get_quadrature_index());
204 }
205 else
206 {
207 AssertThrow(false, dealii::ExcMessage("Not implemented."));
208 }
209 }
210
211 if(type_dirichlet_bc == TypeDirichletBCs::Mirror)
212 {
213 u_p = -u_m + dealii::make_vectorized_array<Number>(2.0) * g;
214 }
215 else if(type_dirichlet_bc == TypeDirichletBCs::Direct)
216 {
217 u_p = g;
218 }
219 else
220 {
221 AssertThrow(false, dealii::ExcMessage("TypeDirichletBCs is not implemented."));
222 }
223 }
224 else if(boundary_type == BoundaryTypeU::Neumann)
225 {
226 u_p = u_m;
227 }
228 else if(boundary_type == BoundaryTypeU::Symmetry)
229 {
230 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> normal_m = integrator.normal_vector(q);
231
232 u_p = u_m - 2. * (u_m * normal_m) * normal_m;
233 }
234 else
235 {
236 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
237 }
238
239 return u_p;
240}
241
242template<int dim, typename Number>
243inline DEAL_II_ALWAYS_INLINE //
244 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
245 calculate_exterior_value_from_dof_vector(
246 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> const & value_m,
247 unsigned int const q,
248 FaceIntegrator<dim, dim, Number> const & integrator_bc,
249 OperatorType const & operator_type,
250 BoundaryTypeU const & boundary_type)
251{
252 // element e⁺
253 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> value_p;
254
255 if(boundary_type == BoundaryTypeU::Dirichlet or boundary_type == BoundaryTypeU::DirichletCached)
256 {
257 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
258 {
259 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> g = integrator_bc.get_value(q);
260
261 value_p = -value_m + dealii::make_vectorized_array<Number>(2.0) * g;
262 }
263 else if(operator_type == OperatorType::homogeneous)
264 {
265 value_p = -value_m;
266 }
267 else
268 {
269 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
270 }
271 }
272 else if(boundary_type == BoundaryTypeU::Neumann)
273 {
274 value_p = value_m;
275 }
276 else if(boundary_type == BoundaryTypeU::Symmetry)
277 {
278 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> normal_m =
279 integrator_bc.normal_vector(q);
280
281 value_p = value_m - 2.0 * (value_m * normal_m) * normal_m;
282 }
283 else
284 {
285 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
286 }
287
288 return value_p;
289}
290
291/*
292 * Pressure:
293 *
294 * These two function calculate the interior/exterior value on boundary faces depending on the
295 * operator type, the type of the boundary face and the given boundary conditions.
296 *
297 * +--------------------+----------------------+
298 * | Neumann boundaries | Dirichlet boundaries |
299 * +-------------------------+--------------------+----------------------+
300 * | full operator | p⁺ = p⁻ | p⁺ = - p⁻ + 2g |
301 * +-------------------------+--------------------+----------------------+
302 * | homogeneous operator | p⁺ = p⁻ | p⁺ = - p⁻ |
303 * +-------------------------+--------------------+----------------------+
304 * | inhomogeneous operator | p⁺ = 0 , p⁻ = 0 | p⁺ = 2g , p⁻ = 0 |
305 * +-------------------------+--------------------+----------------------+
306 *
307 */
308template<int dim, typename Number>
309inline DEAL_II_ALWAYS_INLINE //
310 dealii::VectorizedArray<Number>
311 calculate_interior_value(unsigned int const q,
312 FaceIntegrator<dim, 1, Number> const & integrator,
313 OperatorType const & operator_type)
314{
315 // element e⁻
316 dealii::VectorizedArray<Number> value_m = dealii::make_vectorized_array<Number>(0.0);
317
318 if(operator_type == OperatorType::full or operator_type == OperatorType::homogeneous)
319 {
320 value_m = integrator.get_value(q);
321 }
322 else if(operator_type == OperatorType::inhomogeneous)
323 {
324 // do nothing, value_m is already initialized with zeros
325 }
326 else
327 {
328 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
329 }
330
331 return value_m;
332}
333
334
335template<int dim, typename Number>
336inline DEAL_II_ALWAYS_INLINE //
337 dealii::VectorizedArray<Number>
338 calculate_exterior_value(dealii::VectorizedArray<Number> const & value_m,
339 unsigned int const q,
340 FaceIntegrator<dim, 1, Number> const & integrator,
341 OperatorType const & operator_type,
342 BoundaryTypeP const & boundary_type,
343 dealii::types::boundary_id const boundary_id,
344 std::shared_ptr<BoundaryDescriptorP<dim> const> boundary_descriptor,
345 double const & time,
346 double const & inverse_scaling_factor)
347{
348 dealii::VectorizedArray<Number> value_p = dealii::make_vectorized_array<Number>(0.0);
349
350 if(boundary_type == BoundaryTypeP::Dirichlet)
351 {
352 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
353 {
354 auto bc = boundary_descriptor->dirichlet_bc.find(boundary_id)->second;
355 auto q_points = integrator.quadrature_point(q);
356
357 dealii::VectorizedArray<Number> g =
358 FunctionEvaluator<0, dim, Number>::value(*bc, q_points, time);
359
360 value_p = -value_m + 2.0 * inverse_scaling_factor * g;
361 }
362 else if(operator_type == OperatorType::homogeneous)
363 {
364 value_p = -value_m;
365 }
366 else
367 {
368 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
369 }
370 }
371 else if(boundary_type == BoundaryTypeP::Neumann)
372 {
373 value_p = value_m;
374 }
375 else
376 {
377 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
378 }
379
380 return value_p;
381}
382
383template<int dim, typename Number>
384inline DEAL_II_ALWAYS_INLINE //
385 dealii::VectorizedArray<Number>
386 calculate_exterior_value_from_dof_vector(dealii::VectorizedArray<Number> const & value_m,
387 unsigned int const q,
388 FaceIntegrator<dim, 1, Number> const & integrator_bc,
389 OperatorType const & operator_type,
390 BoundaryTypeP const & boundary_type,
391 double const & inverse_scaling_factor)
392{
393 dealii::VectorizedArray<Number> value_p = dealii::make_vectorized_array<Number>(0.0);
394
395 if(boundary_type == BoundaryTypeP::Dirichlet)
396 {
397 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
398 {
399 dealii::VectorizedArray<Number> g = integrator_bc.get_value(q);
400
401 value_p = -value_m + 2.0 * inverse_scaling_factor * g;
402 }
403 else if(operator_type == OperatorType::homogeneous)
404 {
405 value_p = -value_m;
406 }
407 else
408 {
409 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
410 }
411 }
412 else if(boundary_type == BoundaryTypeP::Neumann)
413 {
414 value_p = value_m;
415 }
416 else
417 {
418 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
419 }
420
421 return value_p;
422}
423
424// clang-format off
425/*
426 * This function calculates the exterior velocity gradient in normal direction depending
427 * on the operator type, the type of the boundary face and the given boundary conditions.
428 *
429 * The function argument normal_gradient_m has the meaning of F(u⁻)*n with
430 *
431 * Divergence formulation: F(u) = F_nu(u) / nu = ( grad(u) + grad(u)^T )
432 * Laplace formulation: F(u) = F_nu(u) / nu = grad(u)
433 *
434 * +---------------------------------+---------------------------------------+----------------------------------------------------+
435 * | Dirichlet boundaries | Neumann boundaries | symmetry boundaries |
436 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
437 * | full operator | F(u⁺)*n = F(u⁻)*n | F(u⁺)*n = -F(u⁻)*n + 2h | F(u⁺)*n = -F(u⁻)*n + 2*[(F(u⁻)*n)*n]n |
438 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
439 * | homogeneous operator | F(u⁺)*n = F(u⁻)*n | F(u⁺)*n = -F(u⁻)*n | F(u⁺)*n = -F(u⁻)*n + 2*[(F(u⁻)*n)*n]n |
440 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
441 * | inhomogeneous operator | F(u⁺)*n = F(u⁻)*n, F(u⁻)*n = 0 | F(u⁺)*n = -F(u⁻)*n + 2h , F(u⁻)*n = 0 | F(u⁺)*n = -F(u⁻)*n + 2*[(F(u⁻)*n)*n]n, F(u⁻)*n = 0 |
442 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
443 *
444 * +---------------------------------+---------------------------------------+----------------------------------------------------+
445 * | Dirichlet boundaries | Neumann boundaries | symmetry boundaries |
446 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
447 * | full operator | {{F(u)}}*n = F(u⁻)*n | {{F(u)}}*n = h | {{F(u)}}*n = [(F(u⁻)*n)*n]n |
448 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
449 * | homogeneous operator | {{F(u)}}*n = F(u⁻)*n | {{F(u)}}*n = 0 | {{F(u)}}*n = [(F(u⁻)*n)*n]n |
450 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
451 * | inhomogeneous operator | {{F(u)}}*n = 0 | {{F(u)}}*n = h | {{F(u)}}*n = 0 |
452 * +-------------------------+---------------------------------+---------------------------------------+----------------------------------------------------+
453 */
454// clang-format on
455
456template<int dim, typename Number>
457inline DEAL_II_ALWAYS_INLINE //
458 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>>
459 calculate_exterior_normal_gradient(
460 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> const & normal_gradient_m,
461 unsigned int const q,
462 FaceIntegrator<dim, dim, Number> const & integrator,
463 OperatorType const & operator_type,
464 BoundaryTypeU const & boundary_type,
465 dealii::types::boundary_id const boundary_id,
466 std::shared_ptr<BoundaryDescriptorU<dim> const> boundary_descriptor,
467 double const & time,
468 bool const variable_normal_vector)
469{
470 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> normal_gradient_p;
471
472 if(boundary_type == BoundaryTypeU::Dirichlet or boundary_type == BoundaryTypeU::DirichletCached)
473 {
474 normal_gradient_p = normal_gradient_m;
475 }
476 else if(boundary_type == BoundaryTypeU::Neumann)
477 {
478 if(operator_type == OperatorType::full or operator_type == OperatorType::inhomogeneous)
479 {
480 auto bc = boundary_descriptor->neumann_bc.find(boundary_id)->second;
481 auto q_points = integrator.quadrature_point(q);
482
483 dealii::Tensor<1, dim, dealii::VectorizedArray<Number>> h;
484 if(variable_normal_vector == false)
485 {
486 h = FunctionEvaluator<1, dim, Number>::value(*bc, q_points, time);
487 }
488 else
489 {
490 auto normals_m = integrator.normal_vector(q);
491 h = FunctionEvaluator<1, dim, Number>::value(
492 *(std::dynamic_pointer_cast<FunctionWithNormal<dim>>(bc)), q_points, normals_m, time);
493 }
494
495 normal_gradient_p = -normal_gradient_m + 2.0 * h;
496 }
497 else if(operator_type == OperatorType::homogeneous)
498 {
499 normal_gradient_p = -normal_gradient_m;
500 }
501 else
502 {
503 AssertThrow(false, dealii::ExcMessage("Specified OperatorType is not implemented!"));
504 }
505 }
506 else if(boundary_type == BoundaryTypeU::Symmetry)
507 {
508 auto normal_m = integrator.normal_vector(q);
509 normal_gradient_p = -normal_gradient_m + 2.0 * (normal_gradient_m * normal_m) * normal_m;
510 }
511 else
512 {
513 AssertThrow(false, dealii::ExcMessage("Boundary type of face is invalid or not implemented."));
514 }
515
516 return normal_gradient_p;
517}
518
519} // namespace IncNS
520} // namespace ExaDG
521
522#endif /* EXADG_INCOMPRESSIBLE_NAVIER_STOKES_SPATIAL_DISCRETIZATION_OPERATORS_WEAK_BOUNDARY_CONDITIONS_H_ \
523 */
Definition driver.cpp:33
Definition boundary_descriptor.h:191
Definition boundary_descriptor.h:81