Repository navigation
InnerLayer.SLAYER - FEATURE! - Add perpendicular Prandtl number options and an ion heat diffusivity profile #501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
b83e193
3fd1885
80c6664
915447f
27d0744
e4b1266
2083d02
d5937d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,7 +16,7 @@ | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Dimensionless layer-physics parameters at one rational surface for the | ||||||||||||||||||||||||
| Fitzpatrick two-fluid drift-MHD SLAYER inner-layer model (Fitzpatrick | ||||||||||||||||||||||||
| 2023; Park et al. 2022), plus dimensional auxiliaries required for | ||||||||||||||||||||||||
| 2023; Park 2022), plus dimensional auxiliaries required for | ||||||||||||||||||||||||
| de-normalization. The parametrization uses `P_perp`, `P_tor`, and | ||||||||||||||||||||||||
| `D_norm` (not the older `pr`/`pe`/`ds` set). | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -28,7 +28,7 @@ de-normalization. The parametrization uses `P_perp`, `P_tor`, and | |||||||||||||||||||||||
| | `lu` | Lundquist number S = τ_R / τ_H | | ||||||||||||||||||||||||
| | `c_beta` | Compressibility √(β_local / (1 + β_local)) | | ||||||||||||||||||||||||
| | `D_norm` | (d_β/r_s) · S^(1/3) · √ι_e (Fitzpatrick normalized scale) | | ||||||||||||||||||||||||
| | `P_perp` | Perpendicular Prandtl number τ_R / τ_⊥ | | ||||||||||||||||||||||||
| | `P_perp` | Perpendicular Prandtl number τ_R / τ_⊥ (set by `P_perp_model`) | | ||||||||||||||||||||||||
| | `P_tor` | Toroidal-direction Prandtl number τ_R / τ_‖tor | | ||||||||||||||||||||||||
| | `Q_e` | Normalized electron diamagnetic: −tauk · ω_*e | | ||||||||||||||||||||||||
| | `Q_i` | Normalized ion diamagnetic: −tauk · ω_*i | | ||||||||||||||||||||||||
|
|
@@ -104,6 +104,9 @@ end | |||||||||||||||||||||||
| # `dc_tmp = 0` branch. | ||||||||||||||||||||||||
| const ALLOWED_DC_TYPES = (:none, :lar, :rfitzp, :toroidal) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Allowed P_perp_model values selecting how P_perp is built. `:chi_perp_e` is the default. | ||||||||||||||||||||||||
| const ALLOWED_P_PERP_MODELS = (:chi_perp_e, :chi_perp_i, :P_phi, :D_perp, :c_beta, :tau_E) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||
| r_based_shear(rs, q, dq_dpsi, da_dpsi) -> Float64 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -132,7 +135,7 @@ end | |||||||||||||||||||||||
| # Internal: solve the Wd self-consistency loop for the chi_parallel-based | ||||||||||||||||||||||||
| # critical Δ (Connor-Hastie-Helander 2015). Returns dc_tmp as a Float64. | ||||||||||||||||||||||||
| function _solve_dc_tmp(; dc_type::Symbol, dr_val::Real, dgeo_val::Real, | ||||||||||||||||||||||||
| chi_perp::Real, t_e::Real, zeff::Real, tau_ee::Real, | ||||||||||||||||||||||||
| chi_perp_e::Real, t_e::Real, zeff::Real, tau_ee::Real, | ||||||||||||||||||||||||
| rs::Real, R0::Real, sval_r::Real, n_tor::Integer, | ||||||||||||||||||||||||
| max_iter::Integer=100, tol::Real=1e-10) | ||||||||||||||||||||||||
| dc_type in ALLOWED_DC_TYPES || | ||||||||||||||||||||||||
|
|
@@ -149,7 +152,7 @@ function _solve_dc_tmp(; dc_type::Symbol, dr_val::Real, dgeo_val::Real, | |||||||||||||||||||||||
| chi_par_lmfp = (2.0 * R0 * vte) / (sqrt(π) * n_tor * abs(sval_r) * Wd) | ||||||||||||||||||||||||
| chi_par = (chi_par_smfp * chi_par_lmfp) / | ||||||||||||||||||||||||
| (chi_par_smfp + chi_par_lmfp) | ||||||||||||||||||||||||
| Wd_new = sqrt(8.0) * (chi_perp / chi_par)^0.25 * | ||||||||||||||||||||||||
| Wd_new = sqrt(8.0) * (chi_perp_e / chi_par)^0.25 * | ||||||||||||||||||||||||
| (1.0 / sqrt((rs / R0) * abs(sval_r) * n_tor)) | ||||||||||||||||||||||||
| if abs(Wd_new - Wd) / max(abs(Wd), 1e-30) < tol | ||||||||||||||||||||||||
| Wd = Wd_new | ||||||||||||||||||||||||
|
|
@@ -165,22 +168,25 @@ function _solve_dc_tmp(; dc_type::Symbol, dr_val::Real, dgeo_val::Real, | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if dc_type === :lar | ||||||||||||||||||||||||
| return 0.5 * (-dr_val) * π^1.5 * | ||||||||||||||||||||||||
| (chi_par / chi_perp)^0.25 * | ||||||||||||||||||||||||
| (chi_par / chi_perp_e)^0.25 * | ||||||||||||||||||||||||
| sqrt((n_tor * abs(sval_r)) / (R0 * rs)) | ||||||||||||||||||||||||
| elseif dc_type === :rfitzp | ||||||||||||||||||||||||
| return -(sqrt(2.0) * π^1.5 * dr_val) / Wd | ||||||||||||||||||||||||
| elseif dc_type === :toroidal | ||||||||||||||||||||||||
| return 0.5 * (-dr_val) * π^1.5 * | ||||||||||||||||||||||||
| (chi_par / chi_perp)^0.25 * dgeo_val | ||||||||||||||||||||||||
| (chi_par / chi_perp_e)^0.25 * dgeo_val | ||||||||||||||||||||||||
| end | ||||||||||||||||||||||||
| return 0.0 | ||||||||||||||||||||||||
| end | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||
| slayer_parameters(; n_e, t_e, t_i, omega, omega_e, omega_i, | ||||||||||||||||||||||||
| qval, sval_r, bt, rs, R0, mu_i, zeff, | ||||||||||||||||||||||||
| chi_perp, chi_tor, | ||||||||||||||||||||||||
| chi_perp_e, chi_tor, | ||||||||||||||||||||||||
| m, n, | ||||||||||||||||||||||||
| chi_perp_i=1.0, tau_E=NaN, | ||||||||||||||||||||||||
| dlnn=NaN, dlnTe=NaN, dlnTi=NaN, | ||||||||||||||||||||||||
| P_perp_model=:chi_perp_e, | ||||||||||||||||||||||||
| dr_val=0.0, dgeo_val=0.0, | ||||||||||||||||||||||||
| dc_type=:none, ising=0, | ||||||||||||||||||||||||
| resistivity_model=SauterNeoModel(), | ||||||||||||||||||||||||
|
|
@@ -210,7 +216,23 @@ parametrization (P_perp/P_tor/D_norm; the older magnetic/electron Prandtl | |||||||||||||||||||||||
| - `R0` -- major radius [m] | ||||||||||||||||||||||||
| - `mu_i` -- ion mass in proton-mass units (e.g. 2.0 for D) | ||||||||||||||||||||||||
| - `zeff` -- effective charge | ||||||||||||||||||||||||
| - `chi_perp`, `chi_tor` -- perpendicular / toroidal heat diffusivity [m²/s] | ||||||||||||||||||||||||
| - `chi_perp_e`, `chi_tor` -- electron perpendicular heat / toroidal momentum diffusivity [m²/s] | ||||||||||||||||||||||||
| - `chi_perp_i` -- ion perpendicular heat diffusivity [m²/s] (used by `P_perp_model=:chi_perp_i`) | ||||||||||||||||||||||||
| - `dlnn`, `dlnTe`, `dlnTi` -- radial log-gradients of n, T_e, T_i in any common radial variable | ||||||||||||||||||||||||
| (only their ratios enter; required by `P_perp_model=:D_perp`) | ||||||||||||||||||||||||
| - `tau_E` -- whole-plasma energy confinement time [s] (required by `P_perp_model=:tau_E`) | ||||||||||||||||||||||||
|
Comment on lines
+220
to
+223
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two lines are what fails the Documentation job:
Suggested change
|
||||||||||||||||||||||||
| - `P_perp_model` -- how `P_perp` is built: | ||||||||||||||||||||||||
| + `:chi_perp_e` (default) -- τ_R·χ⊥,e/r_s² | ||||||||||||||||||||||||
| + `:chi_perp_i` -- τ_R·χ⊥,i/r_s² | ||||||||||||||||||||||||
| + `:P_phi` -- P_perp = P_tor (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 143) | ||||||||||||||||||||||||
| + `:D_perp` -- τ_R/τ_⊥ with τ_⊥ = r_s²/D_⊥ and D_⊥ from Eq. 16 of Fitzpatrick, Phys. Plasmas 29, | ||||||||||||||||||||||||
| 032507 (2022), with η_⊥ = η_∥: | ||||||||||||||||||||||||
| D_⊥ = c_β² η/μ₀ + (2/3)(1 − c_β²)[η_e τ_e/(1+η_e) χ⊥,e + η_i τ_i/(1+η_i) χ⊥,i] | ||||||||||||||||||||||||
| + `:c_beta` -- P_perp = C² with C = c_β (J.-K. Park, Phys. Plasmas 29, 072506 (2022), Eq. 10, with the | ||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small citation fix: in Park (2022) the C² term is in Eq. (9) and is defined in the text just below Eq. (10); Eq. (10) itself carries P, which is our |
||||||||||||||||||||||||
| thermal-conduction term K dropped). This is the χ⊥ → 0 limit of `:D_perp` (P_⊥ = μ₀D_⊥/η = c_β²), so it is | ||||||||||||||||||||||||
| a floor on P_perp; realistic anomalous transport makes D_⊥ much larger. | ||||||||||||||||||||||||
| + `:tau_E` -- P_perp = P_tor = τ_R/τ_E, overriding χ_φ (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 131) | ||||||||||||||||||||||||
| `chi_perp_e` still sets the critical-Δ `dc_tmp` in every mode. | ||||||||||||||||||||||||
| - `m`, `n` -- poloidal / toroidal mode numbers at the surface | ||||||||||||||||||||||||
| - `dr_val`, `dgeo_val` -- inputs for the critical-Δ formula | ||||||||||||||||||||||||
| - `dc_type` -- one of `:none`, `:lar`, `:rfitzp`, `:toroidal` | ||||||||||||||||||||||||
|
|
@@ -263,8 +285,11 @@ function slayer_parameters(; | |||||||||||||||||||||||
| omega::Real, omega_e::Real, omega_i::Real, | ||||||||||||||||||||||||
| qval::Real, sval_r::Real, bt::Real, | ||||||||||||||||||||||||
| rs::Real, R0::Real, mu_i::Real, zeff::Real, | ||||||||||||||||||||||||
| chi_perp::Real, chi_tor::Real, | ||||||||||||||||||||||||
| chi_perp_e::Real, chi_tor::Real, | ||||||||||||||||||||||||
| m::Integer, n::Integer, | ||||||||||||||||||||||||
| chi_perp_i::Real=1.0, tau_E::Real=NaN, | ||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||
| dlnn::Real=NaN, dlnTe::Real=NaN, dlnTi::Real=NaN, | ||||||||||||||||||||||||
| P_perp_model::Symbol=:chi_perp_e, | ||||||||||||||||||||||||
| dr_val::Real=0.0, dgeo_val::Real=0.0, | ||||||||||||||||||||||||
| dc_type::Symbol=:none, ising::Integer=0, | ||||||||||||||||||||||||
| resistivity_model::NeoResistivityModel=SauterNeoModel(), | ||||||||||||||||||||||||
|
|
@@ -366,10 +391,41 @@ function slayer_parameters(; | |||||||||||||||||||||||
| c_beta = sqrt(lbeta / (1.0 + lbeta)) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Effective Prandtl-like transport ratios | ||||||||||||||||||||||||
| tau_perp = rs^2 / chi_perp | ||||||||||||||||||||||||
| P_perp = tau_r / tau_perp | ||||||||||||||||||||||||
| tau_tor = rs^2 / chi_tor | ||||||||||||||||||||||||
| P_tor = tau_r / tau_tor | ||||||||||||||||||||||||
| if P_perp_model === :tau_E | ||||||||||||||||||||||||
| isfinite(tau_E) && tau_E > 0 || | ||||||||||||||||||||||||
| throw(ArgumentError("slayer_parameters: P_perp_model=:tau_E needs a positive tau_E, got $tau_E")) | ||||||||||||||||||||||||
| # P_⊥ = P_φ = τ_R/τ_E (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 131) | ||||||||||||||||||||||||
| P_tor = tau_r / tau_E | ||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked this against Fitzpatrick (2023), Phys. Plasmas 30, 092512. Eq. 131 is P⊥ = P_φ = τ_R/τ_E, but the τ_E there is the local energy confinement time τ_E(r) = r²/χ_E with χ_E uniform (Eqs. 81–83), not the whole-plasma confinement time. Eqs. 140–142 make this explicit: P⊥(r̂) = (τ_R0/τ_E0)·ĵ_oh(r̂) with τ_E0 = a²/χ_E, so the r² cancels and P⊥ = μ₀χ_E/η(r_s). The whole-plasma time from W_e/P_e or a scaling law is τ̄_E = κ_e a²/χ_E (Eqs. 37–38), with κ_e = (3/2)∫₀¹ T̂_e r̂ dr̂ / [−dT̂_e(1)/dr̂]. With Two ways to make it match: take the whole-plasma τ̄_E and use P⊥ = τ_R(r_s)·κ_e a²/(r_s² τ̄_E), which needs κ_e from the T_e profile and the minor radius; or take a uniform χ_E (= κ_e a²/τ̄_E) as the input, which makes this mode the same as the χ-based P⊥ with one number for every surface. Either way, the docstring should say which confinement time is meant and cite Eqs. 81–83 alongside Eq. 131. |
||||||||||||||||||||||||
| end | ||||||||||||||||||||||||
| P_perp = if P_perp_model === :chi_perp_e | ||||||||||||||||||||||||
| tau_r / (rs^2 / chi_perp_e) | ||||||||||||||||||||||||
| elseif P_perp_model === :chi_perp_i | ||||||||||||||||||||||||
| tau_r / (rs^2 / chi_perp_i) | ||||||||||||||||||||||||
| elseif P_perp_model === :P_phi || P_perp_model === :tau_E | ||||||||||||||||||||||||
| # P_⊥ = P_φ (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 143) | ||||||||||||||||||||||||
| P_tor | ||||||||||||||||||||||||
| elseif P_perp_model === :D_perp | ||||||||||||||||||||||||
| # D_⊥ from Fitzpatrick, Phys. Plasmas 29, 032507 (2022), Eqs. 4-6 and 16 (η_⊥ = η_∥), with | ||||||||||||||||||||||||
| # η_s/(1+η_s) = dlnT_s/(dlnn+dlnT_s) and τ = (T_e/T_i)(1+η_e)/(1+η_i) written flat-density safe. | ||||||||||||||||||||||||
| frac_e = dlnTe / (dlnn + dlnTe) | ||||||||||||||||||||||||
| frac_i = dlnTi / (dlnn + dlnTi) | ||||||||||||||||||||||||
| tau_F = (t_e / t_i) * (dlnn + dlnTe) / (dlnn + dlnTi) | ||||||||||||||||||||||||
| D_perp = c_beta^2 * eta / MU_0 + | ||||||||||||||||||||||||
| (2 / 3) * (1 - c_beta^2) * (frac_e * tau_F / (1 + tau_F) * chi_perp_e + frac_i / (1 + tau_F) * chi_perp_i) | ||||||||||||||||||||||||
|
Comment on lines
+410
to
+416
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked this against Fitzpatrick (2022) Eqs. 4–6 and 16: the expression and the docstring formula match the paper. Two small things. The intermediate ratios have a singularity the formula itself does not: with a vanishing ion (or electron) pressure gradient,
Suggested change
It would also help to say in the docstring what Eq. 16 implies at the edges, since users may be surprised: where T_e and T_i are flat, the χ terms vanish and P⊥ falls to the |
||||||||||||||||||||||||
| isfinite(D_perp) && D_perp > 0 || | ||||||||||||||||||||||||
| throw(ArgumentError("slayer_parameters: P_perp_model=:D_perp gave D_perp=$D_perp; " * | ||||||||||||||||||||||||
| "check dlnn/dlnTe/dlnTi (got $dlnn, $dlnTe, $dlnTi)")) | ||||||||||||||||||||||||
| # τ_⊥ = r_s²/D_⊥, P_⊥ = τ_R/τ_⊥ | ||||||||||||||||||||||||
| tau_r / (rs^2 / D_perp) | ||||||||||||||||||||||||
| elseif P_perp_model === :c_beta | ||||||||||||||||||||||||
| # C² = P_⊥ with C = c_β (J.-K. Park, Phys. Plasmas 29, 072506 (2022), Eq. 10, K = 0) | ||||||||||||||||||||||||
| c_beta^2 | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| throw(ArgumentError("slayer_parameters: unknown P_perp_model=$P_perp_model. " * | ||||||||||||||||||||||||
| "Allowed: $(ALLOWED_P_PERP_MODELS)")) | ||||||||||||||||||||||||
| end | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Normalized beta-related width and Δ-normalization | ||||||||||||||||||||||||
| d_beta = c_beta * d_i | ||||||||||||||||||||||||
|
|
@@ -378,7 +434,7 @@ function slayer_parameters(; | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Critical-Δ offset from chi_parallel matching | ||||||||||||||||||||||||
| dc_tmp = _solve_dc_tmp(; dc_type=dc_type, dr_val=dr_val, dgeo_val=dgeo_val, | ||||||||||||||||||||||||
| chi_perp=chi_perp, t_e=t_e, zeff=zeff, | ||||||||||||||||||||||||
| chi_perp_e=chi_perp_e, t_e=t_e, zeff=zeff, | ||||||||||||||||||||||||
| tau_ee=tau_ee, rs=rs, R0=R0, sval_r=sval_r, | ||||||||||||||||||||||||
| n_tor=n) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.