Skip to content

Commit a6d3f37

Browse files
ChrisZYJdanieljvickerssbryngelson
authored
MHD Hyperbolic Divergence Cleaning (#1086)
Co-authored-by: Daniel J. Vickers <dnlvickers5@gmail.com> Co-authored-by: Spencer Bryngelson <sbryngelson@gmail.com>
1 parent bac27a5 commit a6d3f37

32 files changed

Lines changed: 972 additions & 206 deletions

.typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ TKE = "TKE"
2121
HSA = "HSA"
2222
infp = "infp"
2323
Sur = "Sur"
24+
iz = "iz"
2425

2526
[files]
2627
extend-exclude = ["docs/documentation/references*", "tests/", "toolchain/cce_simulation_workgroup_256.sh"]

docs/documentation/case.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -939,22 +939,25 @@ By convention, positive accelerations in the `x[y,z]` direction are in the posit
939939

940940
### 14. Magnetohydrodynamics (MHD)
941941

942-
| Parameter | Type | Description |
943-
| ---: | :---: | :--- |
944-
| `mhd` | Logical | Enable ideal MHD simulation |
945-
| `relativity` | Logical | Enable relativistic MHD simulation |
946-
| `powell` | Logical | Enable Powell's method for solenoidal constraint |
947-
| `fd_order` | Integer | Finite difference order for Powell's method |
948-
| `Bx[y,z]` | Real | Initial magnetic field in the x[y,z] direction |
949-
| `Bx0` | Real | Constant magnetic field in the x direction (1D only)|
942+
| Parameter | Type | Description |
943+
| ---: | :---: | :--- |
944+
| `mhd` | Logical | Enable ideal MHD simulation |
945+
| `relativity` | Logical | Enable relativistic MHD simulation |
946+
| `hyper_cleaning` | Logical | Enable hyperbolic (GLM) divergence cleaning for `div B` |
947+
| `hyper_cleaning_speed` | Real | Cleaning wave speed `c_h` |
948+
| `hyper_cleaning_tau` | Real | Cleaning damping timescale `tau` |
949+
| `Bx[y,z]` | Real | Initial magnetic field in the x[y,z] direction |
950+
| `Bx0` | Real | Constant magnetic field in the x direction (1D only) |
950951

951952
- `mhd` is currently only available for single-component flows and 5-equation model. Its compatibility with most other features is work in progress.
952953

953954
- `relativity` only works for `mhd` enabled and activates relativistic MHD (RMHD) simulation.
954955

955-
- `powell` activates Powell's eight-wave method to impose the solenoidal constraint in the MHD simulation [Powell (1994)](references.md). It should not be used in conjunction with HLLD (`riemann_solver = 4`).
956+
- `hyper_cleaning` [Dedner et al., 2002](references.md) only works with `mhd` in 2D/3D and reduces numerical `div B` errors by propagation and damping. Currently not compatible with HLLD (`riemann_solver = 4`).
957+
958+
- `hyper_cleaning_speed` sets the propagation speed of divergence-cleaning waves.
956959

957-
- `fd_order` specifies the finite difference order for computing the RHS of the Powell's method. `fd_order = 1`, `2`, and `4` are allowed.
960+
- `hyper_cleaning_tau` sets the decay timescale for divergence-cleaning.
958961

959962
- `Bx0` is only used in 1D simulations to specify the constant magnetic field in the x direction. It must be specified in 1D simulations. `Bx` must not be used in 1D simulations.
960963

docs/documentation/references.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666

6767
- <a id="Miyoshi05">Miyoishi, T., and Kusano, K. (2005). A multi-state HLL approximate Riemann solver for ideal magnetohydrodynamics. Journal of Computational Physics, 208(1), 315-344.</a>
6868

69-
- <a id="Powell94">Powell, K. G. (1994). An approximate Riemann solver for magnetohydrodynamics: (That works in more than one dimension). In Upwind and high-resolution schemes (pp. 570-583). Springer.</a>
69+
- <a id="Dedner02">Dedner, A., Kemm, F., Kröner, D., Munz, C. D., Schnitzer, T., & Wesenberg, M. (2002). Hyperbolic divergence cleaning for the MHD equations. Journal of Computational Physics, 175(2), 645-673.</a>
7070

7171
- <a id="Cao19">Cao, S., Zhang, Y., Liao, D., Zhong, P., and Wang, K. G. (2019). Shock-induced damage and dynamic fracture in cylindrical bodies submerged in liquid. International Journal of Solids and Structures, 169:55–71. Elsevier.</a>
7272

examples/2D_mhd_magnetic_vortex/case.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"parallel_io": "T",
5555
# MHD
5656
"mhd": "T",
57-
"patch_icpp(1)%hcid": 252,
57+
"patch_icpp(1)%hcid": 253,
5858
"patch_icpp(1)%geometry": 3,
5959
"patch_icpp(1)%x_centroid": 0.0,
6060
"patch_icpp(1)%y_centroid": 0.0,

examples/2D_mhd_rotor/case.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
import json
3+
import math
4+
5+
# Configuring case dictionary
6+
print(
7+
json.dumps(
8+
{
9+
# Logistics
10+
"run_time_info": "T",
11+
# Computational Domain Parameters
12+
"x_domain%beg": 0.0,
13+
"x_domain%end": 1.0,
14+
"y_domain%beg": 0.0,
15+
"y_domain%end": 1.0,
16+
"m": 399,
17+
"n": 399,
18+
"p": 0,
19+
"dt": 0.0004,
20+
"t_step_start": 0,
21+
"t_step_stop": 375,
22+
"t_step_save": 5,
23+
# Simulation Algorithm Parameters
24+
"num_patches": 1,
25+
"model_eqns": 2,
26+
"alt_soundspeed": "F",
27+
"num_fluids": 1,
28+
"mpp_lim": "F",
29+
"mixture_err": "F",
30+
"time_stepper": 3,
31+
"weno_order": 5,
32+
"mapped_weno": "T",
33+
"weno_eps": 1.0e-6,
34+
"null_weights": "F",
35+
"mp_weno": "F",
36+
"riemann_solver": 1,
37+
"wave_speeds": 1,
38+
"avg_state": 2,
39+
"bc_x%beg": -1,
40+
"bc_x%end": -1,
41+
"bc_y%beg": -1,
42+
"bc_y%end": -1,
43+
# Formatted Database Files Structure Parameters
44+
"format": 1,
45+
"precision": 2,
46+
"prim_vars_wrt": "T",
47+
"rho_wrt": "T",
48+
"parallel_io": "T",
49+
# MHD
50+
"mhd": "T",
51+
"hyper_cleaning": "T",
52+
"hyper_cleaning_speed": 2.5,
53+
"hyper_cleaning_tau": 0.004,
54+
# Patch 1 - 2D MHD Rotor Problem
55+
# gamma = 1.4
56+
# Ambient medium (r > 0.1):
57+
# rho = 1
58+
# p = 1
59+
# v = (0, 0, 0)
60+
# B = (1, 0, 0)
61+
# Rotor (r <= 0.1):
62+
# rho = 10
63+
# v has angular velocity of 20
64+
"patch_icpp(1)%hcid": 252,
65+
"patch_icpp(1)%geometry": 3,
66+
"patch_icpp(1)%x_centroid": 0.5,
67+
"patch_icpp(1)%y_centroid": 0.5,
68+
"patch_icpp(1)%length_x": 1.0,
69+
"patch_icpp(1)%length_y": 1.0,
70+
"patch_icpp(1)%vel(1)": 0.0,
71+
"patch_icpp(1)%vel(2)": 0.0,
72+
"patch_icpp(1)%vel(3)": 0.0,
73+
"patch_icpp(1)%pres": 1.0,
74+
"patch_icpp(1)%Bx": 5.0 / math.sqrt(math.pi * 4.0),
75+
"patch_icpp(1)%By": 0.0,
76+
"patch_icpp(1)%Bz": 0.0,
77+
"patch_icpp(1)%alpha_rho(1)": 1.0,
78+
"patch_icpp(1)%alpha(1)": 1.0,
79+
# Fluids Physical Parameters
80+
"fluid_pp(1)%gamma": 1.0e00 / (1.4e00 - 1.0e00),
81+
"fluid_pp(1)%pi_inf": 0.0,
82+
}
83+
)
84+
)

examples/2D_orszag_tang_powell/case.py renamed to examples/2D_orszag_tang_hyper_cleaning/case.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
"m": 512,
1717
"n": 512,
1818
"p": 0,
19-
"dt": 0.0005,
19+
"dt": 0.0004,
2020
"t_step_start": 0,
21-
"t_step_stop": 2000,
21+
"t_step_stop": 2500,
2222
"t_step_save": 100,
2323
# Simulation Algorithm Parameters
2424
"num_patches": 1,
@@ -28,7 +28,8 @@
2828
"mpp_lim": "F",
2929
"mixture_err": "F",
3030
"time_stepper": 3,
31-
"weno_order": 1,
31+
"weno_order": 5,
32+
"mapped_weno": "T",
3233
"weno_eps": 1.0e-6,
3334
"null_weights": "F",
3435
"mp_weno": "F",
@@ -47,8 +48,9 @@
4748
"parallel_io": "T",
4849
# MHD
4950
"mhd": "T",
50-
"powell": "T",
51-
"fd_order": 2,
51+
"hyper_cleaning": "T",
52+
"hyper_cleaning_speed": 2.5,
53+
"hyper_cleaning_tau": 0.004,
5254
# Patch 1 - Analytical for v and B
5355
# gamma = 5/3
5456
# rho = 25/(36*pi)

src/common/include/2dHardcodedIC.fpp

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
#:def Hardcoded2DVariables()
22
! Place any declaration of intermediate variables here
3-
real(wp) :: eps
3+
real(wp) :: eps, eps_mhd, C_mhd
44
real(wp) :: r, rmax, gam, umax, p0
55
real(wp) :: rhoH, rhoL, pRef, pInt, h, lam, wl, amp, intH, intL, alph
66
real(wp) :: factor
7+
real(wp) :: r0, alpha, r2
8+
real(wp) :: sinA, cosA
9+
10+
real(wp) :: r_sq
11+
712
! # 207
813
real(wp) :: sigma, gauss1, gauss2
914
! # 208
@@ -183,7 +188,43 @@
183188
q_prim_vf(E_idx)%sf(i, j, 0) = 3.e-5_wp
184189
end if
185190

186-
case (252) ! MHD Smooth Magnetic Vortex
191+
! case 252 is for the 2D MHD Rotor problem
192+
case (252) ! 2D MHD Rotor Problem
193+
! Ambient conditions are set in the JSON file.
194+
! This case imposes the dense, rotating cylinder.
195+
!
196+
! gamma = 1.4
197+
! Ambient medium (r > 0.1):
198+
! rho = 1, p = 1, v = 0, B = (1,0,0)
199+
! Rotor (r <= 0.1):
200+
! rho = 10, p = 1
201+
! v has angular velocity w=20, giving v_tan=2 at r=0.1
202+
203+
! Calculate distance squared from the center
204+
r_sq = (x_cc(i) - 0.5_wp)**2 + (y_cc(j) - 0.5_wp)**2
205+
206+
! inner radius of 0.1
207+
if (r_sq <= 0.1**2) then
208+
! -- Inside the rotor --
209+
! Set density uniformly to 10
210+
q_prim_vf(contxb)%sf(i, j, 0) = 10._wp
211+
212+
! Set vup constant rotation of rate v=2
213+
! v_x = -omega * (y - y_c)
214+
! v_y = omega * (x - x_c)
215+
q_prim_vf(momxb)%sf(i, j, 0) = -20._wp*(y_cc(j) - 0.5_wp)
216+
q_prim_vf(momxb + 1)%sf(i, j, 0) = 20._wp*(x_cc(i) - 0.5_wp)
217+
218+
! taper width of 0.015
219+
else if (r_sq <= 0.115**2) then
220+
! linearly smooth the function between r = 0.1 and 0.115
221+
q_prim_vf(contxb)%sf(i, j, 0) = 1._wp + 9._wp*(0.115_wp - sqrt(r_sq))/(0.015_wp)
222+
223+
q_prim_vf(momxb)%sf(i, j, 0) = -(2._wp/sqrt(r_sq))*(y_cc(j) - 0.5_wp)*(0.115_wp - sqrt(r_sq))/(0.015_wp)
224+
q_prim_vf(momxb + 1)%sf(i, j, 0) = (2._wp/sqrt(r_sq))*(x_cc(i) - 0.5_wp)*(0.115_wp - sqrt(r_sq))/(0.015_wp)
225+
end if
226+
227+
case (253) ! MHD Smooth Magnetic Vortex
187228
! Section 5.2 of
188229
! Implicit hybridized discontinuous Galerkin methods for compressible magnetohydrodynamics
189230
! C. Ciuca, P. Fernandez, A. Christophe, N.C. Nguyen, J. Peraire
@@ -199,6 +240,62 @@
199240
! pressure
200241
q_prim_vf(E_idx)%sf(i, j, 0) = 1._wp + (1 - 2._wp*(x_cc(i)**2 + y_cc(j)**2))*exp(1 - (x_cc(i)**2 + y_cc(j)**2))/((2._wp*pi)**3)
201242

243+
case (260) ! Gaussian Divergence Pulse
244+
! Bx(x) = 1 + C * erf((x-0.5)/σ)
245+
! ⇒ ∂Bx/∂x = C * (2/√π) * exp[-((x-0.5)/σ)**2] * (1/σ)
246+
! Choose C = ε * σ * √π / 2 ⇒ ∂Bx/∂x = ε * exp[-((x-0.5)/σ)**2]
247+
! ψ is initialized to zero everywhere.
248+
249+
eps_mhd = patch_icpp(patch_id)%a(2)
250+
sigma = patch_icpp(patch_id)%a(3)
251+
C_mhd = eps_mhd*sigma*sqrt(pi)*0.5_wp
252+
253+
! B-field
254+
q_prim_vf(B_idx%beg)%sf(i, j, 0) = 1._wp + C_mhd*erf((x_cc(i) - 0.5_wp)/sigma)
255+
256+
case (261) ! Blob
257+
r0 = 1._wp/sqrt(8._wp)
258+
r2 = x_cc(i)**2 + y_cc(j)**2
259+
r = sqrt(r2)
260+
alpha = r/r0
261+
if (alpha < 1) then
262+
q_prim_vf(B_idx%beg)%sf(i, j, 0) = 1._wp/sqrt(4._wp*pi)*(alpha**8 - 2._wp*alpha**4 + 1._wp)
263+
! q_prim_vf(B_idx%beg)%sf(i,j,0) = 1._wp/sqrt(4000._wp*pi) * (4096._wp*r2**4 - 128._wp*r2**2 + 1._wp)
264+
! q_prim_vf(B_idx%beg)%sf(i,j,0) = 1._wp/(4._wp*pi) * (alpha**8 - 2._wp*alpha**4 + 1._wp)
265+
! q_prim_vf(E_idx)%sf(i,j,0) = 6._wp - q_prim_vf(B_idx%beg)%sf(i,j,0)**2/2._wp
266+
end if
267+
268+
case (262) ! Tilted 2D MHD shock‐tube at α = arctan2 (≈63.4°)
269+
! rotate by α = atan(2)
270+
alpha = atan(2._wp)
271+
cosA = cos(alpha)
272+
sinA = sin(alpha)
273+
! projection along shock normal
274+
r = x_cc(i)*cosA + y_cc(j)*sinA
275+
276+
if (r <= 0.5_wp) then
277+
! LEFT state: ρ=1, v∥=+10, v⊥=0, p=20, B∥=B⊥=5/√(4π)
278+
q_prim_vf(contxb)%sf(i, j, 0) = 1._wp
279+
q_prim_vf(momxb)%sf(i, j, 0) = 10._wp*cosA
280+
q_prim_vf(momxb + 1)%sf(i, j, 0) = 10._wp*sinA
281+
q_prim_vf(E_idx)%sf(i, j, 0) = 20._wp
282+
q_prim_vf(B_idx%beg)%sf(i, j, 0) = (5._wp/sqrt(4._wp*pi))*cosA &
283+
- (5._wp/sqrt(4._wp*pi))*sinA
284+
q_prim_vf(B_idx%beg + 1)%sf(i, j, 0) = (5._wp/sqrt(4._wp*pi))*sinA &
285+
+ (5._wp/sqrt(4._wp*pi))*cosA
286+
else
287+
! RIGHT state: ρ=1, v∥=10, v⊥=0, p=1, B∥=B⊥=5/√(4π)
288+
q_prim_vf(contxb)%sf(i, j, 0) = 1._wp
289+
q_prim_vf(momxb)%sf(i, j, 0) = -10._wp*cosA
290+
q_prim_vf(momxb + 1)%sf(i, j, 0) = -10._wp*sinA
291+
q_prim_vf(E_idx)%sf(i, j, 0) = 1._wp
292+
q_prim_vf(B_idx%beg)%sf(i, j, 0) = (5._wp/sqrt(4._wp*pi))*cosA &
293+
- (5._wp/sqrt(4._wp*pi))*sinA
294+
q_prim_vf(B_idx%beg + 1)%sf(i, j, 0) = (5._wp/sqrt(4._wp*pi))*sinA &
295+
+ (5._wp/sqrt(4._wp*pi))*cosA
296+
end if
297+
! v^z and B^z remain zero by default
298+
202299
case (270)
203300
! This hardcoded case extrudes a 1D profile to initialize a 2D simulation domain
204301
@: HardcodedReadValues()

src/common/m_variables_conversion.fpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ contains
882882

883883
if (cont_damage) qK_prim_vf(damage_idx)%sf(j, k, l) = qK_cons_vf(damage_idx)%sf(j, k, l)
884884

885+
if (hyper_cleaning) qK_prim_vf(psi_idx)%sf(j, k, l) = qK_cons_vf(psi_idx)%sf(j, k, l)
885886
#ifdef MFC_POST_PROCESS
886887
if (bubbles_lagrange) qK_prim_vf(beta_idx)%sf(j, k, l) = qK_cons_vf(beta_idx)%sf(j, k, l)
887888
#endif
@@ -1152,6 +1153,8 @@ contains
11521153

11531154
if (cont_damage) q_cons_vf(damage_idx)%sf(j, k, l) = q_prim_vf(damage_idx)%sf(j, k, l)
11541155

1156+
if (hyper_cleaning) q_cons_vf(psi_idx)%sf(j, k, l) = q_prim_vf(psi_idx)%sf(j, k, l)
1157+
11551158
end do
11561159
end do
11571160
end do

src/post_process/m_data_output.fpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ contains
363363
! Damage state variable
364364
if (cont_damage) dbvars = dbvars + 1
365365
366+
! Hyperbolic cleaning for MHD
367+
if (hyper_cleaning) dbvars = dbvars + 1
368+
366369
! Magnetic field
367370
if (mhd) then
368371
if (n == 0) then

src/post_process/m_global_parameters.fpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ module m_global_parameters
117117
integer :: b_size !< Number of components in the b tensor
118118
integer :: tensor_size !< Number of components in the nonsymmetric tensor
119119
logical :: cont_damage !< Continuum damage modeling
120+
logical :: hyper_cleaning !< Hyperbolic cleaning for MHD
120121
logical :: igr !< enable IGR
121122
integer :: igr_order !< IGR reconstruction order
122123
logical, parameter :: chemistry = .${chemistry}$. !< Chemistry modeling
@@ -143,6 +144,7 @@ module m_global_parameters
143144
integer :: c_idx !< Index of color function
144145
type(int_bounds_info) :: species_idx !< Indexes of first & last concentration eqns.
145146
integer :: damage_idx !< Index of damage state variable (D) for continuum damage model
147+
integer :: psi_idx !< Index of hyperbolic cleaning state variable for MHD
146148
!> @}
147149

148150
! Cell Indices for the (local) interior points (O-m, O-n, 0-p).
@@ -407,6 +409,7 @@ contains
407409
b_size = dflt_int
408410
tensor_size = dflt_int
409411
cont_damage = .false.
412+
hyper_cleaning = .false.
410413
igr = .false.
411414

412415
bc_x%beg = dflt_int; bc_x%end = dflt_int
@@ -812,6 +815,13 @@ contains
812815
damage_idx = dflt_int
813816
end if
814817

818+
if (hyper_cleaning) then
819+
psi_idx = sys_size + 1
820+
sys_size = psi_idx
821+
else
822+
psi_idx = dflt_int
823+
end if
824+
815825
end if
816826

817827
if (chemistry) then

0 commit comments

Comments
 (0)