Skip to content
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

Final transfer version #306

Merged
merged 58 commits into from
Jan 18, 2025
Merged
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e6676ef
Update naming of update_qpar for ions to be update_ion_qpar, in line …
LucasMontoya4 Sep 18, 2024
53a673c
Add ion_physics flag to determine drift_kinetic, gyrokinetic or bragi…
LucasMontoya4 Sep 18, 2024
6f6df74
Update gyrokinetic flag uses throughout the repo, so that instead of …
LucasMontoya4 Sep 18, 2024
e92dc5c
Some of the Braginskii functionality (unfinished)
LucasMontoya4 Sep 19, 2024
f92f20f
Merge branch 'master' into ion_flags
LucasMontoya4 Sep 19, 2024
a0e2b20
Merge branch 'ion_flags' into ion_braginskii_fluid
LucasMontoya4 Sep 19, 2024
1dbf661
Make initialisation for braginskii ion heat flux be calculated from u…
LucasMontoya4 Sep 19, 2024
77a30c1
Merge branch 'master' into ion_braginskii_fluid
LucasMontoya4 Sep 19, 2024
3b9bc66
Add braginskii heat flux formula by adding an ion dT_dz component in …
LucasMontoya4 Sep 20, 2024
1d8b559
add loop to allow n_neutral_species = 0 and CFL plots to still be mad…
LucasMontoya4 Sep 20, 2024
bb64609
Merge branch 'master' into ion_braginskii_fluid
LucasMontoya4 Sep 20, 2024
77cce1a
Move order of krook_collisions.jl inclusion to allow velocity_moments…
LucasMontoya4 Sep 20, 2024
18cd33e
Add plotting for collisionality (comparing gradient scale lengths to …
LucasMontoya4 Sep 21, 2024
9a1e30a
Add comparison plots functionality for collisionality_plots, and add …
LucasMontoya4 Sep 23, 2024
0e28693
Add comments to boundary condition of braginskii heat flux, and add d…
LucasMontoya4 Sep 23, 2024
5ef19bd
Fix bug during restarts to allow for multiple sources while external_…
LucasMontoya4 Sep 23, 2024
4213c52
Make collisionality_plots plot the last timestep value (which was ori…
LucasMontoya4 Sep 23, 2024
6fc4c76
Merge branch 'master' into ion_braginskii_fluid
LucasMontoya4 Sep 23, 2024
14e510d
Merge branch 'master' into ion_braginskii_fluid
johnomotani Sep 26, 2024
701ab84
Add option of overlaying what the Braginskii heat flux would be for t…
LucasMontoya4 Sep 27, 2024
0e6d395
Add option for super Gaussian with decay of 4th power instead of seco…
LucasMontoya4 Sep 27, 2024
b2b001d
Merge branch 'master' into ion_braginskii_fluid
LucasMontoya4 Sep 27, 2024
9d92ca2
Fix typo when energy source used
LucasMontoya4 Sep 28, 2024
fab3f8a
Don't plot braginskii overlay if the original simulation itself was a…
LucasMontoya4 Sep 30, 2024
8e5ecd9
Add string to braginskii_overlay system to tell you its an overlay, w…
LucasMontoya4 Oct 1, 2024
78bf27e
Merge branch 'ion_braginskii_fluid' of github.com:mabarnes/moment_kin…
LucasMontoya4 Oct 1, 2024
8309e99
Fix PI_controller file io for option
LucasMontoya4 Oct 3, 2024
0062ca8
Edit PI_controller for density_midpoint_control option to begin the s…
LucasMontoya4 Oct 3, 2024
1394626
remove printing function that was used for debugging
LucasMontoya4 Oct 3, 2024
22f91bd
Change naming from Braginskii_ions to coll_krook_ions, and change ins…
LucasMontoya4 Oct 3, 2024
0462f32
Don't evolve shape function if heat flux closure comes from coll_kroo…
LucasMontoya4 Oct 3, 2024
7348809
Allow collisionality_plots to animate comparison runs with different …
LucasMontoya4 Oct 4, 2024
dc627cf
add neutral controller_integral file_io.jl bug fix (ion version was f…
LucasMontoya4 Oct 4, 2024
44ee25a
skip chodura condition check in coll_krook fluid ion case, so that ng…
LucasMontoya4 Oct 6, 2024
1b1cac1
Merge branch 'master' into remove_redundant_shapefn_evolution
LucasMontoya4 Oct 6, 2024
bc7401d
change gamma back to 2, and change the boundary condition for heat fl…
LucasMontoya4 Oct 7, 2024
8155690
Create new module for collision_frequency calculations, so that krook…
LucasMontoya4 Oct 7, 2024
66cbcc1
Change gamma_i to 2.5, from Stangeby (25.2)
LucasMontoya4 Oct 7, 2024
eb01872
Add temperature_midpoint_control source option. This will change the …
LucasMontoya4 Oct 9, 2024
b8d8b6b
Merge branch 'master' into remove_redundant_shapefn_evolution
LucasMontoya4 Oct 9, 2024
499b9ec
Change gamma_i boundary condition for coll_krook heat flux closure de…
LucasMontoya4 Oct 15, 2024
06dcf5d
Correction to heat flux itself, should be 1D instead of 3D calculation
LucasMontoya4 Oct 31, 2024
63321ad
Include all input files that I made for transfer, and the files that …
LucasMontoya4 Jan 7, 2025
b65ac35
Add tests for multi source functionality and PI controllers
LucasMontoya4 Jan 8, 2025
c91c51e
small changes
LucasMontoya4 Jan 8, 2025
f870002
Merge remote-tracking branch 'origin/master' into final_transfer_version
LucasMontoya4 Jan 8, 2025
124a715
Merge branch 'master' of github.com:mabarnes/moment_kinetics into fin…
LucasMontoya4 Jan 13, 2025
a227169
Merge branch 'master' into final_transfer_version
LucasMontoya4 Jan 14, 2025
1dd6046
Merge remote-tracking branch 'origin/master' into final_transfer_version
LucasMontoya4 Jan 14, 2025
96032af
move transfer input files from examples to publication inputs folder
LucasMontoya4 Jan 14, 2025
b3c5f7f
Add a couple of example multi source files with a collisional closure…
LucasMontoya4 Jan 14, 2025
eabb5e9
deleted transfer input files as they were moved
LucasMontoya4 Jan 14, 2025
e3035b3
Add docs page for collision_frequencies.jl
LucasMontoya4 Jan 14, 2025
bed3de4
remove example files so they are not run by remote server checks
LucasMontoya4 Jan 16, 2025
611c284
Change input file for multi source tests to only include 2 tests, whi…
LucasMontoya4 Jan 16, 2025
41a17b1
Comment out julia-actions/cache in documentation CI job
johnomotani Jan 16, 2025
1553fa6
Fix MPI in setup_external_sources!() when `ignore_MPI = true`
johnomotani Jan 17, 2025
af475cc
Apply suggestions from code review
johnomotani Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add plotting for collisionality (comparing gradient scale lengths to …
…mean free path) and braginskii heat flux boundary condition at walls, following Stangeby (though I haven't checked the subtracted part for conductive heat flux yet).
LucasMontoya4 committed Sep 21, 2024
commit 18cd33e9a3cd3e4028603435516c7618562d4c37
Original file line number Diff line number Diff line change
@@ -346,6 +346,8 @@ function makie_post_process(run_dir::Union{String,Tuple},

sound_wave_plots(run_info; plot_prefix=plot_prefix)

collisionality_plots(run_info, plot_prefix)

if all(ri === nothing for ri ∈ run_info_dfns)
nvperp = nothing
else
@@ -807,6 +809,24 @@ function _setup_single_input!(this_input_dict::OrderedDict{String,Any},
plot_steady_state_residual=false,
animate_steady_state_residual=false,
)

set_defaults_and_check_section!(
this_input_dict, "collisionality_plots";
plot=true,
plot_dT_dz_vs_z=false,
animate_dT_dz_vs_z=false,
plot_mfp_vs_z=false,
animate_mfp_vs_z=false,
plot_nu_ii_vth_mfp_vs_z = false,
plot_LT_mfp_vs_z = false,
animate_LT_mfp_vs_z = false,
plot_LT_dT_dz_temp_vs_z = false,
plot_Ln_mfp_vs_z = false,
animate_Ln_mfp_vs_z = false,
plot_Lupar_mfp_vs_z = false,
animate_Lupar_mfp_vs_z = false,
animation_ext = "gif"
)

# We allow top-level options in the post-processing input file
check_sections!(this_input_dict; check_no_top_level_options=false)
@@ -8130,6 +8150,202 @@ function timestep_diagnostics(run_info, run_info_dfns; plot_prefix=nothing, it=n
return steps_fig, dt_fig, CFL_fig
end



function collisionality_plots(run_info, plot_prefix=nothing)
# plot the mean free path of the ions at every point in z, and on the same graph
# plot the lengthscales of the gradients of all moments at each point in z
#println("run_info is ", run_info)
println("Making plots for collisionality")
if !isa(run_info, Tuple)
run_info = (run_info,)
end

input = Dict_to_NamedTuple(input_dict["collisionality_plots"])
temperature_input = Dict_to_NamedTuple(input_dict["temperature"])

mfp = get_variable(run_info, "mfp")
L_T = get_variable(run_info, "L_T")
L_n = get_variable(run_info, "L_n")
L_upar = get_variable(run_info, "L_upar")

if input.plot_mfp_vs_z
variable_name = "mean_free_path"
variable = mfp
variable_prefix = plot_prefix * variable_name
plot_vs_z(run_info, variable_name, is=1, data=variable, input=temperature_input,
outfile=variable_prefix * "_vs_z.pdf")
end

if input.animate_mfp_vs_z
variable_name = "mean_free_path"
variable = mfp
variable_prefix = plot_prefix * variable_name
animate_vs_z(run_info, variable_name, is=1, data=variable, input=temperature_input,
outfile=variable_prefix * "_vs_z." * input.animation_ext)
end
# TASKS: plot mean free path vs z, plot collision frequency vs z, make sure it agrees
# with original plot for it, and plot thermal speed and make sure that agrees, and then
# make sure that the mean free path then makes sense.
# Then plot the temperature and temperature gradient on the same plot
# Eventually plot the upar and dupar_dz and density and ddens_dz on plots too. Again,
# make sure they agree with the original plots.
if input.plot_dT_dz_vs_z
variable_name = "dT_dz"
variable = nothing
try
variable = get_variable(run_info, variable_name)
catch e
return makie_post_processing_error_handler(
e,
"collisionality_plots () failed for $variable_name - could not load data.")
end
#println("variable is ", variable)
variable_prefix = plot_prefix * variable_name
plot_vs_z(run_info, variable_name, is=1, data=variable, input=temperature_input,
outfile=variable_prefix * "_vs_z.pdf")
end

if input.animate_dT_dz_vs_z
variable_name = "dT_dz"
variable = nothing
try
variable = get_variable(run_info, variable_name)
catch e
return makie_post_processing_error_handler(
e,
"collisionality_plots () failed for $variable_name - could not load data.")
end
#println("variable is ", variable)
variable_prefix = plot_prefix * variable_name
animate_vs_z(run_info, variable_name, is=1, data=variable, input=temperature_input,
outfile=variable_prefix * "_vs_z." * input.animation_ext)
end

if input.plot_nu_ii_vth_mfp_vs_z
vth = get_variable(run_info, "thermal_speed")
nu_ii = get_variable(run_info, "collision_frequency_ii")
variable_prefix = plot_prefix * "checking_mfp_vth_and_nu_ii"
#println("vth[1] is ", vth[1])
fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
plot_1d(run_info[1].z.grid, vth[1][:,1,1,21], xlabel="z",
ylabel="values", label="vth", ax=ax[1], title = "checking_mfp_vth")
plot_1d(run_info[1].z.grid, nu_ii[1][:,1,1,21], label="nu_ii", ax=ax[1])
plot_1d(run_info[1].z.grid, mfp[1][:,1,1,21], label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
#plot_1d(z.grid, select_slice(error, :z; input=input), xlabel=L"z",
# ylabel=norm_label, ax=ax[2])
outfile = variable_prefix * "_vs_z.pdf"
save(outfile, fig)
end

if input.plot_LT_dT_dz_temp_vs_z
dT_dz = get_variable(run_info, "dT_dz")
temp = get_variable(run_info, "temperature")
variable_prefix = plot_prefix * "LT_dT_dz_temp"
fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
plot_1d(run_info[1].z.grid, L_T[1][:,1,1,21], xlabel="z",
ylabel="values", label="L_T", ax=ax[1], title = "LT_dT_dz_temp")
plot_1d(run_info[1].z.grid, dT_dz[1][:,1,1,21], label="dT_dz", ax=ax[1])
plot_1d(run_info[1].z.grid, temp[1][:,1,1,21], label="temp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z.pdf"
save(outfile, fig)
end

if input.plot_LT_mfp_vs_z
variable_prefix = plot_prefix * "LT_mfp_first_comparison"
fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
plot_1d(run_info[1].z.grid, L_T[1][:,1,1,21], xlabel="z",
ylabel="values", label="L_T", ax=ax[1], title = "L_T and mean free path comparison")
plot_1d(run_info[1].z.grid, mfp[1][:,1,1,21], label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z.pdf"
save(outfile, fig)
end

if input.animate_LT_mfp_vs_z
nt = length(mfp[1][1,1,1,:])
variable_prefix = plot_prefix * "LT_mfp_first_comparison"

fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
frame_index = Observable(1)
animate_1d(run_info[1].z.grid, L_T[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="L_T", ax=ax[1])
animate_1d(run_info[1].z.grid, mfp[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z." * input.animation_ext
save_animation(fig, frame_index, nt, outfile)
end

if input.plot_Ln_mfp_vs_z
variable_prefix = plot_prefix * "Ln_mfp_first_comparison"
fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
plot_1d(run_info[1].z.grid, L_n[1][:,1,1,21], xlabel="z",
ylabel="values", label="L_n", ax=ax[1], title = "Ln and mean free path comparison")
plot_1d(run_info[1].z.grid, mfp[1][:,1,1,21], label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z.pdf"
save(outfile, fig)
end

if input.animate_Ln_mfp_vs_z
nt = length(mfp[1][1,1,1,:])
variable_prefix = plot_prefix * "Ln_mfp_first_comparison"

fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
frame_index = Observable(1)
animate_1d(run_info[1].z.grid, L_n[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="L_n", ax=ax[1])
animate_1d(run_info[1].z.grid, mfp[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z." * input.animation_ext
save_animation(fig, frame_index, nt, outfile)
end

if input.plot_Lupar_mfp_vs_z
variable_prefix = plot_prefix * "Lupar_mfp_first_comparison"
fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
plot_1d(run_info[1].z.grid, L_upar[1][:,1,1,21], xlabel="z",
ylabel="values", label="L_upar", ax=ax[1], title = "Lupar and mean free path comparison")
plot_1d(run_info[1].z.grid, mfp[1][:,1,1,21], label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z.pdf"
save(outfile, fig)
end

if input.animate_Lupar_mfp_vs_z
nt = length(mfp[1][1,1,1,:])
variable_prefix = plot_prefix * "Lupar_mfp_first_comparison"

fig, ax, legend_place = get_1d_ax(1; get_legend_place=:below)
frame_index = Observable(1)
animate_1d(run_info[1].z.grid, L_upar[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="L_upar", ax=ax[1])
animate_1d(run_info[1].z.grid, mfp[1][:,1,1,:],
frame_index=frame_index, xlabel="z", ylabel="values",
label="mfp", ax=ax[1])
Legend(legend_place[1], ax[1]; tellheight=true, tellwidth=false,
orientation=:horizontal)
outfile = variable_prefix * "_vs_z." * input.animation_ext
save_animation(fig, frame_index, nt, outfile)
end
end

# Utility functions
###################
#
76 changes: 76 additions & 0 deletions moment_kinetics/src/load_data.jl
Original file line number Diff line number Diff line change
@@ -4145,6 +4145,82 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t
if variable_name == "temperature"
vth = get_variable(run_info, "thermal_speed"; kwargs...)
variable = vth.^2
elseif variable_name == "dT_dz"
T = get_variable(run_info, "temperature"; kwargs...)
variable = similar(T)
if :iz ∈ keys(kwargs) && kwargs[:iz] !== nothing
error("Cannot take z-derivative when iz!==nothing")
end
if :ir ∈ keys(kwargs) && isa(kwargs[:ir], mk_int)
for it ∈ 1:size(variable, 3)
@views derivative!(variable[:,:,it], T[:,:,it], run_info.z, run_info.z_spectral)
end
else
for it ∈ 1:size(variable, 4), ir ∈ 1:run_info.r.n
@views derivative!(variable[:,:,ir,it], T[:,:,ir,it], run_info.z, run_info.z_spectral)
end
end
elseif variable_name == "dn_dz"
n = get_variable(run_info, "density"; kwargs...)
variable = similar(n)
if :iz ∈ keys(kwargs) && kwargs[:iz] !== nothing
error("Cannot take z-derivative when iz!==nothing")
end
if :ir ∈ keys(kwargs) && isa(kwargs[:ir], mk_int)
for it ∈ 1:size(variable, 3)
@views derivative!(variable[:,:,it], n[:,:,it], run_info.z, run_info.z_spectral)
end
else
for it ∈ 1:size(variable, 4), ir ∈ 1:run_info.r.n
@views derivative!(variable[:,:,ir,it], n[:,:,ir,it], run_info.z, run_info.z_spectral)
end
end
elseif variable_name == "dupar_dz"
upar = get_variable(run_info, "parallel_flow"; kwargs...)
variable = similar(upar)
if :iz ∈ keys(kwargs) && kwargs[:iz] !== nothing
error("Cannot take z-derivative when iz!==nothing")
end
if :ir ∈ keys(kwargs) && isa(kwargs[:ir], mk_int)
for it ∈ 1:size(variable, 3)
@views derivative!(variable[:,:,it], upar[:,:,it], run_info.z, run_info.z_spectral)
end
else
for it ∈ 1:size(variable, 4), ir ∈ 1:run_info.r.n
@views derivative!(variable[:,:,ir,it], upar[:,:,ir,it], run_info.z, run_info.z_spectral)
end
end
elseif variable_name == "mfp"
vth = get_variable(run_info, "thermal_speed"; kwargs...)
nu_ii = get_variable(run_info, "collision_frequency_ii"; kwargs...)
variable = vth ./ nu_ii
elseif variable_name == "L_T"
dT_dz = get_variable(run_info, "dT_dz"; kwargs...)
temp = get_variable(run_info, "temperature"; kwargs...)
# We define gradient lengthscale of T as LT^-1 = dln(T)/dz (ignore negative sign
# tokamak convention as we're only concerned with comparing magnitudes)
variable = abs.(temp .* dT_dz.^(-1))
# flat points in temperature have diverging LT, so ignore those with NaN
# using a hard coded 10.0 tolerance for now
variable[variable .> 10.0] .= NaN
elseif variable_name == "L_n"
dn_dz = get_variable(run_info, "dn_dz"; kwargs...)
n = get_variable(run_info, "density"; kwargs...)
# We define gradient lengthscale of n as Ln^-1 = dln(n)/dz (ignore negative sign
# tokamak convention as we're only concerned with comparing magnitudes)
variable = abs.(n .* dn_dz.^(-1))
# flat points in temperature have diverging Ln, so ignore those with NaN
# using a hard coded 10.0 tolerance for now
variable[variable .> 10.0] .= NaN
elseif variable_name == "L_upar"
dupar_dz = get_variable(run_info, "dupar_dz"; kwargs...)
upar = get_variable(run_info, "parallel_flow"; kwargs...)
# We define gradient lengthscale of upar as Lupar^-1 = dln(upar)/dz (ignore negative sign
# tokamak convention as we're only concerned with comparing magnitudes)
variable = abs.(upar .* dupar_dz.^(-1))
# flat points in temperature have diverging Lupar, so ignore those with NaN
# using a hard coded 10.0 tolerance for now
variable[variable .> 10.0] .= NaN
elseif variable_name == "collision_frequency_ii"
n = get_variable(run_info, "density"; kwargs...)
vth = get_variable(run_info, "thermal_speed"; kwargs...)
49 changes: 46 additions & 3 deletions moment_kinetics/src/velocity_moments.jl
Original file line number Diff line number Diff line change
@@ -768,7 +768,7 @@ function update_ion_qpar_species!(qpar, density, upar, vth, dT_dz, ff, vpa, vper
calculate_ion_qpar_from_pdf!(qpar, density, upar, vth, ff, vpa, vperp, z, r, evolve_density,
evolve_upar, evolve_ppar)
elseif ion_physics == braginskii_ions
calculate_ion_qpar_from_braginskii!(qpar, density, vth, dT_dz, z, r, collisions, evolve_density,
calculate_ion_qpar_from_braginskii!(qpar, density, upar, vth, dT_dz, z, r, collisions, evolve_density,
evolve_upar, evolve_ppar)
else
throw(ArgumentError("ion model $ion_physics not implemented for qpar calculation"))
@@ -820,7 +820,7 @@ end
"""
calculate parallel heat flux if ion composition flag is Braginskii fluid ions
"""
function calculate_ion_qpar_from_braginskii!(qpar, density, vth, dT_dz, z, r, collisions, evolve_density, evolve_upar, evolve_ppar)
function calculate_ion_qpar_from_braginskii!(qpar, density, upar, vth, dT_dz, z, r, collisions, evolve_density, evolve_upar, evolve_ppar)
# Note that this is a braginskii heat flux for ions using the krook operator. The full Fokker-Planck operator
# Braginskii heat flux is different! This also assumes one ion species, and so no friction between ions.
@boundscheck r.n == size(qpar, 2) || throw(BoundsError(qpar))
@@ -834,7 +834,50 @@ function calculate_ion_qpar_from_braginskii!(qpar, density, vth, dT_dz, z, r, co
qpar[iz,ir] = -(1/2) * 5/4 * density[iz,ir] * vth[iz,ir]^2 /nu_ii * dT_dz[iz,ir,1]
end
else
throw(ArgumentError("Braginskii heat flux simulation requires evolve_density, evolve_upar and evolve_ppar to be true, since it is a purely fluid simulation"))
throw(ArgumentError("Braginskii heat flux simulation requires evolve_density,
evolve_upar and evolve_ppar to be true, since it is a purely fluid simulation"))
end

# add boundary condition to the heat flux, since now there is no distribution function
# (in this case shape function) whose cutoff boundary condition can hold the parallel heat
# flux in check. See Stangeby textbook, equations (2.92) and (2.93), and the paragraph between.

if z.bc == "periodic"
# There's no wall boundary condition here, do nothing (qpar can be what it wants)
return nothing
end

begin_r_region()

if z.irank == 0 && (z.irank == z.nrank - 1)
z_indices = (1, z.n)
elseif z.irank == 0
z_indices = (1,)
elseif z.irank == z.nrank - 1
z_indices = (z.n,)
else
return nothing
end

@loop_r ir begin
for iz ∈ z_indices
this_ppar = vth[iz,ir]^2 * density[iz,ir]/2.0
this_upar = upar[iz,ir]
this_dens = density[iz,ir]
particle_flux = this_dens * this_upar
T_i = vth[iz,ir]^2

# Stangeby paragraph after (2.92)
gamma_i = 2.0

# Stangeby (2.92)
total_heat_flux = gamma_i * T_i * particle_flux

# E.g. Helander&Sigmar (2.14) ??????? what is it for ions?
conductive_heat_flux = total_heat_flux - 2.5 * this_ppar * this_upar

qpar[iz,ir] = conductive_heat_flux
end
end
return nothing
end