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

Krook 'collisions' #127

Merged
merged 53 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
bffaea3
Move generic settings definition functions to input_structs.jl
johnomotani Aug 26, 2023
6293496
Move define_coordinate() calls into mk_input()
johnomotani Aug 26, 2023
fdac38e
Add module with physical constants, mk_input return reference_parameters
johnomotani Aug 27, 2023
df1bd5b
Function to print some dimensional parameters of a simulation
johnomotani Sep 30, 2022
33584ea
Script to compare collision frequencies to numerical dissipation
johnomotani Mar 20, 2023
8d8bcd4
Krook collision operator for ion-ion Coulomb collisions
johnomotani Oct 4, 2022
94e1408
Implement "split 2" and "split 3" test for NonlinearSoundWaveTests
johnomotani Sep 21, 2023
fcdd763
Add regression test for Krook collision operator
johnomotani Sep 22, 2023
9b21e09
Handle 2V case in Krook collision operator
johnomotani Sep 22, 2023
cf8a956
Restrict check for 1V in Krook collisions to moment-kinetic cases
johnomotani Sep 25, 2023
49f41f8
Move handling of reference parameters into separate module
johnomotani Sep 25, 2023
7019804
Merge branch 'master' into Krook-collisions
johnomotani Sep 25, 2023
030fbe7
Ported capability to compare upar and ppar to expectations from MMS t…
mrhardman May 17, 2023
6a9664d
Clean up manufactured solutions input
johnomotani Sep 27, 2023
02ded9a
Put 'show_element_boundaries' in postproc input for manufactured_solns
johnomotani Sep 27, 2023
bf27259
Make MMS plots for ion parallel flow and parallel pressure
johnomotani Sep 27, 2023
a1a17ec
Skip MMS plots of Er for 1D cases
johnomotani Sep 27, 2023
b539670
Fix slicing of distribution functions in MMS plots
johnomotani Sep 27, 2023
f181300
Fix post processing script consistent with updated composition struct.
mrhardman Sep 28, 2023
d91c618
Addition of factor to compensate for the pressure normalisation conve…
mrhardman Sep 29, 2023
1932bf5
Porting of commit cd07a26. Refactoring of the update_derived_moments …
mrhardman May 12, 2023
fa27970
Cherry-pick of commit 8632cf7 to add perpendicular pressure to the bo…
mrhardman May 17, 2023
82de4c4
Attempt to cherry-pick the features from 6bd406e. Some bugs remain wh…
mrhardman May 18, 2023
ed979ad
Include factor of 2 for expected vth in test_velocity_integrals.jl
johnomotani Oct 24, 2023
5bd78ec
Increase Lvpa and Lvperp in test_velocity_integrals.jl
johnomotani Oct 24, 2023
4e7dccb
Correct file_io so that perpendicular pressure is correctly saved to …
mrhardman Oct 24, 2023
b7a7620
Fix file name for output plots
mrhardman Oct 24, 2023
88ad6d0
Attempt to port manufactured solutions test for Krook operator to new…
mrhardman Oct 25, 2023
ba4d733
Put rfac preceding the numerical dissipation term in r to prevent usa…
mrhardman Oct 25, 2023
e37a0a5
Clean up comment
mrhardman Oct 30, 2023
6823546
Modifications to port Krook operator manufactured solutions test to t…
mrhardman Oct 30, 2023
09cb8fb
Allow 2V Krook operator providing that split moments are not used.
mrhardman Oct 30, 2023
58e7c8e
Correct update_moments! to use the update_vth! function so that the t…
mrhardman Oct 30, 2023
6132fc6
Example input files for MMS test with Krook operator (spatially const…
mrhardman Oct 30, 2023
1885c79
Change input options for Krook so that default is to not use the Kroo…
mrhardman Oct 30, 2023
5647180
Fix figure saving for 1D plot in makie_post_processing
johnomotani Oct 30, 2023
7ed8a1c
Pass nvperp to manufactured solutions funcs in makie_post_processing
johnomotani Oct 30, 2023
a6771e5
Convert test_velocity_integrals.jl to a CI test
johnomotani Oct 30, 2023
5130cf8
Merge branch 'master' into Krook-collisions-MMS-port
johnomotani Oct 30, 2023
a8e314d
Merge branch 'Krook-collisions' into Krook-collisions-MMS-port
johnomotani Oct 30, 2023
6884d86
Deactivate Krook collisions by default
johnomotani Oct 30, 2023
92a4e29
Pass 'element_spacing_option' to coords in velocity_integral_tests.jl
johnomotani Oct 30, 2023
afe3709
Better values for MPI variables when ignore_MPI=true in mk_input()
johnomotani Sep 29, 2023
5d5ddaf
Tidy up comments
johnomotani Oct 30, 2023
8a5e298
Make clearer that Ti_over_Tref is not normalised temperature
johnomotani Oct 30, 2023
4c9e810
Krook MMS test inputs use spatially-varying collision frequency
johnomotani Oct 30, 2023
49e33d1
Merge pull request #141 from mabarnes/Krook-collisions-MMS-port
johnomotani Oct 30, 2023
1654f7c
Make clearer that T_over_Tref is not normalised temperature
johnomotani Oct 30, 2023
45fd04f
Define Krook collision frequency in terms of cref rather than Tref
johnomotani Oct 31, 2023
37856fa
Move calculation of Krook collision frequency to a function
johnomotani Oct 31, 2023
eff2647
Make plots of collision frequency if Krook collisions are used
johnomotani Oct 31, 2023
326efbb
Fix coordinate creation in makie_post_processing
johnomotani Oct 31, 2023
c7735e1
Handle derived variables in get_variable() in makie_post_processing
johnomotani Oct 31, 2023
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
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
julia = "1.7.0"
6 changes: 6 additions & 0 deletions docs/src/utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
`utils`
===============

```@autodocs
Modules = [moment_kinetics.utils]
```
33 changes: 33 additions & 0 deletions src/constants.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
Some physical constants
"""
module constants

export epsilon0, mu0
export electron_mass
export proton_charge, proton_mass
export deuteron_mass
export amu

# https://physics.nist.gov/cgi-bin/cuu/Value?ep0
const epsilon0 = 8.8541878128e-12 # F m^-1

# https://physics.nist.gov/cgi-bin/cuu/Value?mu0
const mu0 = 1.25663706212e-6 # N A^-2

# https://physics.nist.gov/cgi-bin/cuu/Value?me
const electron_mass = 9.109383701e-31 # kg

# https://physics.nist.gov/cgi-bin/cuu/Value?e
const proton_charge = 1.602176634e-19 # C

# https://physics.nist.gov/cgi-bin/cuu/Value?mp
const proton_mass = 1.67262192369e-27 # kg

# https://physics.nist.gov/cgi-bin/cuu/Value?md
const deuteron_mass = 3.3435837724e-27

# https://physics.nist.gov/cgi-bin/cuu/Value?ukg
const amu = 1.66053906660e-27

end
113 changes: 113 additions & 0 deletions src/input_structs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export collisions_input
export io_input
export pp_input
export geometry_input
export set_defaults_and_check_top_level!, set_defaults_and_check_section!,
Dict_to_NamedTuple

using ..type_definitions: mk_float, mk_int

Expand Down Expand Up @@ -59,6 +61,7 @@ mutable struct advance_info
ionization_collisions::Bool
ionization_collisions_1V::Bool
ionization_source::Bool
krook_collisions::Bool
numerical_dissipation::Bool
source_terms::Bool
continuity::Bool
Expand Down Expand Up @@ -303,6 +306,8 @@ mutable struct collisions_input
ionization::mk_float
# if constant_ionization_rate = true, use an ionization term that is constant in z
constant_ionization_rate::Bool
# Coulomb collision rate at the reference density and temperature
krook_collision_frequency_prefactor::mk_float
end

"""
Expand Down Expand Up @@ -502,4 +507,112 @@ struct pp_input
diagnostics_chodura_r::Bool
end

import Base: get
"""
Utility method for converting a string to an Enum when getting from a Dict, based on the
type of the default value
"""
function get(d::Dict, key, default::Enum)
valstring = get(d, key, nothing)
if valstring == nothing
return default
# instances(typeof(default)) gets the possible values of the Enum. Then convert to
# Symbol, then to String.
elseif valstring ∈ (split(s, ".")[end] for s ∈ String.(Symbol.(instances(typeof(default)))))
return eval(Symbol(valstring))
else
error("Expected a $(typeof(default)), but '$valstring' is not in "
* "$(instances(typeof(default)))")
end
end

"""
Set the defaults for options in the top level of the input, and check that there are not
any unexpected options (i.e. options that have no default).

Modifies the options[section_name]::Dict by adding defaults for any values that are not
already present.

Ignores any sections, as these will be checked separately.
"""
function set_defaults_and_check_top_level!(options::AbstractDict; kwargs...)
DictType = typeof(options)

# Check for any unexpected values in the options - all options that are set should be
# present in the kwargs of this function call
options_keys_symbols = keys(kwargs)
options_keys = (String(k) for k ∈ options_keys_symbols)
for (key, value) in options
# Ignore any ssections when checking
if !(isa(value, AbstractDict) || key ∈ options_keys)
error("Unexpected option '$key=$value' in top-level options")
end
end

# Set default values if a key was not set explicitly
explicit_keys = keys(options)
for (key_sym, value) ∈ kwargs
key = String(key_sym)
if !(key ∈ explicit_keys)
options[key] = value
end
end

return options
end

"""
Set the defaults for options in a section, and check that there are not any unexpected
options (i.e. options that have no default).

Modifies the options[section_name]::Dict by adding defaults for any values that are not
already present.
"""
function set_defaults_and_check_section!(options::AbstractDict, section_name;
kwargs...)
DictType = typeof(options)

if !(section_name ∈ keys(options))
# If section is not present, create it
options[section_name] = DictType()
end

if !isa(options[section_name], AbstractDict)
error("Expected '$section_name' to be a section in the input file, but it has a "
* "value '$(options[section_name])'")
end

section = options[section_name]

# Check for any unexpected values in the section - all options that are set should be
# present in the kwargs of this function call
section_keys_symbols = keys(kwargs)
section_keys = (String(k) for k ∈ section_keys_symbols)
for (key, value) in section
if !(key ∈ section_keys)
error("Unexpected option '$key=$value' in section '$section_name'")
end
end

# Set default values if a key was not set explicitly
explicit_keys = keys(section)
for (key_sym, value) ∈ kwargs
key = String(key_sym)
if !(key ∈ explicit_keys)
section[key] = value
end
end

return section
end

"""
Convert a Dict whose keys are String or Symbol to a NamedTuple

Useful as NamedTuple is immutable, so option values cannot be accidentally changed.
"""
function Dict_to_NamedTuple(d)
return NamedTuple(Symbol(k)=>v for (k,v) ∈ d)
end

end
134 changes: 134 additions & 0 deletions src/krook_collisions.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"""
"""
module krook_collisions

using ..constants: epsilon0, proton_charge
using ..looping

"""
Calculate normalized collision frequency at reference parameters for Coulomb collisions.

Currently valid only for hydrogenic ions (Z=1)
"""
function setup_krook_collisions(reference_parameters)
Nref = reference_parameters.Nref
Tref = reference_parameters.Tref
mref = reference_parameters.mref
timeref = reference_parameters.timeref

Nref_per_cm3 = Nref * 1.0e-6

# Coulomb logarithm at reference parameters for same-species ion-ion collisions, using
# NRL formulary. Formula given for n in units of cm^-3 and T in units of eV.
logLambda_ii = 23.0 - log(sqrt(2.0*Nref_per_cm3) / Tref^1.5)

# Collision frequency, using \hat{\nu} from Appendix, p. 277 of Helander "Collisional
# Transport in Magnetized Plasmas" (2002).
T0_Joules = Tref * proton_charge # Tref in Joules
mi_kg = mref # mi in kg
vth_i0 = sqrt(2.0 * T0_Joules / mi_kg) # vth_i at reference parameters in m.s^-1
nu_ii0_per_s = Nref * proton_charge^4 * logLambda_ii /
(4.0 * π * epsilon0^2 * mi_kg^2 * vth_i0^3) # s^-1
nu_ii0 = nu_ii0_per_s * timeref

return nu_ii0
end

"""
Add collision operator

Currently Krook collisions
"""
function krook_collisions!(pdf_out, fvec_in, moments, composition, collisions, vperp, vpa, dt)
begin_s_r_z_region()

if vperp.n > 1
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
error("Krook collisions not implemented for 2V case yet")
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
end

# Note: do not need 1/sqrt(pi) for the 'Maxwellian' term because the pdf is already
# normalized by sqrt(pi) (see velocity_moments.integrate_over_vspace).

if moments.evolve_ppar && moments.evolve_upar
# Compared to evolve_upar version, grid is already normalized by vth, and multiply
# through by vth, remembering pdf is already multiplied by vth
@loop_s_r_z is ir iz begin
n = fvec_in.density[iz,ir,is]
T = (moments.charged.vth[iz,ir,is])^2
nu_ii = collisions.krook_collision_frequency_prefactor * n * T^(-1.5)
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
@loop_vperp_vpa ivperp ivpa begin
pdf_out[ivpa,ivperp,iz,ir,is] -= dt * nu_ii *
(fvec_in.pdf[ivpa,ivperp,iz,ir,is]
- exp(-vpa.grid[ivpa]^2 - vperp.grid[ivperp]^2))
end
end
elseif moments.evolve_ppar
# Compared to full-f collision operater, multiply through by vth, remembering pdf
# is already multiplied by vth, and grid is already normalized by vth
@loop_s_r_z is ir iz begin
n = fvec_in.density[iz,ir,is]
vth = moments.charged.vth[iz,ir,is]
T = vth^2
nu_ii = collisions.krook_collision_frequency_prefactor * n * T^(-1.5)
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
@loop_vperp_vpa ivperp ivpa begin
pdf_out[ivpa,ivperp,iz,ir,is] -= dt * nu_ii *
(fvec_in.pdf[ivpa,ivperp,iz,ir,is]
- exp(-((vpa.grid[ivpa] - fvec_in.upar[iz,ir,is])/vth)^2
- (vperp.grid[ivperp]/vth)^2))
end
end
elseif moments.evolve_upar
# Compared to evolve_density version, grid is already shifted by upar
@loop_s_r_z is ir iz begin
n = fvec_in.density[iz,ir,is]
vth = moments.charged.vth[iz,ir,is]
T = vth^2
nu_ii = collisions.krook_collision_frequency_prefactor * n * T^(-1.5)
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
@loop_vperp_vpa ivperp ivpa begin
pdf_out[ivpa,ivperp,iz,ir,is] -= dt * nu_ii *
(fvec_in.pdf[ivpa,ivperp,iz,ir,is]
- 1.0 / vth * exp(-(vpa.grid[ivpa] / vth)^2
- (vperp.grid[ivperp] / vth)^2))
end
end
elseif moments.evolve_density
# Compared to full-f collision operater, divide through by density, remembering
# that pdf is already normalized by density
@loop_s_r_z is ir iz begin
n = fvec_in.density[iz,ir,is]
vth = moments.charged.vth[iz,ir,is]
T = vth^2
nu_ii = collisions.krook_collision_frequency_prefactor * n * T^(-1.5)
johnomotani marked this conversation as resolved.
Show resolved Hide resolved
@loop_vperp_vpa ivperp ivpa begin
pdf_out[ivpa,ivperp,iz,ir,is] -= dt * nu_ii *
(fvec_in.pdf[ivpa,ivperp,iz,ir,is]
- 1.0 / vth
* exp(-((vpa.grid[ivpa] - fvec_in.upar[iz,ir,is]) / vth)^2
- (vperp.grid[ivperp]/vth)^2))
end
end
else
@loop_s_r_z is ir iz begin
n = fvec_in.density[iz,ir,is]
vth = moments.charged.vth[iz,ir,is]
T = vth^2
if vperp.n == 1
vth_prefactor = 1.0 / vth
else
vth_prefactor = 1.0 / vth^3
end
nu_ii = collisions.krook_collision_frequency_prefactor * n * T^(-1.5)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This choice of prefactor is probably motivated by the physical form of Fokker-Planck collision frequency, but it is not obvious to me that we would actually want this feature. Isn't it easier to understand the ad-hoc feature that we add if it doesn't have a nonlinear collision frequency?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to have both options (e.g. Gkeyll does that https://gkeyll.readthedocs.io/en/latest/gkyl/App/Collisions/collisionModels.html). If you want to add an option for constant collision frequency I'm happy for that to be there. I wanted to have a density/temperature dependent collision frequency because in a setup where physically the collisionality changes significantly (e.g. due to a large temperature drop between midplane and target) I don't want to have unphysically strong collisions upstream, but want the collisions near the target to be strong enough to Maxwellian-ise the plasma.

johnomotani marked this conversation as resolved.
Show resolved Hide resolved
@loop_vperp_vpa ivperp ivpa begin
pdf_out[ivpa,ivperp,iz,ir,is] -= dt * nu_ii *
(fvec_in.pdf[ivpa,ivperp,iz,ir,is]
- n * vth_prefactor
* exp(-((vpa.grid[ivpa] - fvec_in.upar[iz,ir,is])/vth)^2
- (vperp.grid[ivperp]/vth)^2))
end
end
end

return nothing
end

end # krook_collisions
13 changes: 6 additions & 7 deletions src/makie_post_processing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ using ..analysis: analyze_fields_data, check_Chodura_condition, get_r_perturbati
get_Fourier_modes_2D, get_Fourier_modes_1D, steady_state_residuals
using ..array_allocation: allocate_float
using ..coordinates: define_coordinate
using ..input_structs: grid_input, advection_input
using ..input_structs: grid_input, advection_input, set_defaults_and_check_top_level!,
set_defaults_and_check_section!, Dict_to_NamedTuple
using ..looping: all_dimensions, ion_dimensions, neutral_dimensions
using ..manufactured_solns: manufactured_solutions, manufactured_electric_fields
using ..moment_kinetics_input: mk_input, set_defaults_and_check_top_level!,
set_defaults_and_check_section!, Dict_to_NamedTuple
using ..moment_kinetics_input: mk_input
using ..load_data: open_readonly_output_file, get_group, load_block_data,
load_coordinate_data, load_distributed_charged_pdf_slice,
load_distributed_neutral_pdf_slice, load_input, load_mk_options,
Expand Down Expand Up @@ -778,10 +778,9 @@ function get_run_info(run_dir, restart_index=nothing; itime_min=1, itime_max=-1,

# obtain input options from moment_kinetics_input.jl
# and check input to catch errors
io_input, evolve_moments, t_input, z_input, r_input, vpa_input, vperp_input,
gyrophase_input, vz_input, vr_input, vzeta_input, composition, species,
collisions, geometry, drive_input, num_diss_params, manufactured_solns_input =
mk_input(input)
io_input, evolve_moments, t_input, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
composition, species, collisions, geometry, drive_input, num_diss_params,
manufactured_solns_input, reference_parameters = mk_input(input)

n_ion_species, n_neutral_species = load_species_data(file_final_restart)
evolve_density, evolve_upar, evolve_ppar = load_mk_options(file_final_restart)
Expand Down
Loading