Repository navigation
Conversation
… kinetic HDF5 Add an optional chi_i (ion perpendicular heat diffusivity) dataset to the kinetic-profile reader and writer, alongside chi_e and chi_phi. Ship chi_i in the DIII-D-like example kinetic file, built like its chi_e: AOT CHI_I of DIII-D 147131 at 2300 ms, mapped rho_N -> psi_N with EFIT01 RHOVN, the spurious zero at psi_N = 1 dropped, Gaussian-smoothed with sigma = 12 of 201 rho_N points (the width that best reproduces the example chi_e from AOT CHI_E). Range 0.46-2.1 m^2/s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…i_perp to chi_perp_e New [SLAYER] P_perp_model selects how the perpendicular Prandtl number is built: - chi_perp_e (default, unchanged numbers): tau_R*chi_perp_e/r_s^2 - chi_perp_i: tau_R*chi_perp_i/r_s^2 (kinetic-file chi_i, scalar fallback) - P_phi: P_perp = P_tor (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 143) - D_perp: tau_perp = r_s^2/D_perp (Fitzpatrick, Phys. Plasmas 29, 032507 (2022)) - c_beta: C^2 = P_perp with C = c_beta (Park et al., Phys. Plasmas 29, 122505 (2022)) Breaking: the [SLAYER] chi_perp key is renamed chi_perp_e. chi_perp_e still sets the critical-Delta offset in every mode. Regression harness diiid_slayer_n1 develop vs local: 17 unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…= tau_R/tau_E) A single [SLAYER] tau_E [s] for the whole plasma sets P_perp = P_tor = tau_R/tau_E at every surface (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 131). validate() requires a positive tau_E when this model is selected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…. 16
P_perp_model = D_perp now builds D_perp per surface from Eq. 16 of Fitzpatrick,
Phys. Plasmas 29, 032507 (2022), with eta_perp = eta_par:
D_perp = c_beta^2 eta/mu0 + (2/3)(1 - c_beta^2)[eta_e tau_e/(1+eta_e) chi_perp_e
+ eta_i tau_i/(1+eta_i) chi_perp_i]
using the n, T_e, T_i log-gradients at the surface (Eqs. 4-6, written flat-density
safe). The scalar D_perp input is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e DIII-D-like SLAYER example Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Effect of each
|
P_perp_model |
P_⊥ (2/1, 3/1, 4/1) | P_φ (2/1, 3/1, 4/1) | γ [Hz] (2/1, 3/1, 4/1) | Δγ vs default (2/1, 3/1, 4/1) | ω [Hz] 2/1 |
|---|---|---|---|---|---|
chi_perp_e |
50.3, 44, 35.7 | 34.7, 24.7, 19 | 192, -251, -1012 | — | -10527 |
chi_perp_i |
29.9, 26.4, 12.5 | 34.7, 24.7, 19 | 213, -274, -1217 | +11 %, -9 %, -20 % | -10523 |
P_phi |
34.7, 24.7, 19 | 34.7, 24.7, 19 | 206, -277, -1123 | +8 %, -10 %, -11 % | -10525 |
D_perp |
16.4, 17.5, 10.9 | 34.7, 24.7, 19 | 242, -296, -1249 | +26 %, -18 %, -23 % | -10516 |
c_beta |
0.0133, 0.0088, 0.00645 | 34.7, 24.7, 19 | 313, -588, -1669 | +63 %, -134 %, -65 % | -10133 |
tau_E |
34.5, 30.8, 27.6 | 34.5, 30.8, 27.6 | 206, -264, -1034 | +8 %, -5 %, -2 % | -10525 |
The Δγ column is (γ − γ_default)/|γ_default|, so + means more unstable. For scale, the run-to-run AMR noise on γ is about 0.01 %.
Takeaways
- Only
c_betachanges the answer qualitatively. Its P_⊥ = c_β² ≈ 0.01, three to four orders of magnitude below every other model. The 2/1 drive rises about 60 %, the stable 3/1 and 4/1 roots damp 65–135 % harder, and ω on the 2/1 shifts about 4 %. Every other model shifts ω by less than 0.1 %. - The χ-based models move γ by roughly 10–25 %.
chi_perp_iuses the example's χ⊥,i, which is about 0.4–0.6 of χ⊥,e at these surfaces. That halves P_⊥ and moves γ by about 10 % at the 2/1 and 3/1 and 20 % at the 4/1.D_perpgives the smallest P_⊥ of the transport-based models, so it moves γ the furthest, by 18–26 %.- Across these models, a lower P_⊥ makes the 2/1 more unstable and the 3/1 and 4/1 more stable.
P_phiandtau_Eland close together. With τ_E = 0.1 s, τ_R/τ_E happens to be close to the χ_φ-based P_φ on the 2/1.tau_Ealso overrides P_φ, so its 3/1 and 4/1 sit nearer the default. γ scales with the chosen τ_E, so these numbers only illustrate the model.chi_perp_e(the default) reproduces develop exactly; see the regression report in the PR description.
The unit tests (Pkg.test() at 27d0744 on feynman) pass.
🤖 Generated with Claude Code
Example kinetic-file χ profiles vs the DIII-D 147131 AOT sourceEach panel compares
At the SLAYER surfaces (new
Notes
🤖 Generated with Claude Code |
… and describe c_beta as the no-transport limit of D_perp The SLAYER file headers and the c_beta P_perp_model cited "Park et al., Phys. Plasmas 29, 122505 (2022)", which does not exist. The paper is J.-K. Park, Phys. Plasmas 29, 072506 (2022), doi:10.1063/5.0093079, as docs/src/citations.md already lists. Its Eq. 10 defines C² = c_β² + (1 − c_β²)K; C = c_β drops the thermal-conduction K, which makes P_perp = c_β² the χ⊥ → 0 limit of the D_perp model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o feature/slayer-pperp-models
|
@logan-nc @d-burg This adds a variety of options for perpendicular diffusion inputs. It doesn't change the default yet, so selecting the chi_perp_e is the same as what currently exists. You can see in the comparison that the only really different one is the c_beta which is good news (and encouragement to have this increased fidelity vs the Fortran slayer implementation). I think that we should move to full D_perp as default since there is not a literature justification for chi_perp_e ~ D_perp and if people already need chi_phi and chi_perp_e inputs than its not too crazy to also have them input chi_perp_i. It's encouraging that the tau_E choice is right order of magnitude (using tau_E = chi_phi and P_perp = P_phi) so that is also a helpful, user friendly, and control friendly option. After this gets merged, then either @d-burg or I should make a PR changing the default to D_perp and removing the chi_perp_e and chi_perp_i options. Let me know if you have any questions on this. Thanks! |
|
At a high level, this looks good. I agree that if someone has chi_phi and chi_perp_e, they likely have chi_perp_i on hand. If they don't have things, or are lazy then letting them assert a "reasonable" tau_E for their device is a great way to get results quick. |
d-burg
left a comment
There was a problem hiding this comment.
Thanks -- the switch is cleanly done, the default path is the same arithmetic as before, and the rename is complete. I checked the new models against the papers: D_perp matches Fitzpatrick (2022) Eqs. 4–6 and 16, c_beta matches Park (2022) and is the exact χ⊥ → 0 limit of the coded D_perp, and P_phi matches Fitzpatrick (2023) Eq. 143. tau_E does not yet match Eq. 131 (inline at line 400). I also compared the old and new example file: only chi_i and the provenance text were added, and every pre-existing dataset is byte-identical.
A mix of top level feedback from myself and claude:
Blocking
- Docs CI. Two docstring lines parse as Markdown links (suggestion inline at
LayerParameters.jl:220). - Rebase onto develop. This now conflicts in 7 files since #298 landed. Note for the binary file: #298 raised
chi_einTkMkr_D3Dlike_Hmode_kinetic.h5, and this branch's copy predates that, sochi_ineeds to be added to develop's file rather than taking this branch's version, otherwise thechi_echange is undone. Thechi_i/chi_eratios in your table will change accordingly.
On making D_perp the default and removing chi_perp_e / chi_perp_i
I agree D_perp is the better-founded model, but I'd settle a few things before switching:
D_perpis Fitzpatrick's derived perpendicular particle diffusivity: c_β²η⊥/μ₀ plus (2/3)(1 − c_β²)(n T_e′χ⊥,e + n T_i′χ⊥,i)/p′, built from the electron and ion energy diffusivities. By comparisonchi_perp_eis an electron-only proxy, so I'd describe it in the docstring and release note as the backward-compatible choice rather than "the" P⊥. One caveat for the default: where the temperature profiles are flat, Eq. 16 reduces to thec_betafloor, which your table shows moves γ by 60–130 %, so flat-temperature regions of a real profile would change answers a lot.tau_Eneeds fixing before it is advertised as the quick option: Eq. 131's τ_E is the local r²/χ_E, not the whole-plasma confinement time, so as documented this mode is off by r̂_s²/κ_e (details inline).- χ⊥,e stays a required input in every mode because it sets the critical-Δ width, so it can't go away even if the model option does. This PR is already a breaking rename of a key every SLAYER deck sets; I'd rather agree the end state now so users migrate once.
- Please add one harness case with a non-default
P_perp_model(your table already has the reference numbers), so a later default change has a baseline.
Data question. The example file's provenance attribute now names DIII-D 147131 at 2300 ms as the source of chi_i; the previous text named no shot. Has releasing this AOT-derived profile in a public repository been cleared under the DIII-D data policy? Since the provenance is being rewritten anyway, it should also use the dataset names chi_e and chi_phi, not "chi_perp" and "chi_tor".
Small, outside the diff
docs/src/kinetic_forces.mddocuments the kinetic HDF5 schema withoutchi_iand callschi_e"the" perpendicular heat diffusivity; therun_slayerdocstring likewise mentions onlychi_e/chi_phi.- An old deck with
chi_perp = ...is rejected by the generic unknown-key error, which is the important part, but a one-line hint whenchi_perpis among the unknown keys ("renamed to chi_perp_e") would save users a search through several dozen names. - Fitzpatrick (2022) and (2023) are cited for three of the six models but aren't in
docs/resources; adding them would let later reviewers check the equations.
| - `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`) |
There was a problem hiding this comment.
These two lines are what fails the Documentation job: [m²/s] (used by ...) and [s] (required by ...) parse as Markdown links (the parser skips the space between ] and (), and this docstring is spliced into inner_layer.md. A comma after the unit bracket, as the build_slayer_inputs docstring already does, removes both. The suggestion also adds :D_perp to the models that use chi_perp_i.
| - `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`) | |
| - `chi_perp_i` -- ion perpendicular heat diffusivity [m²/s], used by `P_perp_model=:chi_perp_i` and `:D_perp` | |
| - `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` |
| # 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) |
There was a problem hiding this comment.
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, frac_i and tau_F both go infinite and the product gives Inf·0 = NaN, so this throws although Eq. 16 is finite there. Writing the weights over one common denominator is the same arithmetic (η_e τ_e/(1+η_e) = T_e·dlnTe/dp and likewise for ions), leaves only p′ = 0 singular, and makes the physical content visible: the bracket is (n T_e′ χ⊥,e + n T_i′ χ⊥,i)/p′.
| # 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) | |
| # D_⊥ from Fitzpatrick, Phys. Plasmas 29, 032507 (2022), Eqs. 4-6 and 16 (η_⊥ = η_∥); the weights η_s τ_s/(1+η_s) equal n T_s'/p'. | |
| dp = t_e * (dlnn + dlnTe) + t_i * (dlnn + dlnTi) | |
| D_perp = c_beta^2 * eta / MU_0 + | |
| (2 / 3) * (1 - c_beta^2) * (t_e * dlnTe * chi_perp_e + t_i * dlnTi * chi_perp_i) / dp |
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 c_beta value (≈ 0.01 here), and where the species pressure gradients have opposite signs (hollow density) the weights can exceed 1. A test at a flat-temperature point would pin the first.
| 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, |
There was a problem hiding this comment.
tau_E and the log-gradients default to NaN so that a model which needs them fails loudly, but chi_perp_i defaults to 1.0 m²/s, so :chi_perp_i or :D_perp called without it returns a plausible-looking number. I'd default it to NaN here and in build_slayer_inputs, and move the isfinite(...) && ... > 0 check out of the :D_perp branch to just after the if block so it applies to P_perp for every model: today a zero, negative or NaN χ⊥,i (a partly-zero profile, or spline undershoot) gives P⊥ ≤ 0 in :chi_perp_i mode with no error.
| + `: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 |
There was a problem hiding this comment.
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 P_tor. I'd cite "Eq. 9, with C² = c_β² + (1 − c_β²)K and K = 0" here and at line 423. On line 230, please also define τ_e = τ/(1+τ), τ_i = 1/(1+τ), η_s = dlnT_s/dlnn, and note that this τ is (T_e/T_i)(1+η_e)/(1+η_i), the opposite orientation to the tau = T_i/T_e field of SLAYERParameters.
| chi_perp_e = loaded.chi_perp_e === nothing ? control.chi_perp_e : loaded.chi_perp_e | ||
| chi_tor = loaded.chi_tor === nothing ? control.chi_tor : loaded.chi_tor | ||
| (loaded.chi_perp === nothing || loaded.chi_tor === nothing) && @warn( | ||
| (loaded.chi_perp_e === nothing || loaded.chi_tor === nothing) && @warn( |
There was a problem hiding this comment.
In tau_E mode P_tor is replaced by τ_R/τ_E, so the file's chi_phi and the scalar chi_tor are ignored; that is only stated in the slayer_parameters docstring. Please say it in the SLAYERControl docstring and the TOML annotation too (suggestion on the example deck), and log one @info when the mode is active. This warning should also depend on the model: as written it reports a chi_tor fallback in tau_E mode, and a chi_perp_e fallback in c_beta, P_phi and tau_E mode with dc_type = "none", where those values do not enter the result.
| chi_perp_e = 1.0 # fallback only; the kinetic file supplies χ⊥,e(ψ) | ||
| chi_perp_i = 1.0 # fallback only; the kinetic file supplies χ⊥,i(ψ) | ||
| chi_tor = 1.0 # fallback only; the kinetic file supplies χ_φ(ψ) | ||
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]) |
There was a problem hiding this comment.
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]) | |
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]; also replaces the χ_φ-based P_tor) |
| # η_e = 2, η_i = 3, T_e = T_i ⇒ τ = 3/4, τ_e = 3/7, τ_i = 4/7 | ||
| d1 = slayer_parameters(; base..., P_perp_model=:D_perp, grads..., chi_perp_i=2.0) | ||
| D_hand = d1.c_beta^2 * d1.eta / MU_0 + (2 / 3) * (1 - d1.c_beta^2) * ((2 / 3) * (3 / 7) * 1.0 + (3 / 4) * (4 / 7) * 2.0) | ||
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 |
There was a problem hiding this comment.
With T_e = T_i this check passes whichever way round the temperature ratio is written, and the struct's own tau is T_i/T_e, so I'd add a T_e ≠ T_i point (hand numbers: τ = 3/2, τ_e = 3/5, τ_i = 2/5; not run). One build_slayer_inputs test with P_perp_model=:D_perp would also cover the gradient forwarding from the profile splines, which is otherwise untested. I haven't run this test myself so this is just a suggestion, you should confirm on your end whether it checks out.
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 | |
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 | |
| # T_e = 2T_i ⇒ τ = 3/2, τ_e = 3/5, τ_i = 2/5: fixes the orientation of the temperature ratio | |
| d2 = slayer_parameters(; base..., t_e=2000.0, P_perp_model=:D_perp, grads..., chi_perp_i=2.0) | |
| D_hand2 = d2.c_beta^2 * d2.eta / MU_0 + (2 / 3) * (1 - d2.c_beta^2) * ((2 / 3) * (3 / 5) * 1.0 + (3 / 4) * (2 / 5) * 2.0) | |
| @test d2.P_perp ≈ d2.tau_r * D_hand2 / d2.rs^2 rtol = 1e-12 |
| ctrl.P_perp_model in _VALID_P_PERP_MODELS || | ||
| throw(ArgumentError("SLAYERControl: P_perp_model=$(ctrl.P_perp_model) " * | ||
| "not in $(_VALID_P_PERP_MODELS)")) | ||
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && ctrl.tau_E > 0) || |
There was a problem hiding this comment.
Missing, non-positive and NaN tau_E are caught here, but inf gets through and only fails later inside slayer_parameters, after the equilibrium and stability stages. Adding isfinite makes the two checks agree.
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && ctrl.tau_E > 0) || | |
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && isfinite(ctrl.tau_E) && ctrl.tau_E > 0) || |
| 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 |
There was a problem hiding this comment.
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 tau_E documented as the whole-plasma confinement time, this code's P⊥ differs from the paper's by r̂_s²/κ_e. For a T_e profile like (1 − r̂²), κ_e ≈ 0.19, so the 3/1 and 4/1 surfaces come out about 2–4× larger than Eq. 131 gives, and the error grows outward.
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.
|
Thanks for the thorough review @d-burg I'd just like to reinforce that DIII-D data cannot be included in this open repo directly. The approach for the "DIIID-like" example should be to cite a paper if available and make a roughly matching functional form of the profile needed. Ideally, note the functional form somewhere in annotations / docs so it's clear its not a direct profile fit to data (eg "y = y0 (1 -x^2) where y0=3.0 roughly matches [Name Journal 2026]" or some such). |

Release note
P_perp_model = "chi_perp_e"(harness @ d5937d0)chi_perptochi_perp_ein[SLAYER]ofgpec.toml(and thechi_perpkeyword ofbuild_slayer_inputs/slayer_parameters).SLAYER can now build the perpendicular Prandtl number P_⊥ in several ways, selected with the new
[SLAYER] P_perp_modeloption. The kinetic HDF5 schema gains an optionalchi_i(ion perpendicular heat diffusivity) profile, and the DIII-D-like example kinetic file now carries one.P_perp_modelchi_perp_e(default, unchanged behaviour)chi_perp_iP_phiD_perpc_betaD_perp; a floor on P_⊥)tau_Etau_E[s])chi_perp_estill sets the critical-Δdc_tmpin every mode.This PR also corrects the Park citation in the SLAYER file headers (
SLAYER.jl,Riccati.jl,LayerThickness.jl,LayerParameters.jl). They cited "Park et al., Phys. Plasmas 29, 122505 (2022)", which does not exist; the paper is J.-K. Park, Phys. Plasmas 29, 072506 (2022), doi:10.1063/5.0093079, asdocs/src/citations.mdalready lists.Regression report
regress --cases diiid_slayer_n1,diiid_n1 --refs 0e68a0553,d5937d04e --forceon feynman (SLURM, develop vs head after the develop merge, both fresh, manifest pinned).Every quantity is unchanged in both cases: the default
P_perp_model = "chi_perp_e"reproduces develop, and the newchi_idataset is not read by the default model.Notes for reviewers
chi_iis built the same way as the examplechi_e: AOTCHI_Iof DIII-D 147131 at 2300 ms, mapped ρ_N → ψ_N with EFIT01 RHOVN. The spurious zero at ψ_N = 1 is dropped, and the profile is Gaussian-smoothed with σ = 12 of the 201 uniform ρ_N points. That width gives the smallest error when the same smoothing rebuilds the examplechi_efrom AOTCHI_E(about 10 % RMS in log). The resulting range is 0.46–2.1 m²/s, and the file'sprovenanceattribute records the recipe.chi_tordocstrings in the same three files, so whichever merges second needs a small conflict resolution.D_perpmode: η_⊥ = η_∥ is assumed, and the η_s/(1+η_s) factors are written as gradient ratios so flat density is safe.🤖 Generated with Claude Code