MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
hyperbolic.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12// Implementation of hyperbolic conservation laws
13
14#include "hyperbolic.hpp"
15#include "nonlinearform.hpp"
16#include "pnonlinearform.hpp"
17
18namespace mfem
19{
20
22 const NumericalFlux &numFlux,
23 const int IntOrderOffset,
24 real_t sign)
26 numFlux(numFlux),
27 fluxFunction(numFlux.GetFluxFunction()),
28 IntOrderOffset(IntOrderOffset),
29 sign(sign),
30 num_equations(fluxFunction.num_equations)
31{
32#ifndef MFEM_THREAD_SAFE
34 flux.SetSize(num_equations, fluxFunction.dim);
35 state1.SetSize(num_equations);
36 state2.SetSize(num_equations);
39 nor.SetSize(fluxFunction.dim);
40#endif
42}
43
46 const Vector &elfun,
47 Vector &elvect)
48{
49 // current element's the number of degrees of freedom
50 // does not consider the number of equations
51 const int dof = el.GetDof();
52
53#ifdef MFEM_THREAD_SAFE
54 // Local storage for element integration
55
56 // shape function value at an integration point
57 Vector shape(dof);
58 // derivative of shape function at an integration point
59 DenseMatrix dshape(dof, Tr.GetSpaceDim());
60 // state value at an integration point
61 Vector state(num_equations);
62 // flux value at an integration point
64#else
65 // resize shape and gradient shape storage
66 shape.SetSize(dof);
67 dshape.SetSize(dof, Tr.GetSpaceDim());
68#endif
69
70 // setDegree-up output vector
71 elvect.SetSize(dof * num_equations);
72 elvect = 0.0;
73
74 // make state variable and output dual vector matrix form.
75 const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
76 DenseMatrix elvect_mat(elvect.GetData(), dof, num_equations);
77
78 // obtain integration rule. If integration is rule is given, then use it.
79 // Otherwise, get (2*p + IntOrderOffset) order integration rule
80 const IntegrationRule *ir = IntRule;
81 if (!ir)
82 {
83 const int order = el.GetOrder()*2 + IntOrderOffset;
84 ir = &IntRules.Get(Tr.GetGeometryType(), order);
85 }
86
87 // loop over integration points
88 for (int i = 0; i < ir->GetNPoints(); i++)
89 {
90 const IntegrationPoint &ip = ir->IntPoint(i);
91 Tr.SetIntPoint(&ip);
92
93 el.CalcShape(ip, shape);
94 el.CalcPhysDShape(Tr, dshape);
95 // compute current state value with given shape function values
96 elfun_mat.MultTranspose(shape, state);
97 // compute F(u,x) and point maximum characteristic speed
98
99 const real_t mcs = fluxFunction.ComputeFlux(state, Tr, flux);
100 // update maximum characteristic speed
101 max_char_speed = std::max(mcs, max_char_speed);
102 // integrate (F(u,x), grad v)
103 AddMult_a_ABt(ip.weight * Tr.Weight() * sign, dshape, flux, elvect_mat);
104 }
105}
106
108 const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
109 DenseMatrix &grad)
110{
111 // current element's the number of degrees of freedom
112 // does not consider the number of equations
113 const int dof = el.GetDof();
114
115#ifdef MFEM_THREAD_SAFE
116 // Local storage for element integration
117
118 // shape function value at an integration point
119 Vector shape(dof);
120 // derivative of shape function at an integration point
121 DenseMatrix dshape(dof, Tr.GetSpaceDim());
122 // state value at an integration point
123 Vector state(num_equations);
124 // Jacobian value at an integration point
125 DenseTensor J(num_equations, num_equations, fluxFunction.dim);
126#else
127 // resize shape, gradient shape and Jacobian storage
128 shape.SetSize(dof);
129 dshape.SetSize(dof, Tr.GetSpaceDim());
130 J.SetSize(num_equations, num_equations, fluxFunction.dim);
131#endif
132
133 // setup output gradient matrix
134 grad.SetSize(dof * num_equations);
135 grad = 0.0;
136
137 // make state variable and output dual vector matrix form.
138 const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
139 //DenseMatrix elvect_mat(elvect.GetData(), dof, num_equations);
140
141 // obtain integration rule. If integration is rule is given, then use it.
142 // Otherwise, get (2*p + IntOrderOffset) order integration rule
143 const IntegrationRule *ir = IntRule;
144 if (!ir)
145 {
146 const int order = el.GetOrder()*2 + IntOrderOffset;
147 ir = &IntRules.Get(Tr.GetGeometryType(), order);
148 }
149
150 // loop over integration points
151 for (int q = 0; q < ir->GetNPoints(); q++)
152 {
153 const IntegrationPoint &ip = ir->IntPoint(q);
154 Tr.SetIntPoint(&ip);
155
156 el.CalcShape(ip, shape);
157 el.CalcPhysDShape(Tr, dshape);
158 // compute current state value with given shape function values
159 elfun_mat.MultTranspose(shape, state);
160
161 // compute J(u,x)
162 fluxFunction.ComputeFluxJacobian(state, Tr, J);
163
164 // integrate (J(u,x), grad v)
165 const real_t w = ip.weight * Tr.Weight() * sign;
166 for (int di = 0; di < num_equations; di++)
167 for (int dj = 0; dj < num_equations; dj++)
168 for (int i = 0; i < dof; i++)
169 for (int j = 0; j < dof; j++)
170 for (int d = 0; d < fluxFunction.dim; d++)
171 {
172 grad(di*dof+i, dj*dof+j) += w * dshape(i,d) * shape(j) * J(di,dj,d);
173 }
174 }
175}
176
178 const FiniteElement &el1, const FiniteElement &el2,
179 FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
180{
181 // current elements' the number of degrees of freedom
182 // does not consider the number of equations
183 const int dof1 = el1.GetDof();
184 const int dof2 = el2.GetDof();
185
186#ifdef MFEM_THREAD_SAFE
187 // Local storage for element integration
188
189 // shape function value at an integration point - first elem
190 Vector shape1(dof1);
191 // shape function value at an integration point - second elem
192 Vector shape2(dof2);
193 // normal vector (usually not a unit vector)
194 Vector nor(Tr.GetSpaceDim());
195 // state value at an integration point - first elem
196 Vector state1(num_equations);
197 // state value at an integration point - second elem
198 Vector state2(num_equations);
199 // hat(F)(u,x)
200 Vector fluxN(num_equations);
201#else
202 shape1.SetSize(dof1);
203 shape2.SetSize(dof2);
204#endif
205
206 elvect.SetSize((dof1 + dof2) * num_equations);
207 elvect = 0.0;
208
209 const DenseMatrix elfun1_mat(elfun.GetData(), dof1, num_equations);
210 const DenseMatrix elfun2_mat(elfun.GetData() + dof1 * num_equations, dof2,
212
213 DenseMatrix elvect1_mat(elvect.GetData(), dof1, num_equations);
214 DenseMatrix elvect2_mat(elvect.GetData() + dof1 * num_equations, dof2,
216
217 // Obtain integration rule. If integration is rule is given, then use it.
218 // Otherwise, get (2*p + IntOrderOffset) order integration rule
219 const IntegrationRule *ir = IntRule;
220 if (!ir)
221 {
222 const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
223 ir = &IntRules.Get(Tr.GetGeometryType(), order);
224 }
225 // loop over integration points
226 for (int i = 0; i < ir->GetNPoints(); i++)
227 {
228 const IntegrationPoint &ip = ir->IntPoint(i);
229
230 Tr.SetAllIntPoints(&ip); // set face and element int. points
231
232 // Calculate basis functions on both elements at the face
233 el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
234 el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
235
236 // Interpolate elfun at the point
237 elfun1_mat.MultTranspose(shape1, state1);
238 elfun2_mat.MultTranspose(shape2, state2);
239
240 // Get the normal vector and the flux on the face
241 if (nor.Size() == 1) // if 1D, use 1 or -1.
242 {
243 // This assume the 1D integration point is in (0,1). This may not work
244 // if this changes.
245 nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
246 }
247 else
248 {
249 CalcOrtho(Tr.Jacobian(), nor);
250 }
251 // Compute F(u+, x) and F(u-, x) with maximum characteristic speed
252 // Compute hat(F) using evaluated quantities
253 const real_t speed = numFlux.Eval(state1, state2, nor, Tr, fluxN);
254
255 // Update the global max char speed
256 max_char_speed = std::max(speed, max_char_speed);
257
258 // pre-multiply integration weight to flux
259 AddMult_a_VWt(-ip.weight*sign, shape1, fluxN, elvect1_mat);
260 AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
261 }
262}
263
265 const FiniteElement &el1, const FiniteElement &el2,
266 FaceElementTransformations &Tr, const Vector &elfun, DenseMatrix &elmat)
267{
268 // current elements' the number of degrees of freedom
269 // does not consider the number of equations
270 const int dof1 = el1.GetDof();
271 const int dof2 = el2.GetDof();
272
273#ifdef MFEM_THREAD_SAFE
274 // Local storage for element integration
275
276 // shape function value at an integration point - first elem
277 Vector shape1(dof1);
278 // shape function value at an integration point - second elem
279 Vector shape2(dof2);
280 // normal vector (usually not a unit vector)
281 Vector nor(Tr.GetSpaceDim());
282 // state value at an integration point - first elem
283 Vector state1(num_equations);
284 // state value at an integration point - second elem
285 Vector state2(num_equations);
286 // hat(J)(u,x)
288#else
289 shape1.SetSize(dof1);
290 shape2.SetSize(dof2);
291#endif
292
293 elmat.SetSize((dof1 + dof2) * num_equations);
294 elmat = 0.0;
295
296 const DenseMatrix elfun1_mat(elfun.GetData(), dof1, num_equations);
297 const DenseMatrix elfun2_mat(elfun.GetData() + dof1 * num_equations, dof2,
299
300 // Obtain integration rule. If integration is rule is given, then use it.
301 // Otherwise, get (2*p + IntOrderOffset) order integration rule
302 const IntegrationRule *ir = IntRule;
303 if (!ir)
304 {
305 const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
306 ir = &IntRules.Get(Tr.GetGeometryType(), order);
307 }
308 // loop over integration points
309 for (int q = 0; q < ir->GetNPoints(); q++)
310 {
311 const IntegrationPoint &ip = ir->IntPoint(q);
312
313 Tr.SetAllIntPoints(&ip); // set face and element int. points
314
315 // Calculate basis functions on both elements at the face
316 el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
317 el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
318
319 // Interpolate elfun at the point
320 elfun1_mat.MultTranspose(shape1, state1);
321 elfun2_mat.MultTranspose(shape2, state2);
322
323 // Get the normal vector and the flux on the face
324 if (nor.Size() == 1) // if 1D, use 1 or -1.
325 {
326 // This assume the 1D integration point is in (0,1). This may not work
327 // if this changes.
328 nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
329 }
330 else
331 {
332 CalcOrtho(Tr.Jacobian(), nor);
333 }
334
335 // Trial side 1
336
337 // Compute hat(J) using evaluated quantities
338 numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
339
340 const int ioff = fluxFunction.num_equations * dof1;
341
342 for (int di = 0; di < fluxFunction.num_equations; di++)
343 for (int dj = 0; dj < fluxFunction.num_equations; dj++)
344 {
345 // pre-multiply integration weight to Jacobian
346 const real_t w = -ip.weight * sign * JDotN(di,dj);
347 for (int j = 0; j < dof1; j++)
348 {
349 // Test side 1
350 for (int i = 0; i < dof1; i++)
351 {
352 elmat(i+dof1*di, j+dof1*dj) += w * shape1(i) * shape1(j);
353 }
354
355 // Test side 2
356 for (int i = 0; i < dof2; i++)
357 {
358 elmat(ioff+i+dof2*di, j+dof1*dj) -= w * shape2(i) * shape1(j);
359 }
360 }
361 }
362
363 // Trial side 2
364
365 // Compute hat(J) using evaluated quantities
366 numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
367
368 const int joff = ioff;
369
370 for (int di = 0; di < fluxFunction.num_equations; di++)
371 for (int dj = 0; dj < fluxFunction.num_equations; dj++)
372 {
373 // pre-multiply integration weight to Jacobian
374 const real_t w = +ip.weight * sign * JDotN(di,dj);
375 for (int j = 0; j < dof2; j++)
376 {
377 // Test side 1
378 for (int i = 0; i < dof1; i++)
379 {
380 elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
381 }
382
383 // Test side 2
384 for (int i = 0; i < dof2; i++)
385 {
386 elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
387 }
388 }
389 }
390 }
391}
392
394 const Vector &normal,
396 Vector &FUdotN) const
397{
398#ifdef MFEM_THREAD_SAFE
400#else
402#endif
403 real_t val = ComputeFlux(U, Tr, flux);
404 flux.Mult(normal, FUdotN);
405 return val;
406}
407
409 const Vector &normal,
411 Vector &fluxDotN) const
412{
413#ifdef MFEM_THREAD_SAFE
415#else
417#endif
418 real_t val = ComputeAvgFlux(U1, U2, Tr, flux);
419 flux.Mult(normal, fluxDotN);
420 return val;
421}
422
424 const Vector &normal,
426 DenseMatrix &JDotN) const
427{
428#ifdef MFEM_THREAD_SAFE
430#else
432#endif
433 ComputeFluxJacobian(U, Tr, J);
434 JDotN.Set(normal(0), J(0));
435 for (int d = 1; d < dim; d++)
436 {
437 JDotN.AddMatrix(normal(d), J(d), 0, 0);
438 }
439}
440
442 : NumericalFlux(fluxFunction)
443{
444#ifndef MFEM_THREAD_SAFE
447#endif
448}
449
450real_t RusanovFlux::Eval(const Vector &state1, const Vector &state2,
451 const Vector &nor, FaceElementTransformations &Tr,
452 Vector &flux) const
453{
454#ifdef MFEM_THREAD_SAFE
456#endif
457 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
458 const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
459 // NOTE: nor in general is not a unit normal
460 const real_t maxE = std::max(speed1, speed2);
461 // here, nor.Norml2() is multiplied to match the scale with fluxN
462 const real_t scaledMaxE = maxE * nor.Norml2();
463 for (int i = 0; i < fluxFunction.num_equations; i++)
464 {
465 flux(i) = 0.5*(scaledMaxE*(state1(i) - state2(i)) + (fluxN1(i) + fluxN2(i)));
466 }
467 return maxE;
468}
469
470void RusanovFlux::Grad(int side, const Vector &state1, const Vector &state2,
471 const Vector &nor, FaceElementTransformations &Tr,
472 DenseMatrix &grad) const
473{
474#ifdef MFEM_THREAD_SAFE
476#endif
477
478 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
479 const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
480
481 // NOTE: nor in general is not a unit normal
482 const real_t maxE = std::max(speed1, speed2);
483 // here, nor.Norml2() is multiplied to match the scale with fluxN
484 const real_t scaledMaxE = maxE * nor.Norml2();
485
486 if (side == 1)
487 {
488 fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, grad);
489
490 for (int i = 0; i < fluxFunction.num_equations; i++)
491 {
492 grad(i,i) += 0.5 * scaledMaxE;
493 }
494 }
495 else
496 {
497 fluxFunction.ComputeFluxJacobianDotN(state2, nor, Tr, grad);
498
499 for (int i = 0; i < fluxFunction.num_equations; i++)
500 {
501 grad(i,i) -= 0.5 * scaledMaxE;
502 }
503 }
504}
505
506real_t RusanovFlux::Average(const Vector &state1, const Vector &state2,
507 const Vector &nor, FaceElementTransformations &Tr,
508 Vector &flux) const
509{
510#ifdef MFEM_THREAD_SAFE
512#endif
513 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
514 const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
515 fluxN2);
516 // NOTE: nor in general is not a unit normal
517 const real_t maxE = std::max(speed1, speed2);
518 // here, nor.Norml2() is multiplied to match the scale with fluxN
519 const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
520 for (int i = 0; i < fluxFunction.num_equations; i++)
521 {
522 flux(i) = 0.5*(scaledMaxE*(state1(i) - state2(i)) + (fluxN1(i) + fluxN2(i)));
523 }
524 return maxE;
525}
526
527void RusanovFlux::AverageGrad(int side, const Vector &state1,
528 const Vector &state2,
529 const Vector &nor, FaceElementTransformations &Tr,
530 DenseMatrix &grad) const
531{
532#ifdef MFEM_THREAD_SAFE
534#endif
535
536#if defined(MFEM_USE_DOUBLE)
537 constexpr real_t tol = 1e-12;
538#elif defined(MFEM_USE_SINGLE)
539 constexpr real_t tol = 4e-6;
540#else
541#error "Only single and double precision are supported!"
542 constexpr real_t tol = 1.;
543#endif
544
545 auto equal_check = [=](real_t a, real_t b) -> bool { return std::abs(a - b) <= tol * std::abs(a + b); };
546
547 if (side == 1)
548 {
549#ifdef MFEM_THREAD_SAFE
551#else
553#endif
554 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
555 const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
556 fluxN2);
558
559 // NOTE: nor in general is not a unit normal
560 const real_t maxE = std::max(speed1, speed2);
561 // here, nor.Norml2() is multiplied to match the scale with fluxN
562 const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
563
564 grad = 0.;
565
566 for (int i = 0; i < fluxFunction.num_equations; i++)
567 {
568 // Only diagonal terms of J are considered
569 // lim_{u → u⁻} (F̄(u⁻,u)n - F(u⁻)n) / (u - u⁻) = ½λ
570 if (equal_check(state1(i), state2(i))) { continue; }
571 grad(i,i) = 0.5 * ((fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
572 - JDotN(i,i) + scaledMaxE);
573 }
574 }
575 else
576 {
577 const real_t speed1 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
578 fluxN1);
579 const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
580
581 // NOTE: nor in general is not a unit normal
582 const real_t maxE = std::max(speed1, speed2);
583 // here, nor.Norml2() is multiplied to match the scale with fluxN
584 const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
585
586 grad = 0.;
587
588 for (int i = 0; i < fluxFunction.num_equations; i++)
589 {
590 // lim_{u → u⁻} (F(u)n - F̄(u⁻,u)n) / (u - u⁻) = ½λ
591 if (equal_check(state1(i), state2(i))) { continue; }
592 grad(i,i) = 0.5 * ((fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
593 - scaledMaxE);
594 }
595 }
596}
597
599 const FluxFunction &fluxFunction)
600 : NumericalFlux(fluxFunction)
601{
602#ifndef MFEM_THREAD_SAFE
605#endif
606 if (fluxFunction.dim > 1)
607 MFEM_WARNING("Upwinded flux is implemented only component-wise.")
608 }
609
611 const Vector &nor, FaceElementTransformations &Tr,
612 Vector &flux) const
613{
614#ifdef MFEM_THREAD_SAFE
616#endif
617 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
618 const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
619
620 for (int i = 0; i < fluxFunction.num_equations; i++)
621 {
622 if (state1(i) <= state2(i))
623 {
624 flux(i) = std::min(fluxN1(i), fluxN2(i));
625 }
626 else
627 {
628 flux(i) = std::max(fluxN1(i), fluxN2(i));
629 }
630 }
631
632 return std::max(speed1, speed2);
633}
634
635void ComponentwiseUpwindFlux::Grad(int side, const Vector &state1,
636 const Vector &state2,
637 const Vector &nor, FaceElementTransformations &Tr,
638 DenseMatrix &grad) const
639{
640#ifdef MFEM_THREAD_SAFE
642#else
644#endif
645
646 grad = 0.;
647
648 if (side == 1)
649 {
651
652 for (int i = 0; i < fluxFunction.num_equations; i++)
653 {
654 // Only diagonal terms of J are considered
655 grad(i,i) = std::max(JDotN(i,i), 0_r);
656 }
657 }
658 else
659 {
661
662 for (int i = 0; i < fluxFunction.num_equations; i++)
663 {
664 // Only diagonal terms of J are considered
665 grad(i,i) = std::min(JDotN(i,i), 0_r);
666 }
667 }
668}
669
671 const Vector &state2,
672 const Vector &nor, FaceElementTransformations &Tr,
673 Vector &flux) const
674{
675#ifdef MFEM_THREAD_SAFE
677#endif
678 const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
679 const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
680 fluxN2);
681
682 for (int i = 0; i < fluxFunction.num_equations; i++)
683 {
684 if (state1(i) <= state2(i))
685 {
686 flux(i) = std::min(fluxN1(i), fluxN2(i));
687 }
688 else
689 {
690 flux(i) = std::max(fluxN1(i), fluxN2(i));
691 }
692 }
693
694 return std::max(speed1, speed2);
695}
696
697void ComponentwiseUpwindFlux::AverageGrad(int side, const Vector &state1,
698 const Vector &state2,
699 const Vector &nor, FaceElementTransformations &Tr,
700 DenseMatrix &grad) const
701{
702#ifdef MFEM_THREAD_SAFE
704#endif
705
706#if defined(MFEM_USE_DOUBLE)
707 constexpr real_t tol = 1e-12;
708#elif defined(MFEM_USE_SINGLE)
709 constexpr real_t tol = 4e-6;
710#else
711#error "Only single and double precision are supported!"
712 constexpr real_t tol = 1.;
713#endif
714
715 auto equal_check = [=](real_t a, real_t b) -> bool { return std::abs(a - b) <= tol * std::abs(a + b); };
716
717 if (side == 1)
718 {
719#ifdef MFEM_THREAD_SAFE
721#else
723#endif
724 fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
725 fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr, fluxN2);
727
728 grad = 0.;
729
730 for (int i = 0; i < fluxFunction.num_equations; i++)
731 {
732 // Only diagonal terms of J are considered
733 // lim_{u → u⁻} (F̄(u⁻,u)n - F(u⁻)n) / (u - u⁻) = ½J(u⁻)n
734 const real_t gr12 = (!equal_check(state1(i), state2(i)))?
735 (fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
736 :(0.5 * JDotN(i,i));
737 grad(i,i) = (gr12 >= 0.)?(JDotN(i,i)):(gr12);
738 }
739 }
740 else
741 {
742#ifdef MFEM_THREAD_SAFE
744#endif
745 fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr, fluxN1);
746 fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
747
748 // Jacobian is not needed except the limit case when u⁺=u⁻
749 bool J_needed = false;
750 for (int i = 0; i < fluxFunction.num_equations; i++)
751 if (equal_check(state1(i), state2(i)))
752 {
753 J_needed = true;
754 break;
755 }
756
757 if (J_needed)
758 {
761 }
762
763 grad = 0.;
764
765 for (int i = 0; i < fluxFunction.num_equations; i++)
766 {
767 // Only diagonal terms of J are considered
768 // lim_{u → u⁻} (F(u)n - F̄(u⁻,u)n) / (u - u⁻) = ½J(u⁻)n
769 const real_t gr12 = (!equal_check(state1(i), state2(i)))?
770 (fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
771 :(0.5 * JDotN(i,i));
772 grad(i,i) = std::min(gr12, 0_r);
773 }
774 }
775}
776
779 DenseMatrix &FU) const
780{
781#ifdef MFEM_THREAD_SAFE
782 Vector bval(b.GetVDim());
783#endif
784 b.Eval(bval, Tr, Tr.GetIntPoint());
785 MultVWt(U, bval, FU);
786 return bval.Norml2();
787}
788
790 const Vector &normal,
792 Vector &FDotN) const
793{
794#ifdef MFEM_THREAD_SAFE
795 Vector bval(b.GetVDim());
796#endif
797 b.Eval(bval, Tr, Tr.GetIntPoint());
798 FDotN(0) = U(0) * (bval * normal);
799 return bval.Norml2();
800}
801
804 DenseMatrix &FU) const
805{
806#ifdef MFEM_THREAD_SAFE
807 Vector bval(b.GetVDim());
808#endif
809 b.Eval(bval, Tr, Tr.GetIntPoint());
810 Vector Uavg(1);
811 Uavg(0) = (U1(0) + U2(0)) * 0.5;
812 MultVWt(Uavg, bval, FU);
813 return bval.Norml2();
814}
815
817 const Vector &normal,
819 Vector &FDotN) const
820{
821#ifdef MFEM_THREAD_SAFE
822 Vector bval(b.GetVDim());
823#endif
824 b.Eval(bval, Tr, Tr.GetIntPoint());
825 FDotN(0) = (U1(0) + U2(0)) * 0.5 * (bval * normal);
826 return bval.Norml2();
827}
828
831 DenseTensor &J) const
832{
833#ifdef MFEM_THREAD_SAFE
834 Vector bval(b.GetVDim());
835#endif
836 b.Eval(bval, Tr, Tr.GetIntPoint());
837 J = 0.;
838 for (int d = 0; d < dim; d++)
839 {
840 J(0,0,d) = bval(d);
841 }
842}
843
845 const Vector &normal,
847 DenseMatrix &JDotN) const
848{
849#ifdef MFEM_THREAD_SAFE
850 Vector bval(b.GetVDim());
851#endif
852 b.Eval(bval, Tr, Tr.GetIntPoint());
853 JDotN(0,0) = bval * normal;
854}
855
858 DenseMatrix &FU) const
859{
860 FU = U(0) * U(0) * 0.5;
861 return std::fabs(U(0));
862}
863
865 const Vector &normal,
867 Vector &FDotN) const
868{
869 FDotN(0) = U(0) * U(0) * 0.5 * normal.Sum();
870 return std::fabs(U(0));
871}
872
874 const Vector &U2,
876 DenseMatrix &FU) const
877{
878 FU = (U1(0)*U1(0) + U1(0)*U2(0) + U2(0)*U2(0)) / 6.;
879 return std::max(std::fabs(U1(0)), std::fabs(U2(0)));
880}
881
883 const Vector &U2,
884 const Vector &normal,
886 Vector &FDotN) const
887{
888 FDotN(0) = (U1(0)*U1(0) + U1(0)*U2(0) + U2(0)*U2(0)) / 6. * normal.Sum();
889 return std::max(std::fabs(U1(0)), std::fabs(U2(0)));
890}
891
894 DenseTensor &J) const
895{
896 J = 0.;
897 for (int d = 0; d < dim; d++)
898 {
899 J(0,0,d) = U(0);
900 }
901}
902
904 const Vector &normal,
906 DenseMatrix &JDotN) const
907{
908 JDotN(0,0) = U(0) * normal.Sum();
909}
910
913 DenseMatrix &FU) const
914{
915 const real_t height = U(0);
916 const Vector h_vel(U.GetData() + 1, dim);
917
918 const real_t energy = 0.5 * g * (height * height);
919
920 MFEM_ASSERT(height >= 0, "Negative Height");
921
922 for (int d = 0; d < dim; d++)
923 {
924 FU(0, d) = h_vel(d);
925 for (int i = 0; i < dim; i++)
926 {
927 FU(1 + i, d) = h_vel(i) * h_vel(d) / height;
928 }
929 FU(1 + d, d) += energy;
930 }
931
932 const real_t sound = std::sqrt(g * height);
933 const real_t vel = std::sqrt(h_vel * h_vel) / height;
934
935 return vel + sound;
936}
937
938
940 const Vector &normal,
942 Vector &FUdotN) const
943{
944 const real_t height = U(0);
945 const Vector h_vel(U.GetData() + 1, dim);
946
947 const real_t energy = 0.5 * g * (height * height);
948
949 MFEM_ASSERT(height >= 0, "Negative Height");
950 FUdotN(0) = h_vel * normal;
951 const real_t normal_vel = FUdotN(0) / height;
952 for (int i = 0; i < dim; i++)
953 {
954 FUdotN(1 + i) = normal_vel * h_vel(i) + energy * normal(i);
955 }
956
957 const real_t sound = std::sqrt(g * height);
958 const real_t vel = std::fabs(normal_vel) / std::sqrt(normal*normal);
959
960 return vel + sound;
961}
962
963
966 DenseMatrix &FU) const
967{
968 // 1. Get states
969 const real_t density = U(0); // ρ
970 const Vector momentum(U.GetData() + 1, dim); // ρu
971 const real_t energy = U(1 + dim); // E, internal energy ρe
972 const real_t kinetic_energy = 0.5 * (momentum*momentum) / density;
973 // pressure, p = (γ-1)*(E - ½ρ|u|^2)
974 const real_t pressure = (specific_heat_ratio - 1.0) *
975 (energy - kinetic_energy);
976
977 // Check whether the solution is physical only in debug mode
978 MFEM_ASSERT(density >= 0, "Negative Density");
979 MFEM_ASSERT(pressure >= 0, "Negative Pressure");
980 MFEM_ASSERT(energy >= 0, "Negative Energy");
981
982 // 2. Compute Flux
983 for (int d = 0; d < dim; d++)
984 {
985 FU(0, d) = momentum(d); // ρu
986 for (int i = 0; i < dim; i++)
987 {
988 // ρuuᵀ
989 FU(1 + i, d) = momentum(i) * momentum(d) / density;
990 }
991 // (ρuuᵀ) + p
992 FU(1 + d, d) += pressure;
993 }
994 // enthalpy H = e + p/ρ = (E + p)/ρ
995 const real_t H = (energy + pressure) / density;
996 for (int d = 0; d < dim; d++)
997 {
998 // u(E+p) = ρu*(E + p)/ρ = ρu*H
999 FU(1 + dim, d) = momentum(d) * H;
1000 }
1001
1002 // 3. Compute maximum characteristic speed
1003
1004 // sound speed, √(γ p / ρ)
1005 const real_t sound = std::sqrt(specific_heat_ratio * pressure / density);
1006 // fluid speed |u|
1007 const real_t speed = std::sqrt(2.0 * kinetic_energy / density);
1008 // max characteristic speed = fluid speed + sound speed
1009 return speed + sound;
1010}
1011
1012
1014 const Vector &normal,
1016 Vector &FUdotN) const
1017{
1018 // 1. Get states
1019 const real_t density = x(0); // ρ
1020 const Vector momentum(x.GetData() + 1, dim); // ρu
1021 const real_t energy = x(1 + dim); // E, internal energy ρe
1022 const real_t kinetic_energy = 0.5 * (momentum*momentum) / density;
1023 // pressure, p = (γ-1)*(E - ½ρ|u|^2)
1024 const real_t pressure = (specific_heat_ratio - 1.0) *
1025 (energy - kinetic_energy);
1026
1027 // Check whether the solution is physical only in debug mode
1028 MFEM_ASSERT(density >= 0, "Negative Density");
1029 MFEM_ASSERT(pressure >= 0, "Negative Pressure");
1030 MFEM_ASSERT(energy >= 0, "Negative Energy");
1031
1032 // 2. Compute normal flux
1033
1034 FUdotN(0) = momentum * normal; // ρu⋅n
1035 // u⋅n
1036 const real_t normal_velocity = FUdotN(0) / density;
1037 for (int d = 0; d < dim; d++)
1038 {
1039 // (ρuuᵀ + pI)n = ρu*(u⋅n) + pn
1040 FUdotN(1 + d) = normal_velocity * momentum(d) + pressure * normal(d);
1041 }
1042 // (u⋅n)(E + p)
1043 FUdotN(1 + dim) = normal_velocity * (energy + pressure);
1044
1045 // 3. Compute maximum characteristic speed
1046
1047 // sound speed, √(γ p / ρ)
1048 const real_t sound = std::sqrt(specific_heat_ratio * pressure / density);
1049 // fluid speed |u|
1050 const real_t speed = std::fabs(normal_velocity) / std::sqrt(normal*normal);
1051 // max characteristic speed = fluid speed + sound speed
1052 return speed + sound;
1053}
1054
1055} // namespace mfem
void ComputeFluxJacobian(const Vector &state, ElementTransformation &Tr, DenseTensor &J) const override
Compute J(u)
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute F(u)
void ComputeFluxJacobianDotN(const Vector &state, const Vector &normal, ElementTransformation &Tr, DenseMatrix &JDotN) const override
Compute J(u) n.
real_t ComputeFluxDotN(const Vector &state, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const override
Compute F(u) n.
real_t ComputeAvgFlux(const Vector &state1, const Vector &state2, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute average flux F̄(u)
real_t ComputeAvgFluxDotN(const Vector &state1, const Vector &state2, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const override
Compute average flux F̄(u) n.
real_t ComputeAvgFluxDotN(const Vector &state1, const Vector &state2, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const override
Compute average flux F̄(u) n.
void ComputeFluxJacobianDotN(const Vector &state, const Vector &normal, ElementTransformation &Tr, DenseMatrix &JDotN) const override
Compute J(u) n.
real_t ComputeAvgFlux(const Vector &state1, const Vector &state2, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute average flux F̄(u)
real_t ComputeFluxDotN(const Vector &state, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const override
Compute F(u) n.
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute F(u)
void ComputeFluxJacobian(const Vector &state, ElementTransformation &Tr, DenseTensor &J) const override
Compute J(u)
ComponentwiseUpwindFlux(const FluxFunction &fluxFunction)
Constructor for a flux function.
void AverageGrad(int side, const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, DenseMatrix &grad) const override
Jacobian of average normal numerical flux over the interval [u⁻, u⁺] in the second argument of the fl...
real_t Average(const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, Vector &flux) const override
Average normal numerical flux over the interval [u⁻, u⁺] in the second argument of the flux F̂(u⁻,...
void Grad(int side, const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, DenseMatrix &grad) const override
Jacobian of normal numerical flux F̂(u⁻,u⁺,x) n.
real_t Eval(const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, Vector &flux) const override
Normal numerical flux F̂(u⁻,u⁺,x) n.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
Definition densemat.cpp:125
void Set(real_t alpha, const real_t *A)
Set the matrix to alpha * A, assuming that A has the same dimensions as the matrix and uses column-ma...
Definition densemat.cpp:600
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:172
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:108
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0<=i.
Rank 3 tensor (array of matrices)
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition eltrans.hpp:175
const IntegrationPoint & GetIntPoint()
Get a const reference to the currently set integration point. This will return NULL if no integration...
Definition eltrans.hpp:111
virtual int GetSpaceDim() const =0
Get the dimension of the target (physical) space.
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint,...
Definition eltrans.hpp:132
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute F(ρ, ρu, E)
real_t ComputeFluxDotN(const Vector &x, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxN) const override
Compute normal flux, F(ρ, ρu, E)n.
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
const IntegrationPoint & GetElement1IntPoint()
Get a const reference to the integration point in neighboring element 1 corresponding to the currentl...
Definition eltrans.hpp:846
const IntegrationPoint & GetElement2IntPoint()
Get a const reference to the integration point in neighboring element 2 corresponding to the currentl...
Definition eltrans.hpp:856
void SetAllIntPoints(const IntegrationPoint *face_ip)
Set the integration point in the Face and the two neighboring elements, if present.
Definition eltrans.hpp:835
Abstract class for all finite elements.
Definition fe_base.hpp:244
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:338
void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const
Evaluate the gradients of all shape functions of a scalar finite element in physical space at the poi...
Definition fe_base.cpp:192
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:321
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:334
Abstract class for hyperbolic flux for a system of hyperbolic conservation laws.
virtual real_t ComputeAvgFlux(const Vector &state1, const Vector &state2, ElementTransformation &Tr, DenseMatrix &flux_) const
Compute average flux over the given interval of states. Optionally overloaded in a derived class.
virtual real_t ComputeAvgFluxDotN(const Vector &state1, const Vector &state2, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const
Compute average normal flux over the given interval of states. Optionally overloaded in a derived cla...
const int num_equations
virtual real_t ComputeFlux(const Vector &state, ElementTransformation &Tr, DenseMatrix &flux) const =0
Compute flux F(u, x). Must be implemented in a derived class.
virtual void ComputeFluxJacobian(const Vector &state, ElementTransformation &Tr, DenseTensor &J_) const
Compute flux Jacobian J(u, x). Optionally overloaded in a derived class when Jacobian is necessary (e...
virtual real_t ComputeFluxDotN(const Vector &state, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxDotN) const
Compute normal flux F(u, x)⋅n. Optionally overloaded in a derived class to avoid creating a full dens...
virtual void ComputeFluxJacobianDotN(const Vector &state, const Vector &normal, ElementTransformation &Tr, DenseMatrix &JDotN) const
Compute normal flux Jacobian J(u, x)⋅n. Optionally overloaded in a derived class to avoid creating a ...
HyperbolicFormIntegrator(const NumericalFlux &numFlux, const int IntOrderOffset=0, const real_t sign=1.)
Construct a new Hyperbolic Form Integrator object.
void AssembleFaceGrad(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, const Vector &elfun, DenseMatrix &elmat) override
Implements <-Ĵ(u⁻,u⁺,x) n, [v]> with abstract Ĵ computed by NumericalFlux::Grad() of the numerical ...
void AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect) override
Implements <-F̂(u⁻,u⁺,x) n, [v]> with abstract F̂ computed by NumericalFlux::Eval() of the numerical ...
void ResetMaxCharSpeed()
Reset the Max Char Speed 0.
void AssembleElementGrad(const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun, DenseMatrix &grad) override
Implements (J(u), ∇v) with abstract J computed by FluxFunction::ComputeFluxJacobian()
void AssembleElementVector(const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun, Vector &elvect) override
Implements (F(u), ∇v) with abstract F computed by FluxFunction::ComputeFlux()
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
const IntegrationRule * IntRule
int GetSpaceDim() const override
Get the dimension of the target (physical) space.
Definition eltrans.hpp:709
This class is used to express the local action of a general nonlinear finite element operator....
Abstract class for numerical flux for a system of hyperbolic conservation laws on a face with states,...
const FluxFunction & fluxFunction
virtual real_t Eval(const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, Vector &flux) const =0
Evaluates normal numerical flux for the given states and normal. Must be implemented in a derived cla...
virtual void Grad(int side, const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, DenseMatrix &grad) const
Evaluates Jacobian of the normal numerical flux for the given states and normal. Optionally overloade...
RusanovFlux(const FluxFunction &fluxFunction)
Constructor for a flux function.
DenseMatrix JDotN
real_t Average(const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, Vector &flux) const override
Average normal numerical flux over the interval [u⁻, u⁺] in the second argument of the flux F̂(u⁻,...
void Grad(int side, const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, DenseMatrix &grad) const override
Jacobian of normal numerical flux F̂(u⁻,u⁺,x) n.
void AverageGrad(int side, const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, DenseMatrix &grad) const override
Jacobian of average normal numerical flux over the interval [u⁻, u⁺] in the second argument of the fl...
real_t Eval(const Vector &state1, const Vector &state2, const Vector &nor, FaceElementTransformations &Tr, Vector &flux) const override
Normal numerical flux F̂(u⁻,u⁺,x) n.
real_t ComputeFluxDotN(const Vector &state, const Vector &normal, FaceElementTransformations &Tr, Vector &fluxN) const override
Compute normal flux, F(h, hu)
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr, DenseMatrix &flux) const override
Compute F(h, hu)
int GetVDim()
Returns dimension of the vector.
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Vector data type.
Definition vector.hpp:82
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:931
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
real_t Sum() const
Return the sum of the vector entries.
Definition vector.cpp:1204
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void CalcOrtho(const DenseMatrix &J, Vector &n)
void AddMult_a_ABt(real_t a, const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
ABt += a * A * B^t.
void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
void AddMult_a_VWt(const real_t a, const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += a * v w^t.
float real_t
Definition config.hpp:43
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
void vel(const Vector &x, real_t t, Vector &u)