diff --git a/.github/workflows/debug_checks.yml b/.github/workflows/debug_checks.yml index 55eef9e63..ef2883ab1 100644 --- a/.github/workflows/debug_checks.yml +++ b/.github/workflows/debug_checks.yml @@ -31,7 +31,8 @@ jobs: sed -i -e "s/_debug_level = get_options.*/_debug_level = 2/" moment_kinetics/src/debugging.jl touch Project.toml - julia --project -O3 --check-bounds=yes -e 'using Pkg; Pkg.add(["MPI", "MPIPreferences", "PackageCompiler", "Symbolics"]); using MPIPreferences; MPIPreferences.use_system_binary()' + julia --project -O3 --check-bounds=yes -e 'using Pkg; Pkg.add(["MPI", "MPIPreferences", "PackageCompiler", "Symbolics"]); using MPIPreferences; MPIPreferences.use_jll_binary("OpenMPI_jll")' + julia --project -O3 --check-bounds=no -e 'using MPI; MPI.install_mpiexecjl(; destdir=".")' julia --project -O3 --check-bounds=yes -e 'using Pkg; Pkg.develop(path="moment_kinetics/"); Pkg.precompile()' julia --project -O3 --check-bounds=yes precompile.jl --debug 2 @@ -42,4 +43,4 @@ jobs: # terrible performance when oversubscribing. ## Don't use --compiled-modules=no for now, as it currently breaks Symbolics.jl #mpiexec -np 4 --mca rmaps_base_oversubscribe 1 julia --project --check-bounds=yes --compiled-modules=no moment_kinetics/debug_test/sound_wave_tests.jl --debug 2 - mpiexec -np 4 --mca rmaps_base_oversubscribe 1 julia --project -Jmoment_kinetics.so -O3 --check-bounds=yes moment_kinetics/debug_test/runtests.jl --debug 2 + ./mpiexecjl -np 4 --mca rmaps_base_oversubscribe 1 julia --project -Jmoment_kinetics.so -O3 --check-bounds=yes moment_kinetics/debug_test/runtests.jl --debug 2 diff --git a/.github/workflows/parallel_test.yml b/.github/workflows/parallel_test.yml index b811cff94..e0b1aea43 100644 --- a/.github/workflows/parallel_test.yml +++ b/.github/workflows/parallel_test.yml @@ -24,17 +24,18 @@ jobs: - uses: julia-actions/cache@v1 - run: | touch Project.toml - julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["MPI", "MPIPreferences"]); using MPIPreferences; MPIPreferences.use_system_binary()' - julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["NCDatasets", "Random", "SpecialFunctions", "Test"]); Pkg.develop(path="moment_kinetics/")' + julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["MPI", "MPIPreferences"]); using MPIPreferences; MPIPreferences.use_jll_binary("OpenMPI_jll")' + julia --project -O3 --check-bounds=no -e 'using MPI; MPI.install_mpiexecjl(; destdir=".")' + julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["Random", "SpecialFunctions", "Test"]); Pkg.develop(path="moment_kinetics/")' julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.precompile()' # Need to use openmpi so that the following arguments work: # * `--mca rmaps_base_oversubscribe 1` allows oversubscription (more processes # than physical cores). # * `--mca mpi_yield_when_idle 1` changes a setting to prevent excessively # terrible performance when oversubscribing. - mpiexec -np 3 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 --force-optional-dependencies - mpiexec -np 4 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 --force-optional-dependencies - mpiexec -np 2 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 --long --force-optional-dependencies + ./mpiexecjl -np 3 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 + ./mpiexecjl -np 4 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 + ./mpiexecjl -np 2 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 --long # Note: MPI.jl's default implementation is mpich, which has a similar option # `--with-device=ch3:sock`, but that needs to be set when compiling mpich. shell: bash @@ -56,15 +57,16 @@ jobs: - run: | export MPILIBPATH=$(find /opt/homebrew/Cellar/open-mpi/ -name libmpi.dylib) touch Project.toml - julia --project -O3 --check-bounds=no -e "import Pkg; Pkg.add([\"MPI\", \"MPIPreferences\"]); using MPIPreferences; MPIPreferences.use_system_binary(library_names=\"$MPILIBPATH\")" - julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["NCDatasets", "Random", "SpecialFunctions", "Test"]); Pkg.develop(path="moment_kinetics/")' + julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["MPI", "MPIPreferences"]); using MPIPreferences; MPIPreferences.use_jll_binary("OpenMPI_jll")' + julia --project -O3 --check-bounds=no -e 'using MPI; MPI.install_mpiexecjl(; destdir=".")' + julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.add(["Random", "SpecialFunctions", "Test"]); Pkg.develop(path="moment_kinetics/")' julia --project -O3 --check-bounds=no -e 'import Pkg; Pkg.precompile()' # Need to use openmpi so that the following arguments work: # * `--mca rmaps_base_oversubscribe 1` allows oversubscription (more processes # than physical cores). # * `--mca mpi_yield_when_idle 1` changes a setting to prevent excessively # terrible performance when oversubscribing. - mpiexec -np 4 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 --force-optional-dependencies + ./mpiexecjl -np 4 --mca rmaps_base_oversubscribe 1 julia --project -O3 --check-bounds=no moment_kinetics/test/runtests.jl --debug 1 # Note: MPI.jl's default implementation is mpich, which has a similar option # `--with-device=ch3:sock`, but that needs to be set when compiling mpich. shell: bash diff --git a/.github/workflows/test_scripts.yml b/.github/workflows/test_scripts.yml new file mode 100644 index 000000000..858159d1a --- /dev/null +++ b/.github/workflows/test_scripts.yml @@ -0,0 +1,25 @@ +# Based on example from https://github.com/julia-actions/julia-runtest +name: Check test_scripts + +on: [push, pull_request, workflow_dispatch] + +jobs: + examples: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest] + fail-fast: false + timeout-minutes: 35 + + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@latest + with: + version: '1.10' + - uses: julia-actions/cache@v1 + - name: Test test_scripts + run: | + touch Project.toml + julia -O3 --project -e 'import Pkg; Pkg.develop(path="moment_kinetics/"); Pkg.add(["FastGaussQuadrature", "LaTeXStrings", "LegendrePolynomials", "Measures", "MPI", "Plots", "SpecialFunctions"]); Pkg.precompile()' + julia -O3 --project -e 'include("test_scripts/2D_FEM_assembly_test.jl"); run_assembly_test(); include("test_scripts/chebyshev_radau_test.jl"); chebyshevradau_test(); include("test_scripts/fkpl_direct_integration_test.jl"); test_rosenbluth_potentials_direct_integration(); include("test_scripts/GaussLobattoLegendre_test.jl"); gausslegendre_test(); include("test_scripts/gyroaverage_test.jl"); gyroaverage_test()' diff --git a/docs/make.jl b/docs/make.jl index 18aa253e6..c5c25b0d7 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -9,10 +9,19 @@ Pkg.instantiate() using Documenter using moment_kinetics, makie_post_processing, plots_post_processing +if get(ENV, "CI", nothing) == "true" + # On the CI, run in strict mode to turn warnings into errors, so that we don't deploy + # documentation with formatting bugs. + strict = true +else + strict = false +end + makedocs( sitename = "moment_kinetics", format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"), - modules = [moment_kinetics, makie_post_processing, plots_post_processing] + modules = [moment_kinetics, makie_post_processing, plots_post_processing], + strict = strict, ) if get(ENV, "CI", nothing) == "true" diff --git a/docs/src/developing.md b/docs/src/developing.md index 3ec2536de..b448ff39a 100644 --- a/docs/src/developing.md +++ b/docs/src/developing.md @@ -28,6 +28,44 @@ julia> run_moment_kinetics("input.toml") It might be convenient to add `using Revise` to your `startup.jl` file (`~/julia/config/startup.jl`) so it's always loaded. +## Input options and defaults + +The input is read from a `.toml` file. It is also written to the output HDF5 +(or NetCDF) file, after all defaults are applied, both as a TOML-formatted +String and as a tree of HDF5 variables. + +!!! warning + Neither TOML nor HDF5 have a 'null' type, so there is no convenient way to + store Julia's `nothing` when writing to TOML or HDF5. Therefore `nothing` + should not be used as a default for any input option. If the code should + use `nothing` as a default for some setting, that is fine, but must be done + after the input is read, and not stored in the `input_dict`. + + +## Array types + +Most arrays in `moment_kinetics` are declared using a custom array type +[`moment_kinetics.communication.MPISharedArray`](@ref). Most of the time this +type is just an alias for `Array`, and so it needs the same template parameters +(see [Julia's Array +documentation](https://docs.julialang.org/en/v1/manual/arrays/)) - the data +type and the number of dimensions, e.g. `MPISharedArray{mk_float,3}`. Although +these arrays use shared memory, Julia does not know about this. We use +`MPI.Win_allocate_shared()` to allocate the shared memory, then wrap it in an +`Array` in [`moment_kinetics.communication.allocate_shared`](@ref). + +The reason for using the alias, is that when the shared-memory debugging mode +is activated, we instead create arrays using a type `DebugMPISharedArray`, +which allows us to track some debugging information along with the array, see +[Shared memory debugging](@ref), and make `MPISharedArray` an alias for +`DebugMPISharedArray` instead. The reason for the alias is that if we declared +our structs with just `Array` type, then when debugging is activated we would +not be able to store `DebugMPISharedArray` instances in those structs, and if +we declared the structs with `AbstractArray`, they would not be concretely +typed, which could impact performance by creating code that is not 'type +stable' (i.e. all concrete types are known at compile time). + + ## Parallelization The code is parallelized at the moment using MPI and shared-memory arrays. Arrays representing the pdf, moments, etc. are shared between all processes. Using shared memory means, for example, we can take derivatives along one dimension while parallelising the other for any dimension without having to communicate to re-distribute the arrays. Using shared memory instead of (in future as well as) distributed memory parallelism has the advantage that it is easier to split up the points within each element between processors, giving a finer-grained parallelism which should let the code use larger numbers of processors efficiently. diff --git a/docs/src/zz_electron_fluid_equations.md b/docs/src/zz_electron_fluid_equations.md new file mode 100644 index 000000000..82cb31e65 --- /dev/null +++ b/docs/src/zz_electron_fluid_equations.md @@ -0,0 +1,6 @@ +`electron_fluid_equations` +========================== + +```@autodocs +Modules = [moment_kinetics.electron_fluid_equations] +``` diff --git a/docs/src/zz_electron_kinetic_equation.md b/docs/src/zz_electron_kinetic_equation.md new file mode 100644 index 000000000..5c37a3ef4 --- /dev/null +++ b/docs/src/zz_electron_kinetic_equation.md @@ -0,0 +1,6 @@ +`electron_kinetic_equation` +=========================== + +```@autodocs +Modules = [moment_kinetics.electron_kinetic_equation] +``` diff --git a/docs/src/zz_electron_vpa_advection.md b/docs/src/zz_electron_vpa_advection.md new file mode 100644 index 000000000..2243b0a9e --- /dev/null +++ b/docs/src/zz_electron_vpa_advection.md @@ -0,0 +1,6 @@ +`electron_vpa_advection` +======================== + +```@autodocs +Modules = [moment_kinetics.electron_vpa_advection] +``` diff --git a/docs/src/zz_electron_z_advection.md b/docs/src/zz_electron_z_advection.md new file mode 100644 index 000000000..cba681571 --- /dev/null +++ b/docs/src/zz_electron_z_advection.md @@ -0,0 +1,6 @@ +`electron_z_advection` +====================== + +```@autodocs +Modules = [moment_kinetics.electron_z_advection] +``` diff --git a/docs/src/zz_maxwell_diffusion.md b/docs/src/zz_maxwell_diffusion.md new file mode 100644 index 000000000..d3fd77d27 --- /dev/null +++ b/docs/src/zz_maxwell_diffusion.md @@ -0,0 +1,6 @@ +`maxwell_diffusion` +=================== + +```@autodocs +Modules = [moment_kinetics.maxwell_diffusion] +``` diff --git a/docs/src/zz_nonlinear_solvers.md b/docs/src/zz_nonlinear_solvers.md new file mode 100644 index 000000000..be7d75a22 --- /dev/null +++ b/docs/src/zz_nonlinear_solvers.md @@ -0,0 +1,6 @@ +`nonlinear_solvers` +=================== + +```@autodocs +Modules = [moment_kinetics.nonlinear_solvers] +``` diff --git a/docs/src/zz_species_input.md b/docs/src/zz_species_input.md new file mode 100644 index 000000000..afd5ab66b --- /dev/null +++ b/docs/src/zz_species_input.md @@ -0,0 +1,6 @@ +`species_input` +=============== + +```@autodocs +Modules = [moment_kinetics.species_input] +``` diff --git a/examples/fokker-planck-1D2V/fokker-planck-1D2V-even_nz-shorttest-nstep200.toml b/examples/fokker-planck-1D2V/fokker-planck-1D2V-even_nz-shorttest-nstep200.toml index 9f56e39db..a45f8dff1 100644 --- a/examples/fokker-planck-1D2V/fokker-planck-1D2V-even_nz-shorttest-nstep200.toml +++ b/examples/fokker-planck-1D2V/fokker-planck-1D2V-even_nz-shorttest-nstep200.toml @@ -1,35 +1,53 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false -charge_exchange_frequency = 0.0 -ionization_frequency = 1.0 -constant_ionization_rate = true +[ion_source_1] +z_profile = "constant" +source_strength = 1.0 +source_T = 0.25 -z_ngrid = 5 -z_nelement = 16 -#z_nelement_local = 2 -z_bc = "wall" -z_element_spacing_option = "sqrt" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 15 -vpa_L = 6.0 -vpa_bc = "zero" -#vpa_discretization = "chebyshev_pseudospectral" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 4 -vperp_L = 3.0 -#vperp_bc = "periodic" -#vperp_discretization = "finite_difference" -#vperp_discretization = "chebyshev_pseudospectral" -vperp_discretization = "gausslegendre_pseudospectral" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 5 +nelement = 16 +#nelement_local = 2 +bc = "wall" +element_spacing_option = "sqrt" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 15 +L = 6.0 +bc = "zero" +#discretization = "chebyshev_pseudospectral" +discretization = "gausslegendre_pseudospectral" + +[vz] +ngrid = 6 +nelement = 15 +L = 6.0 +bc = "zero" +#discretization = "chebyshev_pseudospectral" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 4 +L = 3.0 +#bc = "periodic" +#discretization = "finite_difference" +#discretization = "chebyshev_pseudospectral" +discretization = "gausslegendre_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/fokker-planck/fokker-planck-relaxation-report-resolutions.toml b/examples/fokker-planck/fokker-planck-relaxation-report-resolutions.toml index b79376025..879ee5d9e 100644 --- a/examples/fokker-planck/fokker-planck-relaxation-report-resolutions.toml +++ b/examples/fokker-planck/fokker-planck-relaxation-report-resolutions.toml @@ -1,32 +1,41 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 8 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 4 -vperp_L = 3.0 -vperp_discretization = "gausslegendre_pseudospectral" -vperp_bc = "zero" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 8 +L = 6.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 4 +L = 3.0 +discretization = "gausslegendre_pseudospectral" +bc = "zero" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids diff --git a/examples/fokker-planck/fokker-planck-relaxation-slowing-down-alphas.toml b/examples/fokker-planck/fokker-planck-relaxation-slowing-down-alphas.toml index f6bccbe51..37b5e1971 100644 --- a/examples/fokker-planck/fokker-planck-relaxation-slowing-down-alphas.toml +++ b/examples/fokker-planck/fokker-planck-relaxation-slowing-down-alphas.toml @@ -1,33 +1,41 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions and collisions with fixed Maxwellian background of cold ions and electrons. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false - +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 32 -vpa_L = 3.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 16 -vperp_L = 1.5 -vperp_discretization = "gausslegendre_pseudospectral" -vperp_bc = "zero" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 32 +L = 3.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 16 +L = 1.5 +discretization = "gausslegendre_pseudospectral" +bc = "zero" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids @@ -46,7 +54,7 @@ sd_mi = 0.5 # mD/malpha sd_me = 0.000013616 # 0.25/1836.0 me/malpha sd_q = 1.0 -[ion_source] +[ion_source_1] active=false source_strength=0.0 source_T=0.005 diff --git a/examples/fokker-planck/fokker-planck-relaxation-slowing-down.toml b/examples/fokker-planck/fokker-planck-relaxation-slowing-down.toml index f637a06ef..1512eb3a3 100644 --- a/examples/fokker-planck/fokker-planck-relaxation-slowing-down.toml +++ b/examples/fokker-planck/fokker-planck-relaxation-slowing-down.toml @@ -1,30 +1,40 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 32 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 16 -vperp_L = 3.0 -vperp_discretization = "gausslegendre_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 32 +L = 6.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 16 +L = 3.0 +discretization = "gausslegendre_pseudospectral" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids diff --git a/examples/fokker-planck/fokker-planck-relaxation.toml b/examples/fokker-planck/fokker-planck-relaxation.toml index 9a512fbf8..94b65dbc4 100644 --- a/examples/fokker-planck/fokker-planck-relaxation.toml +++ b/examples/fokker-planck/fokker-planck-relaxation.toml @@ -1,31 +1,40 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false - -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 3 -vpa_nelement = 6 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 3 -vperp_nelement = 3 -vperp_L = 3.0 -vperp_discretization = "gausslegendre_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 3 +nelement = 6 +L = 6.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 3 +nelement = 3 +L = 3.0 +discretization = "gausslegendre_pseudospectral" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids diff --git a/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas-no-self-collisions.toml b/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas-no-self-collisions.toml index 1300c4ef9..bf837f2c9 100644 --- a/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas-no-self-collisions.toml +++ b/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas-no-self-collisions.toml @@ -1,32 +1,41 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions and collisions with fixed Maxwellian background of cold ions and electrons. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 32 -vpa_L = 3.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 16 -vperp_L = 1.5 -vperp_discretization = "gausslegendre_pseudospectral" -vperp_bc = "zero" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 32 +L = 3.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 16 +L = 1.5 +discretization = "gausslegendre_pseudospectral" +bc = "zero" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids @@ -72,7 +81,7 @@ sd_mi = 0.5 # mD/malpha sd_me = 0.000013616 # 0.25/1836.0 me/malpha sd_q = 1.0 -[ion_source] +[ion_source_1] active=true source_strength=1.0 source_T=0.005 diff --git a/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas.toml b/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas.toml index 13c56692e..abfd8918f 100644 --- a/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas.toml +++ b/examples/fokker-planck/fokker-planck-source-sink-slowing-down-alphas.toml @@ -1,32 +1,41 @@ # cheap input file for a 0D2V relaxation to a collisional Maxwellian distribution with self-ion collisions and collisions with fixed Maxwellian background of cold ions and electrons. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 32 -vpa_L = 3.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 16 -vperp_L = 1.5 -vperp_discretization = "gausslegendre_pseudospectral" -vperp_bc = "zero" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 32 +L = 3.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 16 +L = 1.5 +discretization = "gausslegendre_pseudospectral" +bc = "zero" # Fokker-Planck operator requires the "gausslegendre_pseudospectral # options for the vpa and vperp grids @@ -73,7 +82,7 @@ sd_mi = 0.5 # mD/malpha sd_me = 0.000013616 # 0.25/1836.0 me/malpha sd_q = 1.0 -[ion_source] +[ion_source_1] active=true source_strength=1.0 source_T=0.005 diff --git a/examples/geometry/1D-mirror.toml b/examples/geometry/1D-mirror.toml index 4b7a954b1..9d24da7d7 100644 --- a/examples/geometry/1D-mirror.toml +++ b/examples/geometry/1D-mirror.toml @@ -1,31 +1,44 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false -charge_exchange_frequency = 0.5 -ionization_frequency = 0.05 -constant_ionization_rate = true -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -z_nelement = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 16 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 8 -vperp_L = 3.0 -vperp_bc = "zero" -vperp_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" +[ion_source_1] +z_profile = "constant" +source_strength = 0.05 +source_T = 0.25 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +nelement = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 16 +L = 6.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 8 +L = 3.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -33,7 +46,8 @@ n_neutral_species = 0 electron_physics = "boltzmann_electron_response" T_e = 1.0 T_wall = 1.0 -[ion_species] + +[ion_species_1] initial_density = 1.0 initial_temperature = 1.0 diff --git a/examples/gk-ions/2D-periodic-gk.toml b/examples/gk-ions/2D-periodic-gk.toml index 19659aede..8e47f20b7 100644 --- a/examples/gk-ions/2D-periodic-gk.toml +++ b/examples/gk-ions/2D-periodic-gk.toml @@ -1,32 +1,45 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false -charge_exchange_frequency = 0.0 -ionization_frequency = 0.05 -constant_ionization_rate = true -r_ngrid = 5 -r_nelement = 2 -r_bc = "periodic" -z_ngrid = 5 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 2 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 1 -vperp_L = 3.0 -vperp_bc = "zero" -vperp_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" +[ion_source_1] +z_profile = "constant" +source_strength = 0.05 +source_T = 0.25 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 5 +nelement = 2 +bc = "periodic" + +[z] +ngrid = 5 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 2 +L = 6.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 1 +L = 3.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/kinetic-electrons/periodic_split3_boltzmann.toml b/examples/kinetic-electrons/periodic_split3_boltzmann.toml index 5ad042d4b..b0bbdc4ee 100644 --- a/examples/kinetic-electrons/periodic_split3_boltzmann.toml +++ b/examples/kinetic-electrons/periodic_split3_boltzmann.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/periodic_split3_braginskii-IMEX.toml b/examples/kinetic-electrons/periodic_split3_braginskii-IMEX.toml index f359c859d..c4fadf9d5 100644 --- a/examples/kinetic-electrons/periodic_split3_braginskii-IMEX.toml +++ b/examples/kinetic-electrons/periodic_split3_braginskii-IMEX.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/periodic_split3_braginskii.toml b/examples/kinetic-electrons/periodic_split3_braginskii.toml index 6f5c8d737..308c76ba9 100644 --- a/examples/kinetic-electrons/periodic_split3_braginskii.toml +++ b/examples/kinetic-electrons/periodic_split3_braginskii.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/periodic_split3_kinetic-IMEX.toml b/examples/kinetic-electrons/periodic_split3_kinetic-IMEX.toml index e5a02086f..a67591698 100644 --- a/examples/kinetic-electrons/periodic_split3_kinetic-IMEX.toml +++ b/examples/kinetic-electrons/periodic_split3_kinetic-IMEX.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/periodic_split3_kinetic.toml b/examples/kinetic-electrons/periodic_split3_kinetic.toml index d4a1140d0..b99a5afb0 100644 --- a/examples/kinetic-electrons/periodic_split3_kinetic.toml +++ b/examples/kinetic-electrons/periodic_split3_kinetic.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/periodic_split3_kinetic_high-collisionality.toml b/examples/kinetic-electrons/periodic_split3_kinetic_high-collisionality.toml index a0c44f500..8a7e9ea3a 100644 --- a/examples/kinetic-electrons/periodic_split3_kinetic_high-collisionality.toml +++ b/examples/kinetic-electrons/periodic_split3_kinetic_high-collisionality.toml @@ -1,29 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.0 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 16 -#z_nelement_local = 16 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 6 -vpa_nelement = 31 -vpa_L = 12.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 31 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 16 +#nelement_local = 16 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 31 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/wall+sheath-bc_boltzmann_loworder.toml b/examples/kinetic-electrons/wall+sheath-bc_boltzmann_loworder.toml index cb1b24116..a06f36b1e 100644 --- a/examples/kinetic-electrons/wall+sheath-bc_boltzmann_loworder.toml +++ b/examples/kinetic-electrons/wall+sheath-bc_boltzmann_loworder.toml @@ -1,37 +1,47 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 electron_charge_exchange_frequency = 0.0 -nu_ei = 0.0 ionization_frequency = 2.0 #electron_ionization_frequency = 2.0 #ionization_energy = 1.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -#z_nelement = 32 -z_nelement = 64 -#z_nelement = 128 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_spacing_option = "sqrt" -vpa_ngrid = 5 -#vpa_nelement = 40 -vpa_nelement = 80 -vpa_L = 12.0 #8.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -#vpa_discretization = "gausslegendre_pseudospectral" -vz_ngrid = 5 -vz_nelement = 80 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[electron_fluid_collisions] +nu_ei = 0.0 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +#nelement = 32 +nelement = 64 +#nelement = 128 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 5 +#nelement = 40 +nelement = 80 +L = 12.0 #8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +#discretization = "gausslegendre_pseudospectral" + +[vz] +ngrid = 5 +nelement = 80 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -75,7 +85,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -102,6 +112,8 @@ nstep = 1000000 dt = 1.0e-5 nwrite = 10000 nwrite_dfns = 10000 +steady_state_residual = true +converged_residual_value = 1.0e-3 [electron_numerical_dissipation] diff --git a/examples/kinetic-electrons/wall+sheath-bc_kinetic.toml b/examples/kinetic-electrons/wall+sheath-bc_kinetic.toml index 8136e86d0..84fb66008 100644 --- a/examples/kinetic-electrons/wall+sheath-bc_kinetic.toml +++ b/examples/kinetic-electrons/wall+sheath-bc_kinetic.toml @@ -1,36 +1,48 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 electron_charge_exchange_frequency = 0.0 -nu_ei = 0.0 ionization_frequency = 2.0 electron_ionization_frequency = 2.0 ionization_energy = 1.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -#z_nelement = 16 -z_nelement = 32 -#z_nelement = 64 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_spacing_option = "sqrt" -vpa_ngrid = 17 -#vpa_nelement = 10 -vpa_nelement = 20 -vpa_L = 12.0 #8.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -#vpa_discretization = "gausslegendre_pseudospectral" -vz_ngrid = 17 -#vz_nelement = 10 -vz_nelement = 20 -vz_L = 8.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[electron_fluid_collisions] +nu_ei = 0.0 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +#nelement = 16 +nelement = 32 +#nelement = 64 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 17 +#nelement = 10 +nelement = 20 +L = 12.0 #8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +#discretization = "gausslegendre_pseudospectral" + +[vz] +ngrid = 17 +#nelement = 10 +nelement = 20 +L = 8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -74,7 +86,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/wall+sheath-bc_kinetic_krook_loworder.toml b/examples/kinetic-electrons/wall+sheath-bc_kinetic_krook_loworder.toml index f932d0357..843b7696a 100644 --- a/examples/kinetic-electrons/wall+sheath-bc_kinetic_krook_loworder.toml +++ b/examples/kinetic-electrons/wall+sheath-bc_kinetic_krook_loworder.toml @@ -1,35 +1,47 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 electron_charge_exchange_frequency = 0.0 -nu_ei = 0.0 ionization_frequency = 2.0 electron_ionization_frequency = 2.0 ionization_energy = 1.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -#z_nelement = 32 -z_nelement = 64 -#z_nelement = 128 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_spacing_option = "sqrt" -vpa_ngrid = 5 -#vpa_nelement = 40 -vpa_nelement = 80 -vpa_L = 12.0 #8.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -#vpa_discretization = "gausslegendre_pseudospectral" -vz_ngrid = 17 -vz_nelement = 10 -vz_L = 8.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[electron_fluid_collisions] +nu_ei = 0.0 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +#nelement = 32 +nelement = 64 +#nelement = 128 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 5 +#nelement = 40 +nelement = 80 +L = 12.0 #8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +#discretization = "gausslegendre_pseudospectral" + +[vz] +ngrid = 5 +nelement = 80 +L = 8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -73,7 +85,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/kinetic-electrons/wall+sheath-bc_kinetic_loworder.toml b/examples/kinetic-electrons/wall+sheath-bc_kinetic_loworder.toml index 1b8ca705d..6abaa537c 100644 --- a/examples/kinetic-electrons/wall+sheath-bc_kinetic_loworder.toml +++ b/examples/kinetic-electrons/wall+sheath-bc_kinetic_loworder.toml @@ -1,37 +1,47 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 electron_charge_exchange_frequency = 0.0 -nu_ei = 0.0 ionization_frequency = 2.0 #electron_ionization_frequency = 2.0 #ionization_energy = 1.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -#z_nelement = 32 -z_nelement = 64 -#z_nelement = 128 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_spacing_option = "sqrt" -vpa_ngrid = 5 -#vpa_nelement = 40 -vpa_nelement = 80 -vpa_L = 12.0 #8.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -#vpa_discretization = "gausslegendre_pseudospectral" -vz_ngrid = 5 -vz_nelement = 80 -vz_L = 12.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[electron_fluid_collisions] +nu_ei = 0.0 + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +#nelement = 32 +nelement = 64 +#nelement = 128 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 5 +#nelement = 40 +nelement = 80 +L = 12.0 #8.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +#discretization = "gausslegendre_pseudospectral" + +[vz] +ngrid = 5 +nelement = 80 +L = 12.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -75,7 +85,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -102,6 +112,8 @@ dt = 5.0e-5 nwrite = 200 nwrite_dfns = 10000 type = "SSPRK4" +steady_state_residual = true +converged_residual_value = 1.0e-3 [electron_timestepping] nstep = 5000000 diff --git a/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_braginskii-vpadiss0-IMEX.toml b/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_braginskii-vpadiss0-IMEX.toml index d0ab7a225..371ab8130 100644 --- a/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_braginskii-vpadiss0-IMEX.toml +++ b/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_braginskii-vpadiss0-IMEX.toml @@ -1,30 +1,41 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false + +[electron_fluid_collisions] nu_ei = 1000.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -z_nelement = 32 -#z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 6 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -69,7 +80,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -98,7 +109,7 @@ steady_state_residual = true converged_residual_value = 1.0e-3 #write_after_fixed_step_count = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_kinetic-vpadiss0.toml b/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_kinetic-vpadiss0.toml index 1fb3f2874..dc32eac73 100644 --- a/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_kinetic-vpadiss0.toml +++ b/examples/kinetic-electrons/wall-bc_recyclefraction0.5_split3_kinetic-vpadiss0.toml @@ -1,29 +1,38 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -z_nelement = 32 -#z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 6 -vpa_nelement = 63 -vpa_L = 48.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 6 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 6 +nelement = 63 +L = 48.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -68,7 +77,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -104,7 +113,7 @@ minimum_dt = 1.0e-9 initialization_residual_value = 2.5 converged_residual_value = 0.1 #1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split1.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split1.toml index c8178024f..b451b391f 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split1.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split1.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split2.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split2.toml index 46326e0f4..430a8c986 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split2.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split2.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split3.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split3.toml index fed5d3635..0a15cb08e 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split3.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_cheb_split3.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd.toml index 2d15df95f..b9b86dbd6 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd.toml @@ -1,20 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 400 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split1.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split1.toml index 0de21547e..b5ec2f939 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split1.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split1.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 400 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split2.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split2.toml index a5322c378..32983adcf 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split2.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split2.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 400 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split3.toml b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split3.toml index b17c8ff55..c483575bb 100644 --- a/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split3.toml +++ b/examples/nonlinear-sound-wave/nonlinear-sound-wave_fd_split3.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 400 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 400 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/numerical-dissipation/num-diss-relaxation.toml b/examples/numerical-dissipation/num-diss-relaxation.toml index 3b9e46fe5..06c0a3fe2 100644 --- a/examples/numerical-dissipation/num-diss-relaxation.toml +++ b/examples/numerical-dissipation/num-diss-relaxation.toml @@ -1,32 +1,45 @@ # cheap input file for a 0D2V relaxation with numerical diffusion terms d^2 F / dvpa^2 and d^2 F / vperp^2. -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.0 ionization_frequency = 0.0 -constant_ionization_rate = false + +[fokker_planck_collisions] +use_fokker_planck = true nuii = 0.0 -z_ngrid = 1 -z_nelement = 1 -z_nelement_local = 1 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -r_ngrid = 1 -r_nelement = 1 -r_nelement_local = 1 -r_bc = "periodic" -r_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 5 -vpa_nelement = 16 -vpa_L = 6.0 -vpa_bc = "zero" -vpa_discretization = "gausslegendre_pseudospectral" -vperp_ngrid = 5 -vperp_nelement = 8 -vperp_L = 3.0 -vperp_bc = "zero" -vperp_discretization = "gausslegendre_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[z] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[r] +ngrid = 1 +nelement = 1 +nelement_local = 1 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 5 +nelement = 16 +L = 6.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" + +[vperp] +ngrid = 5 +nelement = 8 +L = 3.0 +bc = "zero" +discretization = "gausslegendre_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5-init.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5-init.toml index 037890334..7fab193ae 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5-init.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5-init.toml @@ -1,30 +1,40 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 6 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 6 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -68,7 +78,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -91,7 +101,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5.toml index aff3860ba..3b9df9716 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5.toml @@ -1,30 +1,40 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -68,7 +78,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -96,7 +106,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split1.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split1.toml index db1f3d37d..327937702 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split1.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split1.toml @@ -1,30 +1,40 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -68,7 +78,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -96,7 +106,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split2.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split2.toml index 74ab5a029..93d16749e 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split2.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split2.toml @@ -1,30 +1,40 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -69,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -97,7 +107,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3-init.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3-init.toml index 3e5dbdd9d..23832cef8 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3-init.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3-init.toml @@ -1,30 +1,40 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 5 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 6 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 6 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 5 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 6 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -69,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -92,7 +102,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3.toml index 1dbb9b4ea..1cb0110ef 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3.toml @@ -1,30 +1,40 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -69,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -97,7 +107,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_SSPRK4.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_SSPRK4.toml index 7440dac74..4a0b35357 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_SSPRK4.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_SSPRK4.toml @@ -1,30 +1,40 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -68,7 +78,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -90,7 +100,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete104.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete104.toml index 71d776507..ff951756c 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete104.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete104.toml @@ -1,31 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -70,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -98,7 +107,7 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete42.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete42.toml index 3cd67baeb..70e939d5c 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete42.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete42.toml @@ -1,31 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -70,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -98,15 +107,18 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[numerical_dissipation] +[ion_numerical_dissipation] #vpa_dissipation_coefficient = 1.0e-1 #vpa_dissipation_coefficient = 1.0e-2 #vpa_dissipation_coefficient = 1.0e-3 force_minimum_pdf_value = 0.0 + +[neutral_numerical_dissipation] +force_minimum_pdf_value = 0.0 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete64.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete64.toml index f8354d268..f476acdc3 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete64.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_fekete64.toml @@ -1,31 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -70,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -98,15 +107,18 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[numerical_dissipation] -#vz_dissipation_coefficient = 1.0e-1 -#vz_dissipation_coefficient = 1.0e-2 -#vz_dissipation_coefficient = 1.0e-3 +[ion_numerical_dissipation] +#vpa_dissipation_coefficient = 1.0e-1 +#vpa_dissipation_coefficient = 1.0e-2 +#vpa_dissipation_coefficient = 1.0e-3 +force_minimum_pdf_value = 0.0 + +[neutral_numerical_dissipation] force_minimum_pdf_value = 0.0 diff --git a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_rkf54.toml b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_rkf54.toml index 52aeb9d2a..d80874761 100644 --- a/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_rkf54.toml +++ b/examples/recycling-fraction/wall-bc_recyclefraction0.5_split3_rkf54.toml @@ -1,31 +1,40 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 16 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vpa_element_spacing_option = "coarse_tails" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" -vz_element_spacing_option = "coarse_tails" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 16 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "coarse_tails" [composition] n_ion_species = 1 @@ -70,7 +79,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -98,15 +107,18 @@ converged_residual_value = 1.0e-3 [krook_collisions] use_krook = true -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[numerical_dissipation] +[ion_numerical_dissipation] #vpa_dissipation_coefficient = 1.0e-1 #vpa_dissipation_coefficient = 1.0e-2 #vpa_dissipation_coefficient = 1.0e-3 force_minimum_pdf_value = 0.0 + +[neutral_numerical_dissipation] +force_minimum_pdf_value = 0.0 diff --git a/examples/sheath+wall-bc_test/sheath-bc_cheb_test.toml b/examples/sheath+wall-bc_test/sheath-bc_cheb_test.toml index 4bb5e56a1..3ad8cd193 100644 --- a/examples/sheath+wall-bc_test/sheath-bc_cheb_test.toml +++ b/examples/sheath+wall-bc_test/sheath-bc_cheb_test.toml @@ -1,21 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 ionization_frequency = 2.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 10 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -60,7 +75,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/sheath+wall-bc_test/wall-bc_cheb_test.toml b/examples/sheath+wall-bc_test/wall-bc_cheb_test.toml index b9ed15f46..11f54c595 100644 --- a/examples/sheath+wall-bc_test/wall-bc_cheb_test.toml +++ b/examples/sheath+wall-bc_test/wall-bc_cheb_test.toml @@ -1,21 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 ionization_frequency = 2.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 10 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -59,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option= "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/sound-wave/sound-wave_cheb.toml b/examples/sound-wave/sound-wave_cheb.toml index 4c50b1c65..1c688d0b0 100644 --- a/examples/sound-wave/sound-wave_cheb.toml +++ b/examples/sound-wave/sound-wave_cheb.toml @@ -1,25 +1,35 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_cheb_split1.toml b/examples/sound-wave/sound-wave_cheb_split1.toml index 9ef684754..e83289a3d 100644 --- a/examples/sound-wave/sound-wave_cheb_split1.toml +++ b/examples/sound-wave/sound-wave_cheb_split1.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_cheb_split2.toml b/examples/sound-wave/sound-wave_cheb_split2.toml index 27989f73c..12423bfae 100644 --- a/examples/sound-wave/sound-wave_cheb_split2.toml +++ b/examples/sound-wave/sound-wave_cheb_split2.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_cheb_split3.toml b/examples/sound-wave/sound-wave_cheb_split3.toml index 0443db2d4..486edd65a 100644 --- a/examples/sound-wave/sound-wave_cheb_split3.toml +++ b/examples/sound-wave/sound-wave_cheb_split3.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_fd.toml b/examples/sound-wave/sound-wave_fd.toml index 5c45c3183..6374483d1 100644 --- a/examples/sound-wave/sound-wave_fd.toml +++ b/examples/sound-wave/sound-wave_fd.toml @@ -1,20 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 180 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_fd_split1.toml b/examples/sound-wave/sound-wave_fd_split1.toml index d25a888d4..962cc1a90 100644 --- a/examples/sound-wave/sound-wave_fd_split1.toml +++ b/examples/sound-wave/sound-wave_fd_split1.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 180 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_fd_split2.toml b/examples/sound-wave/sound-wave_fd_split2.toml index 658572f1f..36e0cb809 100644 --- a/examples/sound-wave/sound-wave_fd_split2.toml +++ b/examples/sound-wave/sound-wave_fd_split2.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 180 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/sound-wave/sound-wave_fd_split3.toml b/examples/sound-wave/sound-wave_fd_split3.toml index 76c205b6a..7e46898d8 100644 --- a/examples/sound-wave/sound-wave_fd_split3.toml +++ b/examples/sound-wave/sound-wave_fd_split3.toml @@ -1,20 +1,36 @@ -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.62831853071 ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 100 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 180 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 100 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" + +[vz] +ngrid = 180 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [composition] n_ion_species = 1 diff --git a/examples/wall-bc/wall+sheath-bc.toml b/examples/wall-bc/wall+sheath-bc.toml index 4e582624e..cb62a6173 100644 --- a/examples/wall-bc/wall+sheath-bc.toml +++ b/examples/wall-bc/wall+sheath-bc.toml @@ -1,26 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 2.0 ionization_frequency = 2.0 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 2 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 10 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 10 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 2 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 10 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -55,7 +65,7 @@ temperature_phase = 0.0 initial_density = 1.0 initial_temperature = 1.0 -[z_IC_eutral_species_1] +[z_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 0.001 density_phase = 0.0 @@ -64,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_eutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 diff --git a/examples/wall-bc/wall-bc_cheb.toml b/examples/wall-bc/wall-bc_cheb.toml index d0228533e..fdd9c8c24 100644 --- a/examples/wall-bc/wall-bc_cheb.toml +++ b/examples/wall-bc/wall-bc_cheb.toml @@ -1,26 +1,36 @@ -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = false +[reactions] charge_exchange_frequency = 0.5 ionization_frequency = 0.75 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 9 -vpa_nelement = 64 -vpa_L = 18.0 -vpa_bc = "both_zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = false + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -64,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -85,4 +95,4 @@ force_minimum_pdf_value = 0.0 [neutral_numerical_dissipation] #vz_dissipation_coefficient = 1.0e-3 #1.0e-2 #1.0e-1 -force_minimum_pdf_value = 0.0 \ No newline at end of file +force_minimum_pdf_value = 0.0 diff --git a/examples/wall-bc/wall-bc_cheb_split1.toml b/examples/wall-bc/wall-bc_cheb_split1.toml index 78474d3d0..07269f7eb 100644 --- a/examples/wall-bc/wall-bc_cheb_split1.toml +++ b/examples/wall-bc/wall-bc_cheb_split1.toml @@ -1,27 +1,36 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.5 ionization_frequency = 0.75 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 9 -vpa_nelement = 64 -vpa_L = 18.0 -vpa_bc = "both_zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -65,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -86,4 +95,4 @@ force_minimum_pdf_value = 0.0 [neutral_numerical_dissipation] #vz_dissipation_coefficient = 1.0e-3 #1.0e-2 #1.0e-1 -force_minimum_pdf_value = 0.0 \ No newline at end of file +force_minimum_pdf_value = 0.0 diff --git a/examples/wall-bc/wall-bc_cheb_split2.toml b/examples/wall-bc/wall-bc_cheb_split2.toml index 81530feec..8b0a9ab85 100644 --- a/examples/wall-bc/wall-bc_cheb_split2.toml +++ b/examples/wall-bc/wall-bc_cheb_split2.toml @@ -1,27 +1,36 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.5 ionization_frequency = 0.75 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 9 -vpa_nelement = 64 -vpa_L = 18.0 -vpa_bc = "both_zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -65,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -86,4 +95,4 @@ force_minimum_pdf_value = 0.0 [neutral_numerical_dissipation] #vz_dissipation_coefficient = 1.0e-3 #1.0e-2 #1.0e-1 -force_minimum_pdf_value = 0.0 \ No newline at end of file +force_minimum_pdf_value = 0.0 diff --git a/examples/wall-bc/wall-bc_cheb_split3.toml b/examples/wall-bc/wall-bc_cheb_split3.toml index 7834ba468..911634d85 100644 --- a/examples/wall-bc/wall-bc_cheb_split3.toml +++ b/examples/wall-bc/wall-bc_cheb_split3.toml @@ -1,27 +1,36 @@ -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.5 ionization_frequency = 0.75 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 9 -vpa_nelement = 64 -vpa_L = 18.0 -vpa_bc = "both_zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 9 -vz_nelement = 64 -vz_L = 18.0 -vz_bc = "both_zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 9 +nelement = 64 +L = 18.0 +bc = "both_zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -65,7 +74,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -86,4 +95,4 @@ force_minimum_pdf_value = 0.0 [neutral_numerical_dissipation] #vz_dissipation_coefficient = 1.0e-3 #1.0e-2 #1.0e-1 -force_minimum_pdf_value = 0.0 \ No newline at end of file +force_minimum_pdf_value = 0.0 diff --git a/examples/wall-bc/wall-bc_no-neutrals.toml b/examples/wall-bc/wall-bc_no-neutrals.toml index fc980405f..51de95096 100644 --- a/examples/wall-bc/wall-bc_no-neutrals.toml +++ b/examples/wall-bc/wall-bc_no-neutrals.toml @@ -1,27 +1,33 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -runtime_plots = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -59,8 +65,10 @@ dt = 5.0e-4 nwrite = 5000 nwrite_dfns = 5000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/examples/wall-bc/wall-bc_no-neutrals_split1.toml b/examples/wall-bc/wall-bc_no-neutrals_split1.toml index a9ac4ee25..1fa86597a 100644 --- a/examples/wall-bc/wall-bc_no-neutrals_split1.toml +++ b/examples/wall-bc/wall-bc_no-neutrals_split1.toml @@ -1,27 +1,33 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -59,8 +65,10 @@ dt = 1.0e-4 nwrite = 5000 nwrite_dfns = 5000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 @@ -75,4 +83,4 @@ source_T = 1.0 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_no-neutrals_split2.toml b/examples/wall-bc/wall-bc_no-neutrals_split2.toml index 66728bc89..3f231f263 100644 --- a/examples/wall-bc/wall-bc_no-neutrals_split2.toml +++ b/examples/wall-bc/wall-bc_no-neutrals_split2.toml @@ -1,27 +1,33 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -59,8 +65,10 @@ dt = 1.0e-4 nwrite = 5000 nwrite_dfns = 5000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 @@ -75,4 +83,4 @@ source_T = 1.0 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_no-neutrals_split3.toml b/examples/wall-bc/wall-bc_no-neutrals_split3.toml index 126a72cfd..50df8c88c 100644 --- a/examples/wall-bc/wall-bc_no-neutrals_split3.toml +++ b/examples/wall-bc/wall-bc_no-neutrals_split3.toml @@ -1,27 +1,33 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -59,8 +65,10 @@ dt = 1.0e-4 nwrite = 5000 nwrite_dfns = 5000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 @@ -75,4 +83,4 @@ force_minimum_pdf_value = 0.0 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_volumerecycle.toml b/examples/wall-bc/wall-bc_volumerecycle.toml index 71892195e..33deae796 100644 --- a/examples/wall-bc/wall-bc_volumerecycle.toml +++ b/examples/wall-bc/wall-bc_volumerecycle.toml @@ -1,31 +1,38 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -70,7 +77,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -85,15 +92,17 @@ dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[neutral_source] +[neutral_source_1] active = true source_type = "recycling" recycling_controller_fraction = 0.25 @@ -112,4 +121,4 @@ force_minimum_pdf_value = 0.0 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_volumerecycle_split1.toml b/examples/wall-bc/wall-bc_volumerecycle_split1.toml index bc5123654..9e990d368 100644 --- a/examples/wall-bc/wall-bc_volumerecycle_split1.toml +++ b/examples/wall-bc/wall-bc_volumerecycle_split1.toml @@ -1,31 +1,38 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -70,7 +77,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -85,15 +92,17 @@ dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[neutral_source] +[neutral_source_1] active = true source_type = "recycling" recycling_controller_fraction = 0.25 @@ -112,4 +121,4 @@ recycling_controller_fraction = 0.25 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_volumerecycle_split2.toml b/examples/wall-bc/wall-bc_volumerecycle_split2.toml index acc92a7d2..440687586 100644 --- a/examples/wall-bc/wall-bc_volumerecycle_split2.toml +++ b/examples/wall-bc/wall-bc_volumerecycle_split2.toml @@ -1,31 +1,38 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -70,7 +77,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -85,15 +92,17 @@ dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[neutral_source] +[neutral_source_1] active = true source_type = "recycling" recycling_controller_fraction = 0.25 @@ -112,4 +121,4 @@ recycling_controller_fraction = 0.25 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/examples/wall-bc/wall-bc_volumerecycle_split3.toml b/examples/wall-bc/wall-bc_volumerecycle_split3.toml index 477a943e9..8c9ca7356 100644 --- a/examples/wall-bc/wall-bc_volumerecycle_split3.toml +++ b/examples/wall-bc/wall-bc_volumerecycle_split3.toml @@ -1,31 +1,38 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -#z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 30.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 30.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +#nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 30.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 30.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [composition] n_ion_species = 1 @@ -70,7 +77,7 @@ upar_phase = 0.0 temperature_amplitude = 0.0 temperature_phase = 0.0 -[vpa_IC_neutral_species_1] +[vz_IC_neutral_species_1] initialization_option = "gaussian" density_amplitude = 1.0 density_phase = 0.0 @@ -85,15 +92,17 @@ dt = 1.0e-5 nwrite = 10000 nwrite_dfns = 10000 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 source_strength = 2.0 source_T = 2.0 -[neutral_source] +[neutral_source_1] active = true source_type = "recycling" recycling_controller_fraction = 0.25 @@ -112,4 +121,4 @@ force_minimum_pdf_value = 0.0 [krook_collisions] use_krook = true -frequency_option = "reference_parameters" \ No newline at end of file +frequency_option = "reference_parameters" diff --git a/makie_post_processing/makie_post_processing/src/makie_post_processing.jl b/makie_post_processing/makie_post_processing/src/makie_post_processing.jl index fb5aeefa0..1b4b024e2 100644 --- a/makie_post_processing/makie_post_processing/src/makie_post_processing.jl +++ b/makie_post_processing/makie_post_processing/src/makie_post_processing.jl @@ -29,7 +29,6 @@ using moment_kinetics.analysis: analyze_fields_data, check_Chodura_condition, get_unnormalised_f_1d, vpagrid_to_dzdt_2d, get_unnormalised_f_2d using moment_kinetics.array_allocation: allocate_float -using moment_kinetics.coordinates: define_coordinate using moment_kinetics.input_structs using moment_kinetics.looping: all_dimensions, ion_dimensions, neutral_dimensions using moment_kinetics.manufactured_solns: manufactured_solutions, @@ -40,7 +39,8 @@ using moment_kinetics.load_data: close_run_info, get_run_info_no_setup, get_vari neutral_moment_variables, all_moment_variables, ion_dfn_variables, electron_dfn_variables, neutral_dfn_variables, all_dfn_variables, ion_variables, - neutral_variables, all_variables + neutral_variables, all_variables, ion_source_variables, + neutral_source_variables, electron_source_variables using moment_kinetics.initial_conditions: vpagrid_to_dzdt using .shared_utils: calculate_and_write_frequencies using moment_kinetics.type_definitions: mk_float, mk_int @@ -233,14 +233,6 @@ function makie_post_process(run_dir::Union{String,Tuple}, # Plots from moment variables ############################# - moment_variable_list = tuple(em_variables..., ion_moment_variables...) - if has_electrons - moment_variable_list = tuple(moment_variable_list..., electron_moment_variables...) - end - if has_neutrals - moment_variable_list = tuple(moment_variable_list..., neutral_moment_variables...) - end - if any(ri !== nothing for ri ∈ run_info_moments) has_moments = true @@ -276,7 +268,7 @@ function makie_post_process(run_dir::Union{String,Tuple}, end do_steady_state_residuals = any(input_dict[v]["steady_state_residual"] - for v ∈ moment_variable_list) + for v ∈ all_moment_variables) if do_steady_state_residuals textoutput_files = Tuple(ri.run_prefix * "_residuals.txt" for ri in run_info if ri !== nothing) @@ -299,7 +291,7 @@ function makie_post_process(run_dir::Union{String,Tuple}, steady_state_residual_fig_axes = nothing end - for variable_name ∈ moment_variable_list + for variable_name ∈ all_moment_variables plots_for_variable(run_info, variable_name; plot_prefix=plot_prefix, has_rdim=has_rdim, has_zdim=has_zdim, is_1V=is_1V, steady_state_residual_fig_axes=steady_state_residual_fig_axes) @@ -818,6 +810,9 @@ function _setup_single_input!(this_input_dict::OrderedDict{String,Any}, animate_steady_state_residual=false, ) + # We allow top-level options in the post-processing input file + check_sections!(this_input_dict; check_no_top_level_options=false) + return nothing end @@ -1011,6 +1006,10 @@ function plots_for_variable(run_info, variable_name; plot_prefix, has_rdim=true, all(ri.collisions.krook_collisions_option == "none" for ri ∈ run_info) # No Krook collisions active, so do not make plots. return nothing + elseif variable_name ∈ union(electron_moment_variables, electron_source_variables, electron_dfn_variables) && + all(ri.composition.electron_physics ∈ (boltzmann_electron_response, boltzmann_electron_response_with_simple_sheath) + for ri ∈ run_info) + return nothing end println("Making plots for $variable_name") @@ -1030,8 +1029,18 @@ function plots_for_variable(run_info, variable_name; plot_prefix, has_rdim=true, elseif variable_name ∈ neutral_moment_variables || variable_name ∈ neutral_dfn_variables species_indices = 1:maximum(ri.n_neutral_species for ri ∈ run_info) - else + elseif variable_name ∈ ion_moment_variables || + variable_name ∈ ion_dfn_variables species_indices = 1:maximum(ri.n_ion_species for ri ∈ run_info) + elseif variable_name in ion_source_variables + species_indices = 1:maximum(length(ri.external_source_settings.ion) for ri ∈ run_info) + elseif variable_name in electron_source_variables + species_indices = 1:maximum(length(ri.external_source_settings.electron) for ri ∈ run_info) + elseif variable_name in neutral_source_variables + species_indices = 1:maximum(length(ri.external_source_settings.neutral) for ri ∈ run_info) + else + species_indices = 1:1 + #error("variable_name=$variable_name not found in any defined group") end for is ∈ species_indices if is !== nothing diff --git a/makie_post_processing/makie_post_processing/src/shared_utils.jl b/makie_post_processing/makie_post_processing/src/shared_utils.jl index 7ce536326..c01d55bc3 100644 --- a/makie_post_processing/makie_post_processing/src/shared_utils.jl +++ b/makie_post_processing/makie_post_processing/src/shared_utils.jl @@ -7,7 +7,7 @@ using moment_kinetics.array_allocation: allocate_float using moment_kinetics.coordinates: define_coordinate using moment_kinetics.input_structs: boltzmann_electron_response, boltzmann_electron_response_with_simple_sheath, - grid_input, geometry_input, species_composition + geometry_input, species_composition using moment_kinetics.type_definitions: mk_float, mk_int using moment_kinetics.reference_parameters: setup_reference_parameters using moment_kinetics.geo: init_magnetic_geometry, setup_geometry_input diff --git a/moment_kinetics/debug_test/debug_redundant_synchronization/runtest_template.jl b/moment_kinetics/debug_test/debug_redundant_synchronization/runtest_template.jl index 32050ead4..17b37e1c9 100644 --- a/moment_kinetics/debug_test/debug_redundant_synchronization/runtest_template.jl +++ b/moment_kinetics/debug_test/debug_redundant_synchronization/runtest_template.jl @@ -7,7 +7,7 @@ function run_test(test_input; args...) # update the default inputs # Convert keyword arguments to a unique name - name = test_input["run_name"] + name = test_input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -25,7 +25,7 @@ function run_test(test_input; args...) # Update default inputs with values to be changed input = merge(test_input, modified_inputs) - input["run_name"] = name + input["output"]["run_name"] = name # run simulation run_moment_kinetics(input) diff --git a/moment_kinetics/debug_test/fokker_planck_collisions_inputs.jl b/moment_kinetics/debug_test/fokker_planck_collisions_inputs.jl index 671a69448..6ea191525 100644 --- a/moment_kinetics/debug_test/fokker_planck_collisions_inputs.jl +++ b/moment_kinetics/debug_test/fokker_planck_collisions_inputs.jl @@ -3,7 +3,7 @@ test_type = "Fokker-Planck collisions" # default input for test test_input_full_f = OptionsDict( - "run_name" => "full_f", + "output" => OptionsDict("run_name" => "full_f"), "timestepping" => OptionsDict("dt" => 0.0, "nstep" => 3, "nwrite" => 2, @@ -13,10 +13,10 @@ test_input_full_f = OptionsDict( "T_e" => 1.0, "T_wall" => 1.0, "electron_physics" => "boltzmann_electron_response"), - "evolve_moments_conservation" => false, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, + "evolve_moments" => OptionsDict("moments_conservation" => false, + "density" => false, + "parallel_flow" => false, + "parallel_pressure" => false), "ion_species_1" => OptionsDict("initial_density" => 0.5, "initial_temperature" => 1.0), "z_IC_ion_species_1" => OptionsDict("density_amplitude" => 0.001, @@ -26,29 +26,28 @@ test_input_full_f = OptionsDict( "temperature_phase" => 0.0, "upar_amplitude" => 0.0, "upar_phase" => 0.0), - "charge_exchange_frequency" => 0.0, - "ionization_frequency" => 0.0, - "constant_ionization_rate" => false, + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0, + "ionization_frequency" => 0.0), "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "nuii" => 1.0, "frequency_option" => "manual"), - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "r_nelement" => 1, - "r_ngrid" => 3, - "vpa_L" => 6.0, - "vpa_bc" => "zero", - "vpa_discretization" => "gausslegendre_pseudospectral", - "vpa_nelement" => 2, - "vpa_ngrid" => 3, - "vperp_L" => 3.0, - "vperp_discretization" => "gausslegendre_pseudospectral", - "vperp_nelement" => 2, - "vperp_ngrid" => 3, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "z_nelement" => 1, - "z_ngrid" => 3, + "r" => OptionsDict("bc" => "periodic", + "discretization" => "chebyshev_pseudospectral", + "nelement" => 1, + "ngrid" => 3), + "vpa" => OptionsDict("L" => 6.0, + "bc" => "zero", + "discretization" => "gausslegendre_pseudospectral", + "nelement" => 2, + "ngrid" => 3), + "vperp" => OptionsDict("L" => 3.0, + "discretization" => "gausslegendre_pseudospectral", + "nelement" => 2, + "ngrid" => 3), + "z" => OptionsDict("bc" => "wall", + "discretization" => "chebyshev_pseudospectral", + "nelement" => 1, + "ngrid" => 3), ) test_input_list = [ diff --git a/moment_kinetics/debug_test/gyroaverage_inputs.jl b/moment_kinetics/debug_test/gyroaverage_inputs.jl index 516d4c674..9855050c3 100644 --- a/moment_kinetics/debug_test/gyroaverage_inputs.jl +++ b/moment_kinetics/debug_test/gyroaverage_inputs.jl @@ -3,16 +3,16 @@ test_type = "gyroaverage" # default inputs for tests test_input = OptionsDict( - "run_name" => "gyroaverage", + "output" => OptionsDict("run_name" => "gyroaverage"), "composition" => OptionsDict("n_ion_species" => 1, "n_neutral_species" => 0, "gyrokinetic_ions" => true, "T_e" => 1.0, "T_wall" => 1.0), - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), "ion_species_1" => OptionsDict("initial_density" => 1.0, "initial_temperature" => 1.0), "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", @@ -29,37 +29,37 @@ test_input = OptionsDict( "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "charge_exchange_frequency" => 0.0, - "ionization_frequency" => 0.05, - "constant_ionization_rate" => true, + "ion_source_1" => OptionsDict("z_profile" => "constant", + "source_strength" => 0.05, + "source_T" => 0.25), "timestepping" => OptionsDict("nstep" => 3, "dt" => 1.0e-12, "nwrite" => 2, "nwrite_dfns" => 2,), - "r_ngrid" => 5, - "r_nelement" => 2, - "r_bc" => "periodic", - "z_ngrid" => 5, - "z_nelement" => 2, - "z_bc" => "periodic", - "z_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 5, - "vpa_nelement" => 2, - "vpa_L" => 6.0, - "vpa_bc" => "zero", - "vpa_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 5, - "vperp_nelement" => 1, - "vperp_L" => 3.0, - "vperp_bc" => "zero", - "vperp_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 5, - "vz_nelement" => 2, - "vz_L" => 6.0, - "vz_bc" => "zero", - "vz_discretization" => "chebyshev_pseudospectral", - "numerical_dissipation" => OptionsDict("vpa_dissipation_coefficient" => 1.0e-3, - "vperp_dissipation_coefficient" => 1.0e-3), + "r" => OptionsDict("ngrid" => 5, + "nelement" => 2, + "bc" => "periodic"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 2, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 5, + "nelement" => 2, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "L" => 3.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 5, + "nelement" => 2, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "ion_numerical_dissipation" => OptionsDict("vpa_dissipation_coefficient" => 1.0e-3, + "vperp_dissipation_coefficient" => 1.0e-3), "geometry" => OptionsDict("DeltaB"=>0.0, "option"=>"constant-helical", "pitch"=>0.1, diff --git a/moment_kinetics/debug_test/kinetic_electron_inputs.jl b/moment_kinetics/debug_test/kinetic_electron_inputs.jl index cc8c50f3e..0d4e8d042 100644 --- a/moment_kinetics/debug_test/kinetic_electron_inputs.jl +++ b/moment_kinetics/debug_test/kinetic_electron_inputs.jl @@ -2,94 +2,97 @@ test_type = "Kinetic electron" using moment_kinetics.type_definitions: OptionsDict test_input = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "kinetic_electrons", - "recycling_fraction" => 0.5, - "T_e" => 0.2, - "T_wall" => 0.1), - "run_name" => "kinetic_electron", - "base_directory" => test_output_directory, - "evolve_moments_density" => true, - "evolve_moments_parallel_flow" => true, - "evolve_moments_parallel_pressure" => true, - "evolve_moments_conservation" => true, - "ion_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => 1.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, + "n_neutral_species" => 1, + "electron_physics" => "kinetic_electrons", + "recycling_fraction" => 0.5, + "T_e" => 0.2, + "T_wall" => 0.1), + "output" => OptionsDict("run_name" => "kinetic_electron", + "base_directory" => test_output_directory), + "evolve_moments" => OptionsDict("density" => true, + "parallel_flow" => true, + "parallel_pressure" => true, + "moments_conservation" => true), + "ion_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.001, "density_phase" => 0.0, - "upar_amplitude" => 0.0, + "upar_amplitude" => 1.0, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "neutral_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.001, + "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, "density_phase" => 0.0, - "upar_amplitude" => -1.0, + "upar_amplitude" => 0.0, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "vpa_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, + "neutral_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.001, "density_phase" => 0.0, - "upar_amplitude" => 0.0, + "upar_amplitude" => -1.0, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "charge_exchange_frequency" => 0.75, - "ionization_frequency" => 0.5, - "constant_ionization_rate" => false, - "timestepping" => OptionsDict("type" => "Fekete4(3)", - "nstep" => 3, - "dt" => 2.0e-8, - "minimum_dt" => 1.0e-8, - "CFL_prefactor" => 1.0, - "step_update_prefactor" => 0.4, - "nwrite" => 2, - "split_operators" => false), - "electron_timestepping" => OptionsDict("type" => "Fekete4(3)", - "nstep" => 10, - "dt" => 4.0e-11, - "minimum_dt" => 2.0e-11, - "initialization_residual_value" => 1.e10, - "converged_residual_value" => 1.e10, - "nwrite" => 10000, - "nwrite_dfns" => 10000, - "no_restart" => true), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 3, - "z_nelement" => 24, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "z_element_spacing_option" => "sqrt", - "vpa_ngrid" => 3, - "vpa_nelement" => 16, - "vpa_L" => 6.0, - "vpa_bc" => "zero", - "vpa_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 6, - "vz_L" => 6.0, - "vz_bc" => "zero", - "vz_discretization" => "chebyshev_pseudospectral", - "ion_source" => OptionsDict("active" => true, - "z_profile" => "gaussian", - "z_width" => 0.125, - "source_strength" => 2.0, - "source_T" => 2.0), - "krook_collisions" => OptionsDict("use_krook" => true), - "numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, - "vpa_dissipation_coefficient" => 1e-2)) + "vz_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.75, + "ionization_frequency" => 0.5), + "timestepping" => OptionsDict("type" => "Fekete4(3)", + "nstep" => 3, + "dt" => 2.0e-8, + "minimum_dt" => 1.0e-8, + "CFL_prefactor" => 1.0, + "step_update_prefactor" => 0.4, + "nwrite" => 2, + "split_operators" => false), + "electron_timestepping" => OptionsDict("type" => "Fekete4(3)", + "nstep" => 10, + "dt" => 4.0e-11, + "minimum_dt" => 2.0e-11, + "initialization_residual_value" => 1.e10, + "converged_residual_value" => 1.e10, + "nwrite" => 10000, + "nwrite_dfns" => 10000, + "no_restart" => true), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 3, + "nelement" => 24, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral", + "element_spacing_option" => "sqrt"), + "vpa" => OptionsDict("ngrid" => 3, + "nelement" => 16, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 3, + "nelement" => 6, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "ion_source_1" => OptionsDict("active" => true, + "z_profile" => "gaussian", + "z_width" => 0.125, + "source_strength" => 2.0, + "source_T" => 2.0), + "krook_collisions" => OptionsDict("use_krook" => true), + "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vpa_dissipation_coefficient" => 1e-2), + "electron_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vpa_dissipation_coefficient" => 1e-2), + "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vz_dissipation_coefficient" => 1e-2)) test_input_list = [ diff --git a/moment_kinetics/debug_test/mms_inputs.jl b/moment_kinetics/debug_test/mms_inputs.jl index 5db15d46b..ce6ddf196 100644 --- a/moment_kinetics/debug_test/mms_inputs.jl +++ b/moment_kinetics/debug_test/mms_inputs.jl @@ -4,55 +4,55 @@ test_type = "MMS" # default inputs for tests test_input = OptionsDict( "manufactured_solns" => OptionsDict("use_for_advance"=>true), - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), "composition" => OptionsDict("n_ion_species" => 1, "n_neutral_species" => 1, "electron_physics" => "boltzmann_electron_response", "T_e" => 1.0, "T_wall" => 1.0), - "run_name" => "MMS-2D-wall_cheb-with-neutrals", - "charge_exchange_frequency" => 0.0, - "ionization_frequency" => 0.0, + "output" => OptionsDict("run_name" => "MMS-2D-wall_cheb-with-neutrals"), + "recations" => OptionsDict("charge_exchange_frequency" => 0.0, + "ionization_frequency" => 0.0), "timestepping" => OptionsDict("nstep" => 3, "dt" => 1.e-8, "nwrite" => 2, "type" => "SSPRK2", "split_operators" => false), - "z_ngrid" => 3, - "z_nelement" => 2, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "r_ngrid" => 3, - "r_nelement" => 2, - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vpa_L" => 12.0, - "vpa_bc" => "periodic", - "vpa_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 3, - "vperp_nelement" => 2, - "vperp_L" => 6.0, - "vperp_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2, - "vz_L" => 12.0, - "vz_bc" => "none", - "vz_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 3, - "vr_nelement" => 2, - "vr_L" => 12.0, - "vr_bc" => "none", - "vr_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 3, - "vzeta_nelement" => 2, - "vzeta_L" => 12.0, - "vzeta_bc" => "none", - "vzeta_discretization" => "chebyshev_pseudospectral", + "z" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral"), + "r" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 12.0, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 6.0, + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 12.0, + "bc" => "none", + "discretization" => "chebyshev_pseudospectral"), + "vr" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 12.0, + "bc" => "none", + "discretization" => "chebyshev_pseudospectral"), + "vzeta" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 12.0, + "bc" => "none", + "discretization" => "chebyshev_pseudospectral"), "geometry" => OptionsDict("rhostar" => 1.0,), ) diff --git a/moment_kinetics/debug_test/recycling_fraction_inputs.jl b/moment_kinetics/debug_test/recycling_fraction_inputs.jl index fdefdfe8a..fec866af1 100644 --- a/moment_kinetics/debug_test/recycling_fraction_inputs.jl +++ b/moment_kinetics/debug_test/recycling_fraction_inputs.jl @@ -1,105 +1,107 @@ test_type = "Recycling fraction and adaptive timestepping" using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge test_input = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "recycling_fraction" => 0.5, - "T_e" => 0.2, - "T_wall" => 2.0), - "ion_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "run_name" => "full-f", - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, - "krook_collisions" => OptionsDict("use_krook" => true), - "z_IC_ion_species_1" => OptionsDict("density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => 1.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0, - "initialization_option" => "gaussian"), - "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "neutral_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => -1.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "charge_exchange_frequency" => 0.75, - "ionization_frequency" => 0.5, - "constant_ionization_rate" => false, - "timestepping" => OptionsDict("type" => "Fekete4(3)", - "nstep" => 3, - "dt" => 1.0e-8, - "minimum_dt" => 1.0e-8, - "CFL_prefactor" => 1.0, - "step_update_prefactor" => 0.5, - "nwrite" => 2, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 3, - "z_nelement" => 2, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "z_element_spacing_option" => "sqrt", - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vpa_L" => 6.0, - "vpa_bc" => "zero", - "vpa_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2, - "vz_L" => 6.0, - "vz_bc" => "zero", - "vz_discretization" => "chebyshev_pseudospectral", - "ion_source" => OptionsDict("active" => true, - "z_profile" => "gaussian", - "z_width" => 0.125, - "source_strength" => 2.0, - "source_T" => 2.0)) + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "recycling_fraction" => 0.5, + "T_e" => 0.2, + "T_wall" => 2.0), + "ion_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "output" => OptionsDict("run_name" => "full-f", + "base_directory" => test_output_directory), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), + "krook_collisions" => OptionsDict("use_krook" => true), + "z_IC_ion_species_1" => OptionsDict("density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => 1.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0, + "initialization_option" => "gaussian"), + "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "neutral_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => -1.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "vz_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.75, + "ionization_frequency" => 0.5), + "timestepping" => OptionsDict("type" => "Fekete4(3)", + "nstep" => 3, + "dt" => 1.0e-8, + "minimum_dt" => 1.0e-8, + "CFL_prefactor" => 1.0, + "step_update_prefactor" => 0.5, + "nwrite" => 2, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral", + "element_spacing_option" => "sqrt"), + "vpa" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 6.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "ion_source_1" => OptionsDict("active" => true, + "z_profile" => "gaussian", + "z_width" => 0.125, + "source_strength" => 2.0, + "source_T" => 2.0)) -test_input_split1 = merge(test_input, - OptionsDict("run_name" => "split1", - "evolve_moments_density" => true, - "evolve_moments_conservation" => true)) -test_input_split2 = merge(test_input_split1, - OptionsDict("run_name" => "split2", - "evolve_moments_parallel_flow" => true)) -test_input_split2["timestepping"] = merge(test_input_split2["timestepping"], - OptionsDict("step_update_prefactor" => 0.4)) -test_input_split3 = merge(test_input_split2, - OptionsDict("run_name" => "split3", - "evolve_moments_parallel_pressure" => true, - "vpa_nelement" => 8, - "vz_nelement" => 8, - "numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, - "vpa_dissipation_coefficient" => 1e-2))) -test_input_split3["timestepping"] = merge(test_input_split3["timestepping"], - OptionsDict("dt" => 1.0e-9, - "minimum_dt" => 1.0e-9)) +test_input_split1 = recursive_merge(test_input, + OptionsDict("output" => OptionsDict("run_name" => "split1"), + "evolve_moments" => OptionsDict("density" => true, + "moments_conservation" => true))) +test_input_split2 = recursive_merge(test_input_split1, + OptionsDict("output" => OptionsDict("run_name" => "split2"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) +test_input_split2["timestepping"] = recursive_merge(test_input_split2["timestepping"], + OptionsDict("step_update_prefactor" => 0.4)) +test_input_split3 = recursive_merge(test_input_split2, + OptionsDict("output" => OptionsDict("run_name" => "split3"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("nelement" => 8), + "vz" => OptionsDict("nelement" => 8), + "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vpa_dissipation_coefficient" => 1e-2), + "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vz_dissipation_coefficient" => 1e-2))) +test_input_split3["timestepping"] = recursive_merge(test_input_split3["timestepping"], + OptionsDict("dt" => 1.0e-9, + "minimum_dt" => 1.0e-9)) test_input_list = [ diff --git a/moment_kinetics/debug_test/restart_interpolation_inputs.jl b/moment_kinetics/debug_test/restart_interpolation_inputs.jl index 1041423cf..6c70b5d30 100644 --- a/moment_kinetics/debug_test/restart_interpolation_inputs.jl +++ b/moment_kinetics/debug_test/restart_interpolation_inputs.jl @@ -1,71 +1,72 @@ test_type = "restart_interpolation" using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge # default inputs for tests base_input = OptionsDict( - "run_name" => "base", + "output" => OptionsDict("run_name" => "base", + "base_directory" => test_output_directory), "composition" => OptionsDict("n_ion_species" => 2, - "n_neutral_species" => 2, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0), - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "charge_exchange_frequency" => 2*π*0.1, - "ionization_frequency" => 0.0, + "n_neutral_species" => 2, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*π*0.1, + "ionization_frequency" => 0.0), "timestepping" => OptionsDict("nstep" => 3, - "dt" => 0.0, - "nwrite" => 2, - "type" => "SSPRK2", - "split_operators" => false), - "z_ngrid" => 3, - "z_nelement" => 2, - "z_bc" => "periodic", - "z_discretization" => "chebyshev_pseudospectral", - "r_ngrid" => 1, - "r_nelement" => 1, - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vpa_L" => 8.0, - "vpa_bc" => "periodic", - "vpa_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vz_ngrid" => 3, - "vz_nelement" => 2, - "vz_L" => 8.0, - "vz_bc" => "periodic", - "vz_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, - "vr_ngrid" => 1, - "vr_nelement" => 1, + "dt" => 0.0, + "nwrite" => 2, + "type" => "SSPRK2", + "split_operators" => false), + "z" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vpa" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vz" => OptionsDict("ngrid" => 3, + "nelement" => 2, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vzeta" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vr" => OptionsDict("ngrid" => 1, + "nelement" => 1), "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0), "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0)) test_input = - merge(base_input, - OptionsDict("run_name" => "full-f", - "z_nelement" => 3, - "vpa_nelement" => 3, - "vz_nelement" => 3)) + recursive_merge(base_input, + OptionsDict("output" => OptionsDict("run_name" => "full-f"), + "z" => OptionsDict("nelement" => 3), + "vpa" => OptionsDict("nelement" => 3), + "vz" => OptionsDict("nelement" => 3))) test_input_split1 = - merge(test_input, - OptionsDict("run_name" => "split1", - "evolve_moments_density" => true)) + recursive_merge(test_input, + OptionsDict("output" => OptionsDict("run_name" => "split1"), + "evolve_moments" => OptionsDict("density" => true))) -test_input_split2 = - merge(test_input_split1 , - OptionsDict("run_name" => "split2", - "evolve_moments_parallel_flow" => true)) + test_input_split2 = + recursive_merge(test_input_split1 , + OptionsDict("output" => OptionsDict("run_name" => "split2"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) -test_input_split3 = - merge(test_input_split2, - OptionsDict("run_name" => "split3", - "evolve_moments_parallel_pressure" => true)) + test_input_split3 = + recursive_merge(test_input_split2, + OptionsDict("output" => OptionsDict("run_name" => "split3"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_list = [ test_input, diff --git a/moment_kinetics/debug_test/restart_interpolation_tests.jl b/moment_kinetics/debug_test/restart_interpolation_tests.jl index 21faff756..8fea9a42b 100644 --- a/moment_kinetics/debug_test/restart_interpolation_tests.jl +++ b/moment_kinetics/debug_test/restart_interpolation_tests.jl @@ -12,9 +12,9 @@ include("restart_interpolation_inputs.jl") run_moment_kinetics(base_input) if moment_kinetics.file_io.io_has_parallel(Val(moment_kinetics.file_io.hdf5)) - base_output_file = realpath(joinpath(base_input["base_directory"], base_input["run_name"], string(base_input["run_name"], ".dfns.h5"))) + base_output_file = realpath(joinpath(base_input["output"]["base_directory"], base_input["output"]["run_name"], string(base_input["output"]["run_name"], ".dfns.h5"))) else - base_output_file = realpath(joinpath(base_input["base_directory"], base_input["run_name"], string(base_input["run_name"], ".dfns.0.h5"))) + base_output_file = realpath(joinpath(base_input["output"]["base_directory"], base_input["output"]["run_name"], string(base_input["output"]["run_name"], ".dfns.0.h5"))) end # Defines the test functions, using variables defined in the *_inputs.jl file diff --git a/moment_kinetics/debug_test/runtest_template.jl b/moment_kinetics/debug_test/runtest_template.jl index 6f1cb0b4e..224c57ce7 100644 --- a/moment_kinetics/debug_test/runtest_template.jl +++ b/moment_kinetics/debug_test/runtest_template.jl @@ -12,7 +12,7 @@ Run a test for a single set of parameters # Note 'name' should not be shared by any two tests in this file function run_test(test_input, debug_loop_type, debug_loop_parallel_dims; restart=false) - name = test_input["run_name"] + name = test_input["output"]["run_name"] @testset "$name" begin # Provide some progress info diff --git a/moment_kinetics/debug_test/sound_wave_inputs.jl b/moment_kinetics/debug_test/sound_wave_inputs.jl index 45b8caedc..9f91fa239 100644 --- a/moment_kinetics/debug_test/sound_wave_inputs.jl +++ b/moment_kinetics/debug_test/sound_wave_inputs.jl @@ -1,243 +1,247 @@ test_type = "sound_wave" using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge # default inputs for tests -test_input_finite_difference_1D1V = OptionsDict( - "run_name" => "finite_difference_1D1V", - "composition" => OptionsDict("n_ion_species" => 2, - "n_neutral_species" => 2, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0), - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "charge_exchange_frequency" => 2*π*0.1, - "ionization_frequency" => 0.0, - "timestepping" => OptionsDict("nstep" => 3, - "dt" => 1.e-8, - "nwrite" => 2, - "type" => "SSPRK2", - "split_operators" => false), - "z_ngrid" => 4, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "r_ngrid" => 1, - "r_nelement" => 1, - "vpa_ngrid" => 4, - "vpa_nelement" => 1, - "vpa_L" => 8.0, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vz_ngrid" => 4, - "vz_nelement" => 1, - "vz_L" => 8.0, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference", - "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, - "vr_ngrid" => 1, - "vr_nelement" => 1) +test_input_finite_difference_1D1V = OptionsDict("output" => OptionsDict("run_name" => "finite_difference_1D1V", + "base_directory" => test_output_directory), + "composition" => OptionsDict("n_ion_species" => 2, + "n_neutral_species" => 2, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*π*0.1, + "ionization_frequency" => 0.0), + "timestepping" => OptionsDict("nstep" => 3, + "dt" => 1.e-8, + "nwrite" => 2, + "type" => "SSPRK2", + "split_operators" => false), + "z" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vpa" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vz" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vzeta" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vr" => OptionsDict("ngrid" => 1, + "nelement" => 1), + ) test_input_finite_difference_1D1V_split_1_moment = - merge(test_input_finite_difference_1D1V, - OptionsDict("run_name" => "finite_difference_1D1V_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_finite_difference_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_1D1V_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_finite_difference_1D1V_split_2_moments = - merge(test_input_finite_difference_1D1V_split_1_moment, - OptionsDict("run_name" => "finite_difference_1D1V_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_finite_difference_1D1V_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_1D1V_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_finite_difference_1D1V_split_3_moments = - merge(test_input_finite_difference_1D1V_split_2_moments, - OptionsDict("run_name" => "finite_difference_1D1V_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_finite_difference_1D1V_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_1D1V_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_finite_difference_cx0_1D1V = - merge(test_input_finite_difference_1D1V, - OptionsDict("run_name" => "finite_difference_cx0_1D1V", - "charge_exchange_frequency" => 0.0)) +recursive_merge(test_input_finite_difference_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_1D1V"), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0))) test_input_finite_difference_cx0_1D1V_split_1_moment = - merge(test_input_finite_difference_cx0_1D1V, - OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_finite_difference_cx0_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_finite_difference_cx0_1D1V_split_2_moments = - merge(test_input_finite_difference_cx0_1D1V_split_1_moment, - OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_finite_difference_cx0_1D1V_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_finite_difference_cx0_1D1V_split_3_moments = - merge(test_input_finite_difference_cx0_1D1V_split_2_moments, - OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_finite_difference_cx0_1D1V_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_1D1V_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_finite_difference = - merge(test_input_finite_difference_1D1V, - OptionsDict("run_name" => "finite_difference", - "r_ngrid" => 4, - "r_nelement" => 1, - "r_discretization" => "finite_difference", - "vperp_ngrid" => 4, - "vperp_nelement" => 1, - "vperp_discretization" => "finite_difference", - "vz_ngrid" => 4, - "vz_nelement" => 1, - "vz_discretization" => "finite_difference", - "vr_ngrid" => 4, - "vr_nelement" => 1, - "vr_discretization" => "finite_difference", - "vzeta_ngrid" => 4, - "vzeta_nelement" => 1, - "vzeta_discretization" => "finite_difference")) +recursive_merge(test_input_finite_difference_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference"), + "r" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vr" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vzeta" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + )) test_input_finite_difference_split_1_moment = - merge(test_input_finite_difference, - OptionsDict("run_name" => "finite_difference_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_finite_difference_split_2_moments = - merge(test_input_finite_difference_split_1_moment, - OptionsDict("run_name" => "finite_difference_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_finite_difference_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_finite_difference_split_3_moments = - merge(test_input_finite_difference_split_2_moments, - OptionsDict("run_name" => "finite_difference_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_finite_difference_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_finite_difference_cx0 = - merge(test_input_finite_difference, - OptionsDict("run_name" => "finite_difference_cx0", - "charge_exchange_frequency" => 0.0)) +recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0"), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0))) test_input_finite_difference_cx0_split_1_moment = - merge(test_input_finite_difference_cx0, - OptionsDict("run_name" => "finite_difference_cx0_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_finite_difference_cx0, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_finite_difference_cx0_split_2_moments = - merge(test_input_finite_difference_cx0_split_1_moment, - OptionsDict("run_name" => "finite_difference_cx0_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_finite_difference_cx0_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_finite_difference_cx0_split_3_moments = - merge(test_input_finite_difference_cx0_split_2_moments, - OptionsDict("run_name" => "finite_difference_cx0_split_3_moments", - "evolve_moments_parallel_pressure" => true)) - -test_input_chebyshev = merge(test_input_finite_difference, - OptionsDict("run_name" => "chebyshev_pseudospectral", - "r_discretization" => "chebyshev_pseudospectral", - "r_ngrid" => 3, - "r_nelement" => 1, - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 3, - "z_nelement" => 2, - "vperp_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 3, - "vperp_nelement" => 1, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2, - "vr_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 3, - "vr_nelement" => 1, - "vzeta_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 3, - "vzeta_nelement" => 1)) +recursive_merge(test_input_finite_difference_cx0_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_cx0_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) + +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "r" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vperp" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vr" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "vzeta" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + )) test_input_chebyshev_split_1_moment = - merge(test_input_chebyshev, - OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_chebyshev, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_split_2_moments = - merge(test_input_chebyshev_split_1_moment, - OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_chebyshev_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_split_3_moments = - merge(test_input_chebyshev_split_2_moments, - OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_chebyshev_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_chebyshev_cx0 = - merge(test_input_chebyshev, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0", - "charge_exchange_frequency" => 0.0)) +recursive_merge(test_input_chebyshev, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0"), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0))) test_input_chebyshev_cx0_split_1_moment = - merge(test_input_chebyshev_cx0, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_chebyshev_cx0, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_cx0_split_2_moments = - merge(test_input_chebyshev_cx0_split_1_moment, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_chebyshev_cx0_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_cx0_split_3_moments = - merge(test_input_chebyshev_cx0_split_2_moments, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_chebyshev_cx0_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_chebyshev_1D1V = - merge(test_input_finite_difference_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 3, - "z_nelement" => 2, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2)) +recursive_merge(test_input_finite_difference_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + )) test_input_chebyshev_1D1V_split_1_moment = - merge(test_input_chebyshev_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_chebyshev_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_1D1V_split_2_moments = - merge(test_input_chebyshev_1D1V_split_1_moment, - OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_chebyshev_1D1V_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_1D1V_split_3_moments = - merge(test_input_chebyshev_1D1V_split_2_moments, - OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_3_moments", - "evolve_moments_parallel_pressure" => true, "runtime_plots" => true)) +recursive_merge(test_input_chebyshev_1D1V_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_chebyshev_cx0_1D1V = - merge(test_input_chebyshev_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V", - "charge_exchange_frequency" => 0.0)) +recursive_merge(test_input_chebyshev_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V"), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0))) test_input_chebyshev_cx0_1D1V_split_1_moment = - merge(test_input_chebyshev_cx0_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_1_moment", - "evolve_moments_density" => true)) +recursive_merge(test_input_chebyshev_cx0_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_cx0_1D1V_split_2_moments = - merge(test_input_chebyshev_cx0_1D1V_split_1_moment, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_2_moments", - "evolve_moments_parallel_flow" => true)) +recursive_merge(test_input_chebyshev_cx0_1D1V_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_cx0_1D1V_split_3_moments = - merge(test_input_chebyshev_cx0_1D1V_split_2_moments, - OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_3_moments", - "evolve_moments_parallel_pressure" => true)) +recursive_merge(test_input_chebyshev_cx0_1D1V_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_cx0_1D1V_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) test_input_list = [ test_input_finite_difference, diff --git a/moment_kinetics/debug_test/wall_bc_inputs.jl b/moment_kinetics/debug_test/wall_bc_inputs.jl index 6698d2700..eb1341ccc 100644 --- a/moment_kinetics/debug_test/wall_bc_inputs.jl +++ b/moment_kinetics/debug_test/wall_bc_inputs.jl @@ -1,133 +1,136 @@ test_type = "Wall boundary conditions" using moment_kinetics.type_definitions: OptionsDict -using moment_kinetics.input_structs: merge_dict_of_dicts +using moment_kinetics.utils: recursive_merge # default inputs for tests test_input_finite_difference_1D1V = OptionsDict( - "run_name" => "finite_difference_1D1V", + "output" => OptionsDict("run_name" => "finite_difference_1D1V", + "base_directory" => test_output_directory), "composition" => OptionsDict("n_ion_species" => 2, "n_neutral_species" => 2, "electron_physics" => "boltzmann_electron_response", "T_e" => 1.0, "T_wall" => 1.0), - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "charge_exchange_frequency" => 2.0, - "ionization_frequency" => 2.0, - "constant_ionization_rate" => false, + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "reactions" => OptionsDict("charge_exchange_frequency" => 2.0, + "ionization_frequency" => 2.0), "timestepping" => OptionsDict("nstep" => 3, "dt" => 1.0e-8, "nwrite" => 2, "type" => "SSPRK2", "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 4, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 4, - "vpa_nelement" => 8, - "vpa_L" => 8.0, - "vpa_bc" => "zero", - "vpa_discretization" => "finite_difference", - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vz_ngrid" => 4, - "vz_nelement" => 1, - "vz_L" => 8.0, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference", - "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, - "vr_ngrid" => 1, - "vr_nelement" => 1) + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 4, + "nelement" => 8, + "L" => 8.0, + "bc" => "zero", + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vz" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vzeta" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vr" => OptionsDict("ngrid" => 1, + "nelement" => 1), + ) -test_input_finite_difference_simple_sheath_1D1V = merge_dict_of_dicts( +test_input_finite_difference_simple_sheath_1D1V = recursive_merge( test_input_finite_difference_1D1V, - OptionsDict("run_name" => "finite_difference_simple_sheath_1D1V", + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_simple_sheath_1D1V"), "composition" => OptionsDict("electron_physics" => "boltzmann_electron_response_with_simple_sheath"))) -test_input_finite_difference = merge( +test_input_finite_difference = recursive_merge( test_input_finite_difference_1D1V, - OptionsDict("run_name" => "finite_difference", - "r_ngrid" => 4, - "r_nelement" => 1, - "r_discretization" => "finite_difference", - "vperp_ngrid" => 4, - "vperp_nelement" => 1, - "vperp_discretization" => "finite_difference", - "vz_ngrid" => 4, - "vz_nelement" => 1, - "vz_discretization" => "finite_difference", - "vr_ngrid" => 4, - "vr_nelement" => 1, - "vr_discretization" => "finite_difference", - "vzeta_ngrid" => 4, - "vzeta_nelement" => 1, - "vzeta_discretization" => "finite_difference")) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference"), + "r" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vr" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + "vzeta" => OptionsDict("ngrid" => 4, + "nelement" => 1, + "discretization" => "finite_difference"), + )) -test_input_finite_difference_simple_sheath = merge_dict_of_dicts( +test_input_finite_difference_simple_sheath = recursive_merge( test_input_finite_difference, - OptionsDict("run_name" => "finite_difference_simple_sheath", + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_simple_sheath"), "composition" => OptionsDict("electron_physics" => "boltzmann_electron_response_with_simple_sheath"))) -test_input_chebyshev_1D1V = merge( +test_input_chebyshev_1D1V = recursive_merge( test_input_finite_difference_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 3, - "z_nelement" => 2, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 3, - "vpa_nelement" => 2, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_1D1V"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + )) -test_input_chebyshev_split1_1D1V = merge(test_input_chebyshev_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_split1_1D1V", - "evolve_moments_density" => true)) +test_input_chebyshev_split1_1D1V = recursive_merge(test_input_chebyshev_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split1_1D1V"), + "evolve_moments" => OptionsDict("density" => true))) -test_input_chebyshev_split2_1D1V = merge(test_input_chebyshev_split1_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_split2_1D1V", - "evolve_moments_parallel_flow" => true)) +test_input_chebyshev_split2_1D1V = recursive_merge(test_input_chebyshev_split1_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split2_1D1V"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) -test_input_chebyshev_split3_1D1V = merge(test_input_chebyshev_split2_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_split3_1D1V", - "evolve_moments_parallel_pressure" => true)) +test_input_chebyshev_split3_1D1V = recursive_merge(test_input_chebyshev_split2_1D1V, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split3_1D1V"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) -test_input_chebyshev_simple_sheath_1D1V = merge_dict_of_dicts( +test_input_chebyshev_simple_sheath_1D1V = recursive_merge( test_input_chebyshev_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral_simple_sheath_1D1V", - "composition" => OptionsDict("electron_physics" => "boltzmann_electron_response_with_simple_sheath"))) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_simple_sheath_1D1V"), + "composition" => OptionsDict("electron_physics" => "boltzmann_electron_response_with_simple_sheath"))) -test_input_chebyshev = merge( +test_input_chebyshev = recursive_merge( test_input_chebyshev_1D1V, - OptionsDict("run_name" => "chebyshev_pseudospectral", - "r_discretization" => "chebyshev_pseudospectral", - "r_ngrid" => 3, - "r_nelement" => 1, - "vperp_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 3, - "vperp_nelement" => 1, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 3, - "vz_nelement" => 2, - "vr_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 3, - "vr_nelement" => 1, - "vzeta_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 3, - "vzeta_nelement" => 1)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "r" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "vperp" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 2), + "vr" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + "vzeta" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 3, + "nelement" => 1), + )) -test_input_chebyshev_simple_sheath = merge_dict_of_dicts( +test_input_chebyshev_simple_sheath = recursive_merge( test_input_chebyshev, - OptionsDict("run_name" => "chebyshev_pseudospectral_simple_sheath", + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_simple_sheath"), "composition" => OptionsDict("electron_physics" => "boltzmann_electron_response_with_simple_sheath"))) test_input_list = [ diff --git a/moment_kinetics/ext/file_io_netcdf.jl b/moment_kinetics/ext/file_io_netcdf.jl index bb7a86f2b..fa22f99c3 100644 --- a/moment_kinetics/ext/file_io_netcdf.jl +++ b/moment_kinetics/ext/file_io_netcdf.jl @@ -97,9 +97,17 @@ end function write_single_value!(file_or_group::NCDataset, name, value::Union{Number, AbstractString, AbstractArray{T,N}}, - coords...; parallel_io, n_ion_species=nothing, - n_neutral_species=nothing, description=nothing, - units=nothing) where {T,N} + coords::Union{coordinate,NamedTuple}...; parallel_io, + description=nothing, units=nothing) where {T,N} + + if any(c.n < 0 for c ∈ coords) + error("Got a negative `n` in $coords") + end + if any(c.n == 0 for c ∈ coords) + # No data to write + return nothing + end + if description !== nothing || units !== nothing attributes = Dict{String, Any}() if description !== nothing @@ -112,11 +120,6 @@ function write_single_value!(file_or_group::NCDataset, name, attributes = () end - if n_ion_species !== nothing && n_neutral_species != nothing - error("Cannot have both ion-species and neutral species dimensions." * - "Got n_ion_species=$n_ion_species, n_neutral_species=$n_neutral_species") - end - if isa(value, Number) || isa(value, AbstractString) coords !== () && error("cannot pass coordinates with a scalar") @@ -134,26 +137,6 @@ function write_single_value!(file_or_group::NCDataset, name, maybe_create_netcdf_dim(file_or_group, c) end dims = Tuple(c.name for c in coords) - - if n_ion_species !== nothing - if n_ion_species < 0 - error("n_ion_species must be non-negative, got $n_ion_species") - elseif n_ion_species == 0 - # No data to write - return nothing - end - maybe_create_netcdf_dim(file_or_group, "ion_species", n_ion_species) - dims = tuple(dims..., "ion_species") - elseif n_neutral_species !== nothing - if n_neutral_species < 0 - error("n_neutral_species must be non-negative, got $n_neutral_species") - elseif n_neutral_species == 0 - # No data to write - return nothing - end - maybe_create_netcdf_dim(file_or_group, "neutral_species", n_neutral_species) - dims = tuple(dims..., "neutral_species") - end end if isa(value, Bool) # As a hack, write bools to NetCDF as Char, as NetCDF does not support bools (?), @@ -169,50 +152,20 @@ function write_single_value!(file_or_group::NCDataset, name, end function create_dynamic_variable!(file_or_group::NCDataset, name, type, - coords::coordinate...; parallel_io, - n_ion_species=nothing, n_neutral_species=nothing, - diagnostic_var_size=nothing, description=nothing, - units=nothing) - - if n_ion_species !== nothing && n_neutral_species !== nothing - error("Variable should not contain both ion and neutral species dimensions. " - * "Got n_ion_species=$n_ion_species and " - * "n_neutral_species=$n_neutral_species") - end - if diagnostic_var_size !== nothing && n_ion_species !== nothing - error("Diagnostic variable should not contain both ion species dimension. Got " - * "diagnostic_var_size=$diagnostic_var_size and " - * "n_ion_species=$n_ion_species") + coords::Union{coordinate,NamedTuple}...; parallel_io, + description=nothing, units=nothing) + + if any(c.n < 0 for c ∈ coords) + error("Got a negative `n` in $coords") end - if diagnostic_var_size !== nothing && n_neutral_species !== nothing - error("Diagnostic variable should not contain both neutral species dimension. " - * "Got diagnostic_var_size=$diagnostic_var_size and " - * "n_neutral_species=$n_neutral_species") + if any(c.n == 0 for c ∈ coords) + # No data to write + return nothing end # Create time dimension if necessary maybe_create_netcdf_dim(file_or_group, "time", Inf) - # Create species dimension if necessary - if n_ion_species !== nothing - if n_ion_species < 0 - error("n_ion_species must be non-negative, got $n_ion_species") - elseif n_ion_species == 0 - # No data to write - return nothing - end - maybe_create_netcdf_dim(file_or_group, "ion_species", n_ion_species) - end - if n_neutral_species !== nothing - if n_neutral_species < 0 - error("n_neutral_species must be non-negative, got $n_neutral_species") - elseif n_neutral_species == 0 - # No data to write - return nothing - end - maybe_create_netcdf_dim(file_or_group, "neutral_species", n_neutral_species) - end - # Create other dimensions if necessary for c ∈ coords maybe_create_netcdf_dim(file_or_group, c) @@ -221,23 +174,7 @@ function create_dynamic_variable!(file_or_group::NCDataset, name, type, # create the variable so it can be expanded indefinitely (up to the largest unsigned # integer in size) in the time dimension coord_dims = Tuple(c.name for c ∈ coords) - if diagnostic_var_size !== nothing - if isa(diagnostic_var_size, Number) - # Make diagnostic_var_size a Tuple - diagnostic_var_size = (diagnostic_var_size,) - end - for (i,dim_size) ∈ enumerate(diagnostic_var_size) - maybe_create_netcdf_dim(file_or_group, "$name$i", dim_size) - end - fixed_dims = Tuple("$name$i" for i ∈ 1:length(diagnostic_var_size)) - elseif n_ion_species !== nothing - fixed_dims = tuple(coord_dims..., "ion_species") - elseif n_neutral_species !== nothing - fixed_dims = tuple(coord_dims..., "neutral_species") - else - fixed_dims = coord_dims - end - dims = tuple(fixed_dims..., "time") + dims = tuple(coord_dims..., "time") # create the variable so it can be expanded indefinitely (up to the largest unsigned # integer in size) in the time dimension diff --git a/moment_kinetics/ext/manufactured_solns_ext.jl b/moment_kinetics/ext/manufactured_solns_ext.jl index e65c964db..fcfeaca74 100644 --- a/moment_kinetics/ext/manufactured_solns_ext.jl +++ b/moment_kinetics/ext/manufactured_solns_ext.jl @@ -605,8 +605,8 @@ using IfElse ExBgeofac = 0.5*rhostar*Bzeta*jacobian/Bmag^2 #exceptions for cases with missing terms if composition.n_neutral_species > 0 - cx_frequency = collisions.charge_exchange - ionization_frequency = collisions.ionization + cx_frequency = collisions.reactions.charge_exchange_frequency + ionization_frequency = collisions.reactions.ionization_frequency else cx_frequency = 0.0 ionization_frequency = 0.0 diff --git a/moment_kinetics/src/calculus.jl b/moment_kinetics/src/calculus.jl index 2b473a232..47036e077 100644 --- a/moment_kinetics/src/calculus.jl +++ b/moment_kinetics/src/calculus.jl @@ -64,7 +64,7 @@ function derivative!(df, f, coord, spectral::Union{null_spatial_dimension_info, return nothing end -function second_derivative!(d2f, f, coord, spectral; handle_periodic=true) +function second_derivative!(d2f, f, coord, spectral) # computes d^2f / d(coord)^2 # For spectral element methods, calculate second derivative by applying first # derivative twice, with special treatment for element boundaries @@ -124,14 +124,22 @@ function second_derivative!(d2f, f, coord, spectral; handle_periodic=true) error("Distributed memory MPI not yet supported here") end d2f[1] -= C * coord.scratch2_2d[end,end] - d2f[end] += C * coord.scratch2_2d[1,1] + # With the first derivative from the opposite end of the grid, d2f[end] here + # should be equal to d2f[1] up to rounding errors... + @boundscheck isapprox(d2f[end] + C * coord.scratch2_2d[1,1], d2f[1]; atol=1.0e-14) + # ...but because arithmetic operations were in a different order, there may be + # rounding errors, so set the two ends exactly equal to ensure consistency for the + # rest of the code - we assume that duplicate versions of the 'same point' on + # element boundaries (due to periodic bc or distributed-MPI block boundaries) are + # exactly equal. + d2f[end] = d2f[1] else error("Unsupported bc '$(coord.bc)'") end return nothing end -function laplacian_derivative!(d2f, f, coord, spectral; handle_periodic=true) +function laplacian_derivative!(d2f, f, coord, spectral) # computes (1/coord) d / coord ( coord d f / d(coord)) for vperp coordinate # For spectral element methods, calculate second derivative by applying first # derivative twice, with special treatment for element boundaries @@ -207,29 +215,30 @@ is an input. """ function mass_matrix_solve! end -function second_derivative!(d2f, f, coord, spectral::weak_discretization_info; handle_periodic=true) +function second_derivative!(d2f, f, coord, spectral::weak_discretization_info) # obtain the RHS of numerical weak-form of the equation # g = d^2 f / d coord^2, which is # M * g = K * f, with M the mass matrix and K an appropriate stiffness matrix # by multiplying by basis functions and integrating by parts mul!(coord.scratch3, spectral.K_matrix, f) - if handle_periodic && coord.bc == "periodic" - if coord.nrank > 1 - error("second_derivative!() cannot handle periodic boundaries for a " - * "distributed coordinate") - end - - coord.scratch3[1] = 0.5 * (coord.scratch3[1] + coord.scratch3[end]) - coord.scratch3[end] = coord.scratch3[1] - end - # solve weak form matrix problem M * g = K * f to obtain g = d^2 f / d coord^2 if coord.nrank > 1 error("mass_matrix_solve!() does not support a " * "distributed coordinate") end mass_matrix_solve!(d2f, coord.scratch3, spectral) + + if coord.bc == "periodic" + # d2f[end] here should be equal to d2f[1] up to rounding errors... + @boundscheck isapprox(d2f[end], d2f[1]; atol=1.0e-14) + # ...but in the matrix operations arithmetic operations are not necessarily in + # exactly the same order, there may be rounding errors, so set the two ends + # exactly equal to ensure consistency for the rest of the code - we assume that + # duplicate versions of the 'same point' on element boundaries (due to periodic bc + # or distributed-MPI block boundaries) are exactly equal. + d2f[end] = d2f[1] + end end function laplacian_derivative!(d2f, f, coord, spectral::weak_discretization_info) diff --git a/moment_kinetics/src/communication.jl b/moment_kinetics/src/communication.jl index f8fa46fff..394446a4a 100644 --- a/moment_kinetics/src/communication.jl +++ b/moment_kinetics/src/communication.jl @@ -544,6 +544,9 @@ end end """ +Type used to declare a shared-memory array. When debugging is not active `MPISharedArray` +is just an alias for `Array`, but when `@debug_shared_array` is activated, it is instead +defined as an alias for `DebugMPISharedArray`. """ const MPISharedArray = @debug_shared_array_ifelse(DebugMPISharedArray, Array) diff --git a/moment_kinetics/src/continuity.jl b/moment_kinetics/src/continuity.jl index 26e9e1314..6a7c328e8 100644 --- a/moment_kinetics/src/continuity.jl +++ b/moment_kinetics/src/continuity.jl @@ -30,11 +30,13 @@ function continuity_equation!(dens_out, fvec_in, moments, composition, dt, spect end end - if ion_source_settings.active - source_amplitude = moments.ion.external_source_density_amplitude - @loop_s_r_z is ir iz begin - dens_out[iz,ir,is] += - dt * source_amplitude[iz,ir] + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_amplitude = moments.ion.external_source_density_amplitude[:, :, index] + @loop_s_r_z is ir iz begin + dens_out[iz,ir,is] += + dt * source_amplitude[iz,ir] + end end end @@ -71,11 +73,13 @@ function neutral_continuity_equation!(dens_out, fvec_in, moments, composition, d end end - if neutral_source_settings.active - source_amplitude = moments.neutral.external_source_density_amplitude - @loop_s_r_z is ir iz begin - dens_out[iz,ir,is] += - dt * source_amplitude[iz,ir] + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_amplitude = moments.neutral.external_source_density_amplitude[:, :, index] + @loop_s_r_z is ir iz begin + dens_out[iz,ir,is] += + dt * source_amplitude[iz,ir] + end end end diff --git a/moment_kinetics/src/coordinates.jl b/moment_kinetics/src/coordinates.jl index 16e7d8848..7ab861537 100644 --- a/moment_kinetics/src/coordinates.jl +++ b/moment_kinetics/src/coordinates.jl @@ -7,7 +7,7 @@ export equally_spaced_grid export set_element_boundaries using LinearAlgebra -using ..type_definitions: mk_float, mk_int +using ..type_definitions: mk_float, mk_int, OptionsDict using ..array_allocation: allocate_float, allocate_shared_float, allocate_int using ..calculus: derivative! using ..chebyshev: scaled_chebyshev_grid, scaled_chebyshev_radau_grid, setup_chebyshev_pseudospectral @@ -16,7 +16,7 @@ using ..finite_differences: finite_difference_info using ..gauss_legendre: scaled_gauss_legendre_lobatto_grid, scaled_gauss_legendre_radau_grid, setup_gausslegendre_pseudospectral using ..input_structs using ..quadrature: composite_simpson_weights -using ..input_structs: advection_input +using ..input_structs using ..moment_kinetics_structs: null_spatial_dimension_info, null_velocity_dimension_info using MPI @@ -59,8 +59,8 @@ struct coordinate{T <: AbstractVector{mk_float},Tbparams} igrid_full::Array{mk_int,2} # discretization option for the grid discretization::String - # if the discretization is finite differences, fd_option provides the precise scheme - fd_option::String + # if the discretization is finite differences, finite_difference_option provides the precise scheme + finite_difference_option::String # if the discretization is chebyshev_pseudospectral, cheb_option chooses whether to use FFT or differentiation matrices for d / d coord cheb_option::String # bc is the boundary condition option for this coordinate @@ -133,36 +133,148 @@ struct coordinate{T <: AbstractVector{mk_float},Tbparams} end """ -create arrays associated with a given coordinate, -setup the coordinate grid, and populate the coordinate structure -containing all of this information + get_coordinate_input(input_dict, name) + +Read the input for coordinate `name` from `input_dict`, setting defaults, etc. +""" +function get_coordinate_input(input_dict, name; ignore_MPI=false) + if name == "z" + default_bc = "wall" + elseif name == "r" + default_bc = "periodic" + elseif name == "vperp" + default_bc = "default" + else + default_bc = "zero" + end + coord_input_dict = set_defaults_and_check_section!( + input_dict, name; + # ngrid is number of grid points per element + ngrid=1, + # nelement is the number of elements in total + nelement=1, + # nelement_local is the number of elements on each process + nelement_local=-1, + # L is the box length in this coordinate + L=1.0, + # discretization option for the coordinate grid supported options are + # "chebyshev_pseudospectral", "gausslegendre_pseudospectral" and + # "finite_difference" + discretization="chebyshev_pseudospectral", + # option for implementation of chebyshev discretization: "FFT" or "matrix" + cheb_option="FFT", + # finite_difference_option determines the finite difference scheme to be used + # supported options are "third_order_upwind", "second_order_upwind" and + # "first_order_upwind" + finite_difference_option="third_order_upwind", + element_spacing_option="uniform", + # which boundary condition to use + bc=default_bc, + # determine the option used for the advection speed in z supported options are + # "constant" and "oscillating", in addition to the "default" option which uses + # d(coord)/dt from the moment-kinetic equations as the advection speed + advection_option="default", + # constant advection speed to use with advection_option = "constant" + advection_speed=0.0, + # for advection_option = "oscillating", advection speed is of form + # speed = advection_speed*(1 + advection_oscillation_amplitude*sinpi(advection_oscillation_frequency*t)) + advection_oscillation_amplitude=1.0, + advection_oscillation_frequency=1.0, + ) + if coord_input_dict["nelement_local"] == -1 || ignore_MPI + coord_input_dict["nelement_local"] = coord_input_dict["nelement"] + end + if name == "vperp" && coord_input_dict["bc"] == "default" + if coord_input_dict["ngrid"] == 1 && coord_input_dict["nelement"] == 1 + # 1V simulation, so boundary condition should be "none" + coord_input_dict["bc"] = "none" + else + # 2V simulation, so boundary condition should be "zero" + coord_input_dict["bc"] = "zero" + end + end + # Make a copy so we do not add "name" to the global input_dict + coord_input_dict = copy(coord_input_dict) + coord_input_dict["name"] = name + coord_input = Dict_to_NamedTuple(coord_input_dict) + + return coord_input +end + +""" + define_coordinate(input_dict, name; parallel_io::Bool=false, + run_directory=nothing, ignore_MPI=false, + collision_operator_dim::Bool=true) + define_coordinate(coord_input::NamedTuple; parallel_io::Bool=false, + run_directory=nothing, ignore_MPI=false, + collision_operator_dim::Bool=true, irank=0, nrank=1, + comm=MPI.COMM_NULL) + +Create arrays associated with a given coordinate, setup the coordinate grid, and populate +the coordinate structure containing all of this information. + +When `input_dict` is passed, any missing settings will be set with default values. + +When `coord_input` is passed, it should be a `NamedTuple` as generated by +[`get_coordinate_input`](@ref), which contains a field for every coordinate input option. """ -function define_coordinate(input, input_dict, parallel_io::Bool=false; +function define_coordinate end + +function define_coordinate(input_dict, name; kwargs...) + + coord_input = get_coordinate_input(input_dict, name) + + return define_coordinate(coord_input; kwargs...) +end + +function define_coordinate(coord_input::NamedTuple; parallel_io::Bool=false, run_directory=nothing, ignore_MPI=false, - collision_operator_dim::Bool=true) + collision_operator_dim::Bool=true, irank=0, nrank=1, + comm=MPI.COMM_NULL) + + if coord_input.name ∉ ("r", "z") + if irank != 0 || nrank != 1 || comm != MPI.COMM_NULL + if comm == MPI.COMM_NULL + comm_message = "comm is MPI.COMM_NULL" + else + comm_message = "comm is not MPI.COMM_NULL" + end + error("Distributed-memory MPI is not supported for coordinate " + * "$(coord_input.name), but got irank=$irank, nrank=$nrank and " + * "$comm_message") + end + end + # total number of grid points is ngrid for the first element # plus ngrid-1 unique points for each additional element due # to the repetition of a point at the element boundary - n_global = (input.ngrid-1)*input.nelement_global + 1 + n_global = (coord_input.ngrid-1)*coord_input.nelement + 1 # local number of points on this process - n_local = (input.ngrid-1)*input.nelement_local + 1 + n_local = (coord_input.ngrid-1)*coord_input.nelement_local + 1 # obtain index mapping from full (local) grid to the # grid within each element (igrid, ielement) - igrid, ielement = full_to_elemental_grid_map(input.ngrid, - input.nelement_local, n_local) + igrid, ielement = full_to_elemental_grid_map(coord_input.ngrid, + coord_input.nelement_local, n_local) # obtain (local) index mapping from the grid within each element # to the full grid - imin, imax, igrid_full = elemental_to_full_grid_map(input.ngrid, input.nelement_local) + imin, imax, igrid_full = elemental_to_full_grid_map(coord_input.ngrid, + coord_input.nelement_local) # initialise the data used to construct the grid # boundaries for each element - element_boundaries = set_element_boundaries(input.nelement_global, input.L, input.element_spacing_option, input.name) + element_boundaries = set_element_boundaries(coord_input.nelement, + coord_input.L, + coord_input.element_spacing_option, + coord_input.name) # shift and scale factors for each local element - element_scale, element_shift = set_element_scale_and_shift(input.nelement_global, input.nelement_local, input.irank, element_boundaries) + element_scale, element_shift = + set_element_scale_and_shift(coord_input.nelement, coord_input.nelement_local, + irank, element_boundaries) # initialize the grid and the integration weights associated with the grid # also obtain the Chebyshev theta grid and spacing if chosen as discretization option - grid, wgts, uniform_grid, radau_first_element = init_grid(input.ngrid, - input.nelement_local, n_global, n_local, input.irank, input.L, element_scale, - element_shift, imin, imax, igrid, input.discretization, input.name) + grid, wgts, uniform_grid, radau_first_element = + init_grid(coord_input.ngrid, coord_input.nelement_local, n_global, n_local, + irank, coord_input.L, element_scale, element_shift, imin, imax, igrid, + coord_input.discretization, coord_input.name) # calculate the widths of the cells between neighboring grid points cell_width = grid_spacing(grid, n_local) # Get some parameters that may be used for the boundary condition @@ -183,7 +295,7 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; end # duniform_dgrid is the local derivative of the uniform grid with respect to # the coordinate grid - duniform_dgrid = allocate_float(input.ngrid, input.nelement_local) + duniform_dgrid = allocate_float(coord_input.ngrid, coord_input.nelement_local) # scratch is an array used for intermediate calculations requiring n entries scratch = allocate_float(n_local) if ignore_MPI @@ -203,9 +315,12 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; _block_synchronize() end # scratch_2d is an array used for intermediate calculations requiring ngrid x nelement entries - scratch_2d = allocate_float(input.ngrid, input.nelement_local) + scratch_2d = allocate_float(coord_input.ngrid, coord_input.nelement_local) # struct containing the advection speed options/inputs for this coordinate - advection = input.advection + advection = advection_input(coord_input.advection_option, + coord_input.advection_speed, + coord_input.advection_oscillation_frequency, + coord_input.advection_oscillation_amplitude) # buffers for cyclic communication of boundary points # each chain of elements has only two external (off-rank) # endpoints, so only two pieces of information must be shared @@ -216,23 +331,24 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; # No parallel io, just write everything local_io_range = 1:n_local global_io_range = 1:n_local - elseif input.irank == input.nrank-1 + elseif irank == nrank-1 # Include endpoint on final block local_io_range = 1:n_local - global_io_range = input.irank*(n_local-1)+1:n_global + global_io_range = irank*(n_local-1)+1:n_global else # Skip final point, because it is shared with the next block # Choose to skip final point in each block so all blocks (except the final one) # write a 'chunk' of the same size to the output file. This makes it simple to # align HDF5 'chunks' with the data being written local_io_range = 1 : n_local-1 - global_io_range = input.irank*(n_local-1)+1 : (input.irank+1)*(n_local-1) + global_io_range = irank*(n_local-1)+1 : (irank+1)*(n_local-1) end # Precompute some values for Lagrange polynomial evaluation - other_nodes = allocate_float(input.ngrid-1, input.ngrid, input.nelement_local) - one_over_denominator = allocate_float(input.ngrid, input.nelement_local) - for ielement ∈ 1:input.nelement_local + other_nodes = allocate_float(coord_input.ngrid-1, coord_input.ngrid, + coord_input.nelement_local) + one_over_denominator = allocate_float(coord_input.ngrid, coord_input.nelement_local) + for ielement ∈ 1:coord_input.nelement_local if ielement == 1 this_imin = imin[ielement] else @@ -240,11 +356,11 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; end this_imax = imax[ielement] this_grid = grid[this_imin:this_imax] - for j ∈ 1:input.ngrid + for j ∈ 1:coord_input.ngrid @views other_nodes[1:j-1,j,ielement] .= this_grid[1:j-1] @views other_nodes[j:end,j,ielement] .= this_grid[j+1:end] - if input.ngrid == 1 + if coord_input.ngrid == 1 one_over_denominator[j,ielement] = 1.0 else one_over_denominator[j,ielement] = 1.0 / prod(this_grid[j] - n for n ∈ @view other_nodes[:,j,ielement]) @@ -252,16 +368,17 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; end end - coord = coordinate(input.name, n_global, n_local, input.ngrid, - input.nelement_global, input.nelement_local, input.nrank, input.irank, input.L, grid, - cell_width, igrid, ielement, imin, imax, igrid_full, input.discretization, input.fd_option, input.cheb_option, - input.bc, boundary_parameters, wgts, uniform_grid, duniform_dgrid, scratch, + coord = coordinate(coord_input.name, n_global, n_local, coord_input.ngrid, + coord_input.nelement, coord_input.nelement_local, nrank, irank, coord_input.L, + grid, cell_width, igrid, ielement, imin, imax, igrid_full, + coord_input.discretization, coord_input.finite_difference_option, + coord_input.cheb_option, coord_input.bc, boundary_parameters, wgts, uniform_grid, + duniform_dgrid, scratch, copy(scratch), copy(scratch), copy(scratch), copy(scratch), copy(scratch), copy(scratch), copy(scratch), copy(scratch), - copy(scratch), copy(scratch), copy(scratch), scratch_shared, scratch_shared2, - scratch_2d, copy(scratch_2d), advection, send_buffer, receive_buffer, input.comm, - local_io_range, global_io_range, element_scale, element_shift, - input.element_spacing_option, element_boundaries, radau_first_element, - other_nodes, one_over_denominator) + scratch_shared, scratch_shared2, scratch_2d, copy(scratch_2d), advection, + send_buffer, receive_buffer, comm, local_io_range, global_io_range, + element_scale, element_shift, coord_input.element_spacing_option, + element_boundaries, radau_first_element, other_nodes, one_over_denominator) if coord.n == 1 && occursin("v", coord.name) spectral = null_velocity_dimension_info() @@ -269,14 +386,14 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; elseif coord.n == 1 spectral = null_spatial_dimension_info() coord.duniform_dgrid .= 1.0 - elseif input.discretization == "chebyshev_pseudospectral" + elseif coord_input.discretization == "chebyshev_pseudospectral" # create arrays needed for explicit Chebyshev pseudospectral treatment in this # coordinate and create the plans for the forward and backward fast Chebyshev # transforms spectral = setup_chebyshev_pseudospectral(coord, run_directory; ignore_MPI=ignore_MPI) # obtain the local derivatives of the uniform grid with respect to the used grid derivative!(coord.duniform_dgrid, coord.uniform_grid, coord, spectral) - elseif input.discretization == "gausslegendre_pseudospectral" + elseif coord_input.discretization == "gausslegendre_pseudospectral" # create arrays needed for explicit GaussLegendre pseudospectral treatment in this # coordinate and create the matrices for differentiation spectral = setup_gausslegendre_pseudospectral(coord, collision_operator_dim=collision_operator_dim) @@ -292,6 +409,36 @@ function define_coordinate(input, input_dict, parallel_io::Bool=false; return coord, spectral end +""" + define_test_coordinate(input_dict::AbstractDict; kwargs...) + define_test_coordinate(name; collision_operator_dim=true, kwargs...) + +Wrapper for `define_coordinate()` to make creating a coordinate for tests slightly less +verbose. + +When passing `input_dict`, it must contain a "name" field, and can contain other settings +- "ngrid", "nelement", etc. Options other than "name" will be set using defaults if they +are not passed. `kwargs` are the keyword arguments for [`define_coordinate`](@ref). + +The second form allows the coordinate input options to be passed as keyword arguments. For +this form, apart from `collision_operator_dim`, the keyword arguments of +[`define_coordinate`](@ref) cannot be passed, and `ignore_MPI=true` is always set, as this +is most often useful for tests. +""" +function define_test_coordinate end +function define_test_coordinate(input_dict::AbstractDict; kwargs...) + input_dict = deepcopy(input_dict) + name = pop!(input_dict, "name") + return define_coordinate(OptionsDict(name => input_dict), name; kwargs...) +end +function define_test_coordinate(name; collision_operator_dim=true, kwargs...) + coord_input_dict = OptionsDict(String(k) => v for (k,v) in kwargs) + coord_input_dict["name"] = name + return define_test_coordinate(coord_input_dict; + collision_operator_dim=collision_operator_dim, + ignore_MPI=true) +end + function set_element_boundaries(nelement_global, L, element_spacing_option, coord_name) # set global element boundaries between [-L/2,L/2] element_boundaries = allocate_float(nelement_global+1) diff --git a/moment_kinetics/src/electron_fluid_equations.jl b/moment_kinetics/src/electron_fluid_equations.jl index 395a94f4c..3b661975a 100644 --- a/moment_kinetics/src/electron_fluid_equations.jl +++ b/moment_kinetics/src/electron_fluid_equations.jl @@ -52,7 +52,7 @@ end """ use charge conservation equation to solve for the electron parallel flow density: d/dz(sum_i n_i upar_i - n_e upar_e) = 0 - ==> [sum_i n_i upar_i](z) - [sum_i n_i upar_i](zbound) = [n_e upar_e](z) - [n_e upar_e](zbound) + ==> {sum_i n_i upar_i}(z) - {sum_i n_i upar_i}(zbound) = {n_e upar_e}(z) - {n_e upar_e}(zbound) inputs: upar_e = should contain updated electron parallel flow at boundaries in zed updated = flag indicating whether the electron parallel flow is already updated @@ -111,6 +111,11 @@ function calculate_electron_upar_from_charge_conservation!(upar_e, updated, dens # convert from parallel particle flux to parallel particle density upar_e[iz,ir] /= dens_e[iz,ir] end + else + begin_r_z_region() + @loop_r_z ir iz begin + upar_e[iz,ir] = upar_i[iz,ir,1] + end end updated[] = true end @@ -137,8 +142,9 @@ function calculate_electron_moments!(scratch, pdf, moments, composition, collisi update_electron_vth_temperature!(moments, scratch.electron_ppar, scratch.electron_density, composition) calculate_electron_qpar!(moments.electron, pdf.electron, scratch.electron_ppar, - scratch.electron_upar, scratch.upar, collisions.nu_ei, - composition.me_over_mi, composition.electron_physics, vpa) + scratch.electron_upar, scratch.upar, + collisions.electron_fluid.nu_ei, composition.me_over_mi, + composition.electron_physics, vpa) if composition.electron_physics == braginskii_fluid electron_fluid_qpar_boundary_condition!(scratch.electron_ppar, scratch.electron_upar, @@ -170,7 +176,7 @@ function electron_energy_equation!(ppar_out, ppar_in, electron_density, electron begin_r_z_region() # define some abbreviated variables for convenient use in rest of function me_over_mi = composition.me_over_mi - nu_ei = collisions.nu_ei + nu_ei = collisions.electron_fluid.nu_ei T_in = moments.temp # calculate contribution to rhs of energy equation (formulated in terms of pressure) # arising from derivatives of ppar, qpar and upar @@ -204,34 +210,39 @@ function electron_energy_equation!(ppar_out, ppar_in, electron_density, electron end end # add in contributions due to charge exchange/ionization collisions + charge_exchange_electron = collisions.reactions.electron_charge_exchange_frequency + ionization_electron = collisions.reactions.electron_ionization_frequency + ionization_energy = collisions.reactions.ionization_energy if composition.n_neutral_species > 0 - if abs(collisions.charge_exchange_electron) > 0.0 + if abs(charge_exchange_electron) > 0.0 @loop_sn_r_z isn ir iz begin ppar_out[iz,ir] += - dt * 2.0 * me_over_mi * collisions.charge_exchange_electron * ( + dt * 2.0 * me_over_mi * charge_exchange_electron * ( 2*(pz_neutral[iz,ir,isn] - density_neutral[iz,ir,isn]*ppar_in[iz,ir]/electron_density[iz,ir]) + (2/3)*density_neutral[iz,ir,isn] * (uz_neutral[iz,ir,isn] - electron_upar[iz,ir])^2) end end - if abs(collisions.ionization_electron) > 0.0 + if abs(ionization_electron) > 0.0 @loop_sn_r_z isn ir iz begin ppar_out[iz,ir] += - dt * 2.0 * collisions.ionization_electron * density_neutral[iz,ir,isn] * ( + dt * 2.0 * ionization_electron * density_neutral[iz,ir,isn] * ( ppar_in[iz,ir] / electron_density[iz,ir] - - collisions.ionization_energy) + ionization_energy) end end end - if electron_source_settings.active - pressure_source_amplitude = moments.external_source_pressure_amplitude - density_source_amplitude = moments.external_source_density_amplitude - @loop_r_z ir iz begin - ppar_out[iz,ir] += dt * (2.0 * pressure_source_amplitude[iz,ir] - - T_in[iz,ir] * density_source_amplitude[iz,ir]) / - electron_density[iz,ir] + for index ∈ eachindex(electron_source_settings) + if electron_source_settings[index].active + @views pressure_source_amplitude = moments.external_source_pressure_amplitude[:, :, index] + @views density_source_amplitude = moments.external_source_density_amplitude[:, :, index] + @loop_r_z ir iz begin + ppar_out[iz,ir] += dt * (2.0 * pressure_source_amplitude[iz,ir] + - T_in[iz,ir] * density_source_amplitude[iz,ir]) / + electron_density[iz,ir] + end end end @@ -244,7 +255,7 @@ function electron_energy_equation!(ppar_out, ppar_in, electron_density, electron begin_r_z_region() # define some abbreviated variables for convenient use in rest of function me_over_mi = composition.me_over_mi - nu_ei = collisions.nu_ei + nu_ei = collisions.electron_fluid.nu_ei # calculate contribution to rhs of energy equation (formulated in terms of pressure) # arising from derivatives of ppar, qpar and upar @loop_r_z ir iz begin @@ -280,36 +291,41 @@ function electron_energy_equation!(ppar_out, ppar_in, electron_density, electron end # add in contributions due to charge exchange/ionization collisions if composition.n_neutral_species > 0 - if abs(collisions.charge_exchange_electron) > 0.0 + charge_exchange_electron = collisions.reactions.electron_charge_exchange_frequency + ionization_electron = collisions.reactions.electron_ionization_frequency + ionization_energy = collisions.reactions.ionization_energy + if abs(charge_exchange_electron) > 0.0 @loop_sn_r_z isn ir iz begin ppar_out[iz,ir] += - dt * me_over_mi * collisions.charge_exchange_electron * ( + dt * me_over_mi * charge_exchange_electron * ( 2*(electron_density[iz,ir]*pz_neutral[iz,ir,isn] - density_neutral[iz,ir,isn]*ppar_in[iz,ir]) + (2/3)*electron_density[iz,ir]*density_neutral[iz,ir,isn] * (uz_neutral[iz,ir,isn] - electron_upar[iz,ir])^2) end end - if abs(collisions.ionization_electron) > 0.0 + if abs(ionization_electron) > 0.0 # @loop_s_r_z is ir iz begin # ppar_out[iz,ir] += - # dt * collisions.ionization_electron * density_neutral[iz,ir,is] * ( + # dt * ionization_electron * density_neutral[iz,ir,is] * ( # ppar_in[iz,ir] - - # (2/3)*electron_density[iz,ir] * collisions.ionization_energy) + # (2/3)*electron_density[iz,ir] * ionization_energy) # end @loop_sn_r_z isn ir iz begin ppar_out[iz,ir] += - dt * collisions.ionization_electron * density_neutral[iz,ir,isn] * ( + dt * ionization_electron * density_neutral[iz,ir,isn] * ( ppar_in[iz,ir] - - electron_density[iz,ir] * collisions.ionization_energy) + electron_density[iz,ir] * ionization_energy) end end end - if electron_source_settings.active - source_amplitude = moments.external_source_pressure_amplitude - @loop_r_z ir iz begin - ppar_out[iz,ir] += dt * source_amplitude[iz,ir] + for index ∈ eachindex(electron_source_settings) + if electron_source_settings[index].active + @views source_amplitude = moments.external_source_pressure_amplitude[:, :, index] + @loop_r_z ir iz begin + ppar_out[iz,ir] += dt * source_amplitude[iz,ir] + end end end end @@ -381,7 +397,7 @@ function electron_braginskii_conduction!(ppar_out::AbstractVector{mk_float}, z) electron_moments.qpar_updated[] = false calculate_electron_qpar!(electron_moments, nothing, ppar_in, upar_e, upar_i, - collisions.nu_ei, composition.me_over_mi, + collisions.electron_fluid.nu_ei, composition.me_over_mi, composition.electron_physics, nothing) electron_fluid_qpar_boundary_condition!(ppar_in, upar_e, dens, electron_moments, z) derivative_z!(dqpar_dz, qpar, buffer_r_1, buffer_r_2, buffer_r_3, buffer_r_4, diff --git a/moment_kinetics/src/electron_kinetic_equation.jl b/moment_kinetics/src/electron_kinetic_equation.jl index fe1aeeb1e..6582e4ea0 100644 --- a/moment_kinetics/src/electron_kinetic_equation.jl +++ b/moment_kinetics/src/electron_kinetic_equation.jl @@ -23,7 +23,7 @@ using ..electron_fluid_equations: electron_energy_equation!, electron_energy_res using ..electron_z_advection: electron_z_advection!, update_electron_speed_z! using ..electron_vpa_advection: electron_vpa_advection!, update_electron_speed_vpa! using ..em_fields: update_phi! -using ..external_sources: external_electron_source! +using ..external_sources: total_external_electron_sources! using ..file_io: get_electron_io_info, write_electron_state, finish_electron_io using ..krook_collisions: electron_krook_collisions! using ..moment_constraints: hard_force_moment_constraints!, @@ -770,7 +770,8 @@ function implicit_electron_advance!(fvec_out, fvec_in, pdf, scratch_electron, mo calculate_electron_parallel_friction_force!( moments.electron.parallel_friction, fvec_out.electron_density, fvec_out.electron_upar, fvec_out.upar, moments.electron.dT_dz, - composition.me_over_mi, collisions.nu_ei, composition.electron_physics) + composition.me_over_mi, collisions.electron_fluid.nu_ei, + composition.electron_physics) # Solve for EM fields now that electrons are updated. update_phi!(fields, fvec_out, vperp, z, r, composition, collisions, moments, @@ -1819,12 +1820,11 @@ function electron_kinetic_equation_euler_update!(fvec_out, fvec_in, moments, z, vperp, vpa, dt) end - if external_source_settings.electron.active - external_electron_source!(fvec_out.pdf_electron, fvec_in.pdf_electron, - moments.electron.dens, moments.electron.upar, moments, - composition, external_source_settings.electron, vperp, - vpa, dt) - end + total_external_electron_sources!(fvec_out.pdf_electron, fvec_in.pdf_electron, + moments.electron.dens, moments.electron.upar, moments, + composition, external_source_settings.electron, vperp, + vpa, dt) + if evolve_ppar electron_energy_equation!(fvec_out.electron_ppar, fvec_in.electron_ppar, @@ -2274,16 +2274,18 @@ function add_contribution_from_pdf_term!(pdf_out, pdf_in, ppar, dens, upar, mome end end - if electron_source_settings.active - source_density_amplitude = moments.electron.external_source_density_amplitude - source_momentum_amplitude = moments.electron.external_source_momentum_amplitude - source_pressure_amplitude = moments.electron.external_source_pressure_amplitude - @loop_r_z ir iz begin - term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - - (0.5 * source_pressure_amplitude[iz,ir] + - source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) - @loop_vperp_vpa ivperp ivpa begin - pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + for index ∈ eachindex(electron_source_settings) + if electron_source_settings[index].active + @views source_density_amplitude = moments.electron.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.electron.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.electron.external_source_pressure_amplitude[:, :, index] + @loop_r_z ir iz begin + term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - + (0.5 * source_pressure_amplitude[iz,ir] + + source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) + @loop_vperp_vpa ivperp ivpa begin + pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + end end end end diff --git a/moment_kinetics/src/electron_vpa_advection.jl b/moment_kinetics/src/electron_vpa_advection.jl index 2d7968286..5f8abe6b5 100644 --- a/moment_kinetics/src/electron_vpa_advection.jl +++ b/moment_kinetics/src/electron_vpa_advection.jl @@ -66,19 +66,22 @@ function update_electron_speed_vpa!(advect, density, upar, ppar, moments, vpa, advect.speed[ivpa,ivperp,iz,ir] = ((vth[iz,ir] * dppar_dz[iz,ir] + vpa[ivpa] * dqpar_dz[iz,ir]) / (2 * ppar[iz,ir]) - vpa[ivpa]^2 * dvth_dz[iz,ir]) end - if electron_source_settings.active - source_density_amplitude = moments.electron.external_source_density_amplitude - source_momentum_amplitude = moments.electron.external_source_momentum_amplitude - source_pressure_amplitude = moments.electron.external_source_pressure_amplitude - @loop_r_z ir iz begin - term1 = source_density_amplitude[iz,ir] * upar[iz,ir]/(density[iz,ir]*vth[iz,ir]) - term2_over_vpa = - -0.5 * (source_pressure_amplitude[iz,ir] + - 2.0 * upar[iz,ir] * source_momentum_amplitude[iz,ir]) / - ppar[iz,ir] + - 0.5 * source_density_amplitude[iz,ir] / density[iz,ir] - @loop_vperp_vpa ivperp ivpa begin - advect.speed[ivpa,ivperp,iz,ir] += term1 + vpa[ivpa] * term2_over_vpa + + for index ∈ eachindex(electron_source_settings) + if electron_source_settings[index].active + @views source_density_amplitude = moments.electron.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.electron.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.electron.external_source_pressure_amplitude[:, :, index] + @loop_r_z ir iz begin + term1 = source_density_amplitude[iz,ir] * upar[iz,ir]/(density[iz,ir]*vth[iz,ir]) + term2_over_vpa = + -0.5 * (source_pressure_amplitude[iz,ir] + + 2.0 * upar[iz,ir] * source_momentum_amplitude[iz,ir]) / + ppar[iz,ir] + + 0.5 * source_density_amplitude[iz,ir] / density[iz,ir] + @loop_vperp_vpa ivperp ivpa begin + advect.speed[ivpa,ivperp,iz,ir] += term1 + vpa[ivpa] * term2_over_vpa + end end end end diff --git a/moment_kinetics/src/em_fields.jl b/moment_kinetics/src/em_fields.jl index 9f26f009c..462d23959 100644 --- a/moment_kinetics/src/em_fields.jl +++ b/moment_kinetics/src/em_fields.jl @@ -21,7 +21,7 @@ using MPI """ """ -function setup_em_fields(nvperp, nz, nr, n_ion_species, force_phi, drive_amplitude, drive_frequency, force_Er_zero) +function setup_em_fields(nvperp, nz, nr, n_ion_species, em_input) phi = allocate_shared_float(nz,nr) phi0 = allocate_shared_float(nz,nr) Er = allocate_shared_float(nz,nr) @@ -29,7 +29,8 @@ function setup_em_fields(nvperp, nz, nr, n_ion_species, force_phi, drive_amplitu gphi = allocate_shared_float(nvperp,nz,nr,n_ion_species) gEr = allocate_shared_float(nvperp,nz,nr,n_ion_species) gEz = allocate_shared_float(nvperp,nz,nr,n_ion_species) - return em_fields_struct(phi, phi0, Er, Ez, gphi, gEr, gEz, force_phi, drive_amplitude, drive_frequency, force_Er_zero) + return em_fields_struct(phi, phi0, Er, Ez, gphi, gEr, gEz, + em_input.force_Er_zero_at_wall) end """ @@ -116,9 +117,10 @@ function update_phi!(fields, fvec, vperp, z, r, composition, collisions, moments elseif composition.electron_physics ∈ (braginskii_fluid, kinetic_electrons, kinetic_electrons_with_temperature_equation) calculate_Epar_from_electron_force_balance!(fields.Ez, dens_e, moments.electron.dppar_dz, - collisions.nu_ei, moments.electron.parallel_friction, - composition.n_neutral_species, collisions.charge_exchange_electron, composition.me_over_mi, - fvec.density_neutral, fvec.uz_neutral, fvec.electron_upar) + collisions.electron_fluid.nu_ei, moments.electron.parallel_friction, + composition.n_neutral_species, collisions.reactions.electron_charge_exchange_frequency, + composition.me_over_mi, fvec.density_neutral, fvec.uz_neutral, + fvec.electron_upar) calculate_phi_from_Epar!(fields.phi, fields.Ez, r, z) end ## can calculate phi at z = L and hence phi_wall(z=L) using jpar_i at z =L if needed diff --git a/moment_kinetics/src/energy_equation.jl b/moment_kinetics/src/energy_equation.jl index 8890be3b6..3f505473b 100644 --- a/moment_kinetics/src/energy_equation.jl +++ b/moment_kinetics/src/energy_equation.jl @@ -23,10 +23,12 @@ function energy_equation!(ppar, fvec, moments, collisions, dt, spectral, composi end - if ion_source_settings.active - source_amplitude = moments.ion.external_source_pressure_amplitude - @loop_s_r_z is ir iz begin - ppar[iz,ir,is] += dt * source_amplitude[iz,ir] + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_amplitude = moments.ion.external_source_pressure_amplitude[:, :, index] + @loop_s_r_z is ir iz begin + ppar[iz,ir,is] += dt * source_amplitude[iz,ir] + end end end @@ -39,20 +41,22 @@ function energy_equation!(ppar, fvec, moments, collisions, dt, spectral, composi # add in contributions due to charge exchange/ionization collisions if composition.n_neutral_species > 0 - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 @loop_s_r_z is ir iz begin ppar[iz,ir,is] -= - dt*collisions.charge_exchange*( + dt*charge_exchange*( fvec.density_neutral[iz,ir,is]*fvec.ppar[iz,ir,is] - fvec.density[iz,ir,is]*fvec.pz_neutral[iz,ir,is] - fvec.density[iz,ir,is]*fvec.density_neutral[iz,ir,is] * (fvec.upar[iz,ir,is] - fvec.uz_neutral[iz,ir,is])^2) end end - if abs(collisions.ionization) > 0.0 + if abs(ionization) > 0.0 @loop_s_r_z is ir iz begin ppar[iz,ir,is] += - dt*collisions.ionization*fvec.density[iz,ir,is] * ( + dt*ionization*fvec.density[iz,ir,is] * ( fvec.pz_neutral[iz,ir,is] + fvec.density_neutral[iz,ir,is] * (fvec.upar[iz,ir,is]-fvec.uz_neutral[iz,ir,is])^2) @@ -75,10 +79,12 @@ function neutral_energy_equation!(pz, fvec, moments, collisions, dt, spectral, - 3.0*fvec.pz_neutral[iz,ir,isn]*moments.neutral.duz_dz[iz,ir,isn]) end - if neutral_source_settings.active - source_amplitude = moments.neutral.external_source_pressure_amplitude - @loop_s_r_z isn ir iz begin - pz[iz,ir,isn] += dt * source_amplitude[iz,ir] + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_amplitude = moments.neutral.external_source_pressure_amplitude[:, :, index] + @loop_s_r_z isn ir iz begin + pz[iz,ir,isn] += dt * source_amplitude[iz,ir] + end end end @@ -91,20 +97,22 @@ function neutral_energy_equation!(pz, fvec, moments, collisions, dt, spectral, # add in contributions due to charge exchange/ionization collisions if composition.n_neutral_species > 0 - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 @loop_sn_r_z isn ir iz begin pz[iz,ir,isn] -= - dt*collisions.charge_exchange*( + dt*charge_exchange*( fvec.density[iz,ir,isn]*fvec.pz_neutral[iz,ir,isn] - fvec.density_neutral[iz,ir,isn]*fvec.ppar[iz,ir,isn] - fvec.density_neutral[iz,ir,isn]*fvec.density[iz,ir,isn] * (fvec.uz_neutral[iz,ir,isn] - fvec.upar[iz,ir,isn])^2) end end - if abs(collisions.ionization) > 0.0 + if abs(ionization) > 0.0 @loop_sn_r_z isn ir iz begin pz[iz,ir,isn] -= - dt*collisions.ionization*fvec.density[iz,ir,isn]*fvec.pz_neutral[iz,ir,isn] + dt*ionization*fvec.density[iz,ir,isn]*fvec.pz_neutral[iz,ir,isn] end end end diff --git a/moment_kinetics/src/external_sources.jl b/moment_kinetics/src/external_sources.jl index 98fe4169c..e2551e6d7 100644 --- a/moment_kinetics/src/external_sources.jl +++ b/moment_kinetics/src/external_sources.jl @@ -14,7 +14,10 @@ module external_sources export setup_external_sources!, external_ion_source!, external_neutral_source!, external_ion_source_controller!, external_neutral_source_controller!, initialize_external_source_amplitude!, - initialize_external_source_controller_integral! + initialize_external_source_controller_integral!, + total_external_ion_sources!, total_external_neutral_sources!, + total_external_ion_source_controllers!, total_external_neutral_source_controllers!, + external_electron_source!, total_external_electron_sources! using ..array_allocation: allocate_float, allocate_shared_float using ..calculus @@ -40,13 +43,13 @@ Returns a NamedTuple `(ion=ion_source_settings, neutral=neutral_source_settings) containing two NamedTuples of settings. """ function setup_external_sources!(input_dict, r, z, electron_physics) - function get_settings(neutrals) + function get_settings_ions(source_index, active_flag) input = set_defaults_and_check_section!( - input_dict, neutrals ? "neutral_source" : "ion_source"; - active=false, + input_dict, "ion_source_$source_index"; + active=active_flag, source_strength=1.0, source_n=1.0, - source_T=neutrals ? get(input_dict, "T_wall", 1.0) : 1.0, + source_T=1.0, source_v0=0.0, # birth speed for "alphas" option source_vpa0=0.0, # birth vpa for "beam" option source_vperp0=0.0, # birth vperp for "beam" option @@ -137,7 +140,123 @@ function setup_external_sources!(input_dict, r, z, electron_physics) else PI_density_target_rank = nothing end - elseif neutrals && input["source_type"] == "recycling" + elseif input["source_type"] ∈ ("Maxwellian", "energy", "alphas", "alphas-with-losses", "beam", "beam-with-losses") + PI_density_target = nothing + PI_controller_amplitude = nothing + controller_source_profile = nothing + PI_density_target_ir = nothing + PI_density_target_iz = nothing + PI_density_target_rank = nothing + else + error("Unrecognised ion source_type=$(input["source_type"])." + * "Possible values are: Maxwellian, density_profile_control, " + * "density_midpoint_control, energy, alphas, alphas-with-losses, " + * "beam, beam-with-losses") + end + return ion_source_data(; Dict(Symbol(k)=>v for (k,v) ∈ input)..., r_amplitude, + z_amplitude=z_amplitude, PI_density_target=PI_density_target, + PI_controller_amplitude, controller_source_profile, + PI_density_target_ir, PI_density_target_iz, PI_density_target_rank) + end + + function get_settings_neutrals(source_index, active_flag) + input = set_defaults_and_check_section!( + input_dict, "neutral_source_$source_index"; + active=active_flag, + source_strength=1.0, + source_n=1.0, + source_T=get(input_dict, "T_wall", 1.0), + source_v0=0.0, # birth speed for "alphas" option + source_vpa0=0.0, # birth vpa for "beam" option + source_vperp0=0.0, # birth vperp for "beam" option + sink_strength=1.0, # strength of sink in "alphas-with-losses" & "beam-with-losses" option + sink_vth=0.0, # thermal speed for sink in "alphas-with-losses" & "beam-with-losses" option + r_profile="constant", + r_width=1.0, + r_relative_minimum=0.0, + z_profile="constant", + z_width=1.0, + z_relative_minimum=0.0, + source_type="Maxwellian", # "energy", "alphas", "alphas-with-losses", "beam", "beam-with-losses" + PI_density_controller_P=0.0, + PI_density_controller_I=0.0, + PI_density_target_amplitude=1.0, + PI_density_target_r_profile="constant", + PI_density_target_r_width=1.0, + PI_density_target_r_relative_minimum=0.0, + PI_density_target_z_profile="constant", + PI_density_target_z_width=1.0, + PI_density_target_z_relative_minimum=0.0, + recycling_controller_fraction=0.0, + ) + + r_amplitude = get_source_profile(input["r_profile"], input["r_width"], + input["r_relative_minimum"], r) + z_amplitude = get_source_profile(input["z_profile"], input["z_width"], + input["z_relative_minimum"], z) + if input["source_type"] == "density_profile_control" + PI_density_target_amplitude = input["PI_density_target_amplitude"] + PI_density_target_r_factor = + get_source_profile(input["PI_density_target_r_profile"], + input["PI_density_target_r_width"], + input["PI_density_target_r_relative_minimum"], r) + PI_density_target_z_factor = + get_source_profile(input["PI_density_target_z_profile"], + input["PI_density_target_z_width"], + input["PI_density_target_z_relative_minimum"], z) + PI_density_target = allocate_shared_float(z.n,r.n) + @serial_region begin + for ir ∈ 1:r.n, iz ∈ 1:z.n + PI_density_target[iz,ir] = + PI_density_target_amplitude * PI_density_target_r_factor[ir] * + PI_density_target_z_factor[iz] + end + end + PI_controller_amplitude = nothing + controller_source_profile = nothing + PI_density_target_ir = nothing + PI_density_target_iz = nothing + PI_density_target_rank = nothing + elseif input["source_type"] == "density_midpoint_control" + PI_density_target = input["PI_density_target_amplitude"] + + if comm_block[] != MPI.COMM_NULL + PI_controller_amplitude = allocate_shared_float(1) + controller_source_profile = allocate_shared_float(z.n, r.n) + else + PI_controller_amplitude = allocate_float(1) + controller_source_profile = allocate_float(z.n, r.n) + end + for ir ∈ 1:r.n, iz ∈ 1:z.n + controller_source_profile[iz,ir] = r_amplitude[ir] * z_amplitude[iz] + end + + # Find the indices, and process rank of the point at r=0, z=0. + # The result of findfirst() will be `nothing` if the point was not found. + PI_density_target_ir = findfirst(x->abs(x)<1.e-14, r.grid) + PI_density_target_iz = findfirst(x->abs(x)<1.e-14, z.grid) + if block_rank[] == 0 + # Only need to do communications from the root process of each + # shared-memory block + if PI_density_target_ir !== nothing && PI_density_target_iz !== nothing + PI_density_target_rank = iblock_index[] + else + PI_density_target_rank = 0 + end + if comm_inter_block[] != MPI.COMM_NULL + PI_density_target_rank = MPI.Allreduce(PI_density_target_rank, +, + comm_inter_block[]) + end + if PI_density_target_rank == 0 && iblock_index[] == 0 && + (PI_density_target_ir === nothing || + PI_density_target_iz === nothing) + error("No grid point with r=0 and z=0 was found for the " + * "'density_midpoint' controller.") + end + else + PI_density_target_rank = nothing + end + elseif input["source_type"] == "recycling" recycling = input["recycling_controller_fraction"] if recycling ≤ 0.0 # Don't allow 0.0 as this is the default value, but makes no sense to have @@ -185,21 +304,18 @@ function setup_external_sources!(input_dict, r, z, electron_physics) PI_density_target_iz = nothing PI_density_target_rank = nothing else - error("Unrecognised source_type=$(input["source_type"])." + error("Unrecognised neutral source_type=$(input["source_type"])." * "Possible values are: Maxwellian, density_profile_control, " - * "density_midpoint_control, recycling (for neutrals only)") + * "density_midpoint_control, energy, alphas, alphas-with-losses, " + * "beam, beam-with-losses, recycling (for neutrals only)") end - return (; (Symbol(k)=>v for (k,v) ∈ input)..., r_amplitude=r_amplitude, + return neutral_source_data(; Dict(Symbol(k)=>v for (k,v) ∈ input)..., r_amplitude, z_amplitude=z_amplitude, PI_density_target=PI_density_target, - PI_controller_amplitude=PI_controller_amplitude, - controller_source_profile=controller_source_profile, - PI_density_target_ir=PI_density_target_ir, - PI_density_target_iz=PI_density_target_iz, - PI_density_target_rank=PI_density_target_rank) + PI_controller_amplitude, controller_source_profile, + PI_density_target_ir, PI_density_target_iz, PI_density_target_rank) end - - function get_electron_settings(ion_settings) + function get_settings_electrons(ion_settings) # Note most settings for the electron source are copied from the ion source, # because we require that the particle sources are the same for ions and # electrons. `source_T` can be set independently, and when using @@ -220,22 +336,47 @@ function setup_external_sources!(input_dict, r, z, electron_physics) end input["source_strength"] = ion_settings.source_strength end - return (; (Symbol(k)=>v for (k,v) ∈ input)..., active=ion_settings.active, - r_amplitude=ion_settings.r_amplitude, - z_amplitude=ion_settings.z_amplitude, - source_type=ion_settings.source_type) + return electron_source_data(input["source_strength"], input["source_T"], + ion_settings.active, ion_settings.r_amplitude, + ion_settings.z_amplitude, ion_settings.source_type) end - ion_settings = get_settings(false) + # put all ion sources into ion_source_data struct vector + ion_sources = ion_source_data[] + counter = 1 + while "ion_source_$counter" ∈ keys(input_dict) + push!(ion_sources, get_settings_ions(counter, true)) + counter += 1 + end + + # If there are no ion sources, add an inactive ion source to the vector + if counter == 1 + push!(ion_sources, get_settings_ions(1, false)) + end + + # put all electron sources into electron_source_data struct vector, where + # each entry is a mirror of the ion source vector. + electron_sources = electron_source_data[] if electron_physics ∈ (braginskii_fluid, kinetic_electrons, kinetic_electrons_with_temperature_equation) - electron_settings = get_electron_settings(ion_settings) + electron_sources = [get_settings_electrons(this_source) for this_source ∈ ion_sources] else - electron_settings = (active=false,) + electron_sources = [get_settings_electrons(get_settings_ions(1, false))] end - neutral_settings = get_settings(true) - return (ion=ion_settings, electron=electron_settings, neutral=neutral_settings) + # put all neutral sources into neutral_source_data struct vector + neutral_sources = neutral_source_data[] + counter = 1 + while "neutral_source_$counter" ∈ keys(input_dict) + push!(neutral_sources, get_settings_neutrals(counter, true)) + counter += 1 + end + # If there are no neutral sources, add an inactive neutral source to the vector + if counter == 1 + inactive_neutral_source = get_settings_neutrals(1, false) + push!(neutral_sources, inactive_neutral_source) + end + return (ion=ion_sources, electron=electron_sources, neutral=neutral_sources) end """ @@ -264,6 +405,10 @@ function get_source_profile(profile_type, width, relative_minimum, coord) end end return profile + elseif profile_type == "wall_exp_decay" + x = coord.grid + return @. (1.0 - relative_minimum) * exp(-(x-x[1]) / width) + relative_minimum + + (1.0 - relative_minimum) * exp(-(x[end]-x) / width) + relative_minimum else error("Unrecognised source profile type '$profile_type'.") end @@ -292,195 +437,205 @@ function initialize_external_source_amplitude!(moments, external_source_settings begin_r_z_region() ion_source_settings = external_source_settings.ion - if ion_source_settings.active - if ion_source_settings.source_type == "energy" - @loop_r_z ir iz begin - moments.ion.external_source_amplitude[iz,ir] = - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] - end - if moments.evolve_density + # The electron loop must be in the same as the ion loop so that each electron source + # can be matched to the corresponding ion source. + electron_source_settings = external_source_settings.electron + + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + if ion_source_settings[index].source_type == "energy" @loop_r_z ir iz begin - moments.ion.external_source_density_amplitude[iz,ir] = 0.0 + moments.ion.external_source_amplitude[iz,ir,index] = + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] end - end - if moments.evolve_upar - @loop_r_z ir iz begin - moments.ion.external_source_momentum_amplitude[iz,ir] = - - moments.ion.dens[iz,ir] * moments.ion.upar[iz,ir] * - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] + if moments.evolve_density + @loop_r_z ir iz begin + moments.ion.external_source_density_amplitude[iz,ir,index] = 0.0 + end end - end - if moments.evolve_ppar - @loop_r_z ir iz begin - moments.ion.external_source_pressure_amplitude[iz,ir] = - (0.5 * ion_source_settings.source_T + - moments.ion.upar[iz,ir]^2 - moments.ion.ppar[iz,ir]) * - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] + if moments.evolve_upar + @loop_r_z ir iz begin + moments.ion.external_source_momentum_amplitude[iz,ir,index]= + - moments.ion.dens[iz,ir] * moments.ion.upar[iz,ir] * + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] + end end - end - else - @loop_r_z ir iz begin - moments.ion.external_source_amplitude[iz,ir] = - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] - end - if moments.evolve_density - @loop_r_z ir iz begin - moments.ion.external_source_density_amplitude[iz,ir] = - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] + if moments.evolve_ppar + @loop_r_z ir iz begin + moments.ion.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * ion_source.source_T + + moments.ion.upar[iz,ir]^2 - moments.ion.ppar[iz,ir]) * + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] + end end - end - if moments.evolve_upar + else @loop_r_z ir iz begin - moments.ion.external_source_momentum_amplitude[iz,ir] = 0.0 + moments.ion.external_source_amplitude[iz,ir,index] = + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] end - end - if moments.evolve_ppar - @loop_r_z ir iz begin - moments.ion.external_source_pressure_amplitude[iz,ir] = - (0.5 * ion_source_settings.source_T + - moments.ion.upar[iz,ir]^2) * - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] + if moments.evolve_density + @loop_r_z ir iz begin + moments.ion.external_source_density_amplitude[iz,ir,index] = + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] + end + end + if moments.evolve_upar + @loop_r_z ir iz begin + moments.ion.external_source_momentum_amplitude[iz,ir,index] = 0.0 + end + end + if moments.evolve_ppar + @loop_r_z ir iz begin + moments.ion.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * ion_source_settings[index].source_T + + moments.ion.upar[iz,ir]^2) * + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] + end end end end end - electron_source_settings = external_source_settings.electron - if electron_source_settings.active - if electron_source_settings.source_type == "energy" - @loop_r_z ir iz begin - moments.electron.external_source_amplitude[iz,ir] = - electron_source_settings.source_strength * - electron_source_settings.r_amplitude[ir] * - electron_source_settings.z_amplitude[iz] - end - @loop_r_z ir iz begin - moments.electron.external_source_density_amplitude[iz,ir] = 0.0 - end - @loop_r_z ir iz begin - moments.electron.external_source_momentum_amplitude[iz,ir] = - - moments.electron.dens[iz,ir] * moments.electron.upar[iz,ir] * - electron_source_settings.source_strength * - electron_source_settings.r_amplitude[ir] * - electron_source_settings.z_amplitude[iz] - end - @loop_r_z ir iz begin - moments.electron.external_source_pressure_amplitude[iz,ir] = - (0.5 * electron_source_settings.source_T + - moments.electron.upar[iz,ir]^2 - moments.electron.ppar[iz,ir]) * - electron_source_settings.source_strength * - electron_source_settings.r_amplitude[ir] * - electron_source_settings.z_amplitude[iz] - end - else - @loop_r_z ir iz begin - moments.electron.external_source_amplitude[iz,ir] = - moments.ion.external_source_amplitude[iz,ir] - end - if moments.evolve_density + # now do same for electron sources, which (if present) are mostly mirrors of ion sources + for index ∈ eachindex(electron_source_settings) + if electron_source_settings[index].active + if electron_source_settings[index].source_type == "energy" + @loop_r_z ir iz begin + moments.electron.external_source_amplitude[iz,ir,index] = + electron_source_settings[index].source_strength * + electron_source_settings[index].r_amplitude[ir] * + electron_source_settings[index].z_amplitude[iz] + end @loop_r_z ir iz begin - moments.electron.external_source_density_amplitude[iz,ir] = - moments.ion.external_source_density_amplitude[iz,ir] + moments.electron.external_source_density_amplitude[iz,ir,index] = 0.0 + end + @loop_r_z ir iz begin + moments.electron.external_source_momentum_amplitude[iz,ir,index] = + - moments.electron.dens[iz,ir] * moments.electron.upar[iz,ir] * + electron_source_settings[index].source_strength * + electron_source_settings[index].r_amplitude[ir] * + electron_source_settings[index].z_amplitude[iz] + end + @loop_r_z ir iz begin + moments.electron.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * electron_source_settings[index].source_T + + moments.electron.upar[iz,ir]^2 - moments.electron.ppar[iz,ir]) * + electron_source_settings[index].source_strength * + electron_source_settings[index].r_amplitude[ir] * + electron_source_settings[index].z_amplitude[iz] end else @loop_r_z ir iz begin - # Note set this using *ion* settings to force electron density source - # to always be equal to ion density source (even when - # evolve_density=false) to ensure the source does not inject charge - # into the simulation. - moments.electron.external_source_density_amplitude[iz,ir] = - ion_source_settings.source_strength * - ion_source_settings.r_amplitude[ir] * - ion_source_settings.z_amplitude[iz] + moments.electron.external_source_amplitude[iz,ir,index] = + moments.ion.external_source_amplitude[iz,ir,index] + end + if moments.evolve_density + @loop_r_z ir iz begin + moments.electron.external_source_density_amplitude[iz,ir,index] = + moments.ion.external_source_density_amplitude[iz,ir,index] + end + else + @loop_r_z ir iz begin + # Note set this using *ion* settings to force electron density source + # to always be equal to ion density source (even when + # evolve_density=false) to ensure the source does not inject charge + # into the simulation. + moments.electron.external_source_density_amplitude[iz,ir,index] = + ion_source_settings[index].source_strength * + ion_source_settings[index].r_amplitude[ir] * + ion_source_settings[index].z_amplitude[iz] + end + end + @loop_r_z ir iz begin + moments.electron.external_source_momentum_amplitude[iz,ir,index] = 0.0 + end + @loop_r_z ir iz begin + moments.electron.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * electron_source_settings[index].source_T + + moments.electron.upar[iz,ir]^2) * + moments.electron.external_source_amplitude[iz,ir,index] end - end - @loop_r_z ir iz begin - moments.electron.external_source_momentum_amplitude[iz,ir] = 0.0 - end - @loop_r_z ir iz begin - moments.electron.external_source_pressure_amplitude[iz,ir] = - (0.5 * electron_source_settings.source_T + - moments.electron.upar[iz,ir]^2) * - moments.electron.external_source_amplitude[iz,ir] end end end if n_neutral_species > 0 neutral_source_settings = external_source_settings.neutral - if neutral_source_settings.active - if neutral_source_settings.source_type == "energy" - @loop_r_z ir iz begin - moments.neutral.external_source_amplitude[iz,ir] = - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] - end - if moments.evolve_density + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + if neutral_source_settings[index].source_type == "energy" @loop_r_z ir iz begin - moments.neutral.external_source_density_amplitude[iz,ir] = 0.0 + moments.neutral.external_source_amplitude[iz,ir,index] = + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] end - end - if moments.evolve_upar - @loop_r_z ir iz begin - moments.neutral.external_source_momentum_amplitude[iz,ir] = - - moments.neutral.dens[iz,ir] * moments.neutral.upar[iz,ir] * - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] + if moments.evolve_density + @loop_r_z ir iz begin + moments.neutral.external_source_density_amplitude[iz,ir,index] = 0.0 + end end - end - if moments.evolve_ppar - @loop_r_z ir iz begin - moments.neutral.external_source_pressure_amplitude[iz,ir] = - (0.5 * neutral_source_settings.source_T + - moments.neutral.upar[iz,ir]^2 - - moments.neutral.ppar[iz,ir]) * - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] + if moments.evolve_upar + @loop_r_z ir iz begin + moments.neutral.external_source_momentum_amplitude[iz,ir,index] = + - moments.neutral.dens[iz,ir] * moments.neutral.upar[iz,ir] * + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] + end end - end - else - @loop_r_z ir iz begin - moments.neutral.external_source_amplitude[iz,ir] = - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] + if moments.evolve_ppar + @loop_r_z ir iz begin + moments.neutral.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * neutral_source_settings[index].source_T + + moments.neutral.upar[iz,ir]^2 - + moments.neutral.ppar[iz,ir]) * + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] + end end - if moments.evolve_density + else @loop_r_z ir iz begin - moments.neutral.external_source_density_amplitude[iz,ir] = - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] + moments.neutral.external_source_amplitude[iz,ir,index] = + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] end - end - if moments.evolve_upar - @loop_r_z ir iz begin - moments.neutral.external_source_momentum_amplitude[iz,ir] = 0.0 + if moments.evolve_density + @loop_r_z ir iz begin + moments.neutral.external_source_density_amplitude[iz,ir,index] = + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] + end end - end - if moments.evolve_ppar - @loop_r_z ir iz begin - moments.neutral.external_source_pressure_amplitude[iz,ir] = - (0.5 * neutral_source_settings.source_T + - moments.neutral.uz[iz,ir]^2) * - neutral_source_settings.source_strength * - neutral_source_settings.r_amplitude[ir] * - neutral_source_settings.z_amplitude[iz] + if moments.evolve_upar + @loop_r_z ir iz begin + moments.neutral.external_source_momentum_amplitude[iz,ir,index] = 0.0 + end + end + if moments.evolve_ppar + @loop_r_z ir iz begin + moments.neutral.external_source_pressure_amplitude[iz,ir,index] = + (0.5 * neutral_source_settings[index].source_T + + moments.neutral.uz[iz,ir]^2) * + neutral_source_settings[index].source_strength * + neutral_source_settings[index].r_amplitude[ir] * + neutral_source_settings[index].z_amplitude[iz] + end end end end @@ -503,21 +658,21 @@ function initialize_external_source_controller_integral!( begin_serial_region() @serial_region begin ion_source_settings = external_source_settings.ion - if ion_source_settings.active - if ion_source_settings.PI_density_controller_I != 0.0 && - ion_source_settings.source_type ∈ ("density_profile_control", - "density_midpoint_control") - moments.ion.external_source_controller_integral .= 0.0 + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active && + ion_source_settings[index].PI_density_controller_I != 0.0 && + ion_source_settings[index].source_type ∈ ("density_profile_control", "density_midpoint_control") + moments.ion.external_source_controller_integral[:, :, index] .= 0.0 end end if n_neutral_species > 0 neutral_source_settings = external_source_settings.neutral - if neutral_source_settings.active - if neutral_source_settings.PI_density_controller_I != 0.0 && - neutral_source_settings.source_type ∈ ("density_profile_control", - "density_midpoint_control") - moments.neutral.external_source_controller_integral .= 0.0 + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active && + neutral_source_settings[index].PI_density_controller_I != 0.0 && + neutral_source_settings[index].source_type ∈ ("density_profile_control", "density_midpoint_control") + moments.neutral.external_source_controller_integral[:, :, index] .= 0.0 end end end @@ -526,17 +681,33 @@ function initialize_external_source_controller_integral!( return nothing end +""" + total_external_ion_sources!(pdf, fvec, moments, ion_sources, vperp, vpa, dt, scratch_dummy) + +Contribute all of the ion sources to the ion pdf, one by one. +""" +function total_external_ion_sources!(pdf, fvec, moments, ion_sources, vperp, + vpa, dt, scratch_dummy) + for index ∈ eachindex(ion_sources) + if ion_sources[index].active + external_ion_source!(pdf, fvec, moments, ion_sources[index], + index, vperp, vpa, dt, scratch_dummy) + end + end + return nothing +end + """ external_ion_source!(pdf, fvec, moments, ion_source_settings, vperp, vpa, dt) Add external source term to the ion kinetic equation. """ -function external_ion_source!(pdf, fvec, moments, ion_source_settings, vperp, vpa, dt, scratch_dummy) +function external_ion_source!(pdf, fvec, moments, ion_source, index, vperp, vpa, dt, scratch_dummy) - source_type = ion_source_settings.source_type - source_amplitude = moments.ion.external_source_amplitude - source_T = ion_source_settings.source_T - source_n = ion_source_settings.source_n + source_type = ion_source.source_type + @views source_amplitude = moments.ion.external_source_amplitude[:,:,index] + source_T = ion_source.source_T + source_n = ion_source.source_n if vperp.n == 1 vth_factor = 1.0 / sqrt(source_T) else @@ -748,20 +919,39 @@ function external_ion_source!(pdf, fvec, moments, ion_source_settings, vperp, vp end """ - external_electron_source!(pdf, fvec, moments, electron_source_settings, vperp, + total_external_electron_sources!(pdf, fvec, moments, electron_sources, vperp, vpa, dt, scratch_dummy) + +Contribute all of the electron sources to the electron pdf, one by one. +""" +function total_external_electron_sources!(pdf_out, pdf_in, electron_density, electron_upar, + moments, composition, electron_sources, vperp, + vpa, dt) + for index ∈ eachindex(electron_sources) + if electron_sources[index].active + external_electron_source!(pdf_out, pdf_in, electron_density, electron_upar, + moments, composition, electron_sources[index], index, + vperp, vpa, dt) + end + end + return nothing +end + +""" + external_electron_source!(pdf_out, pdf_in, electron_density, electron_upar, + moments, composition, electron_source, index, vperp, vpa, dt) Add external source term to the electron kinetic equation. """ function external_electron_source!(pdf_out, pdf_in, electron_density, electron_upar, - moments, composition, electron_source_settings, vperp, + moments, composition, electron_source, index, vperp, vpa, dt) begin_r_z_vperp_region() me_over_mi = composition.me_over_mi - source_amplitude = moments.electron.external_source_amplitude - source_T = electron_source_settings.source_T + @views source_amplitude = moments.electron.external_source_amplitude[:, :, index] + source_T = electron_source.source_T if vperp.n == 1 vth_factor = 1.0 / sqrt(source_T / me_over_mi) else @@ -787,7 +977,7 @@ function external_electron_source!(pdf_out, pdf_in, electron_density, electron_u end end - if electron_source_settings.source_type == "energy" + if electron_source.source_type == "energy" # Take particles out of pdf so source does not change density @loop_r_z_vperp_vpa ir iz ivperp ivpa begin pdf_out[ivpa,ivperp,iz,ir] -= dt * source_amplitude[iz,ir] * @@ -798,18 +988,36 @@ function external_electron_source!(pdf_out, pdf_in, electron_density, electron_u return nothing end + +""" + total_external_neutral_sources!(pdf, fvec, moments, neutral_sources, vperp, vpa, dt, scratch_dummy) + +Contribute all of the neutral sources to the neutral pdf, one by one. +""" +function total_external_neutral_sources!(pdf, fvec, moments, neutral_sources, + vzeta, vr, vz, dt) + for index ∈ eachindex(neutral_sources) + if neutral_sources[index].active + external_neutral_source!(pdf, fvec, moments, neutral_sources[index], + index, vzeta, vr, vz, dt) + end + end + return nothing +end + + """ external_neutral_source!(pdf, fvec, moments, neutral_source_settings, vzeta, vr, vz, dt) Add external source term to the neutral kinetic equation. """ -function external_neutral_source!(pdf, fvec, moments, neutral_source_settings, vzeta, vr, - vz, dt) +function external_neutral_source!(pdf, fvec, moments, neutral_source, index, vzeta, vr, + vz, dt) begin_sn_r_z_vzeta_vr_region() - source_amplitude = moments.neutral.external_source_amplitude - source_T = neutral_source_settings.source_T + @views source_amplitude = moments.neutral.external_source_amplitude[:, :, index] + source_T = neutral_source.source_T if vzeta.n == 1 && vr.n == 1 vth_factor = 1.0 / sqrt(source_T) else @@ -883,7 +1091,7 @@ function external_neutral_source!(pdf, fvec, moments, neutral_source_settings, v end - if neutral_source_settings.source_type == "energy" + if neutral_source.source_type == "energy" # Take particles out of pdf so source does not change density @loop_sn_r_z_vzeta_vr_vz isn ir iz ivzeta ivr ivz begin pdf[iveta,ivr,ivz,iz,ir,isn] -= dt * source_amplitude[iz,ir] * @@ -894,13 +1102,27 @@ function external_neutral_source!(pdf, fvec, moments, neutral_source_settings, v return nothing end +""" + total_external_ion_source_controllers!(fvec_in, moments, ion_sources, dt) + +Contribute all of the ion source controllers to fvec_in, one by one. +""" +function total_external_ion_source_controllers!(fvec_in, moments, ion_sources, dt) + for index ∈ eachindex(ion_sources) + if ion_sources[index].active + external_ion_source_controller!(fvec_in, moments, ion_sources[index], index, dt) + end + end + return nothing +end + """ external_ion_source_controller!(fvec_in, moments, ion_source_settings, dt) Calculate the amplitude when using a PI controller for the density to set the external source amplitude. """ -function external_ion_source_controller!(fvec_in, moments, ion_source_settings, dt) +function external_ion_source_controller!(fvec_in, moments, ion_source_settings, index, dt) begin_r_z_region() is = 1 @@ -912,15 +1134,15 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, if ion_source_settings.source_type == "Maxwellian" if moments.evolve_ppar @loop_r_z ir iz begin - ion_moments.external_source_pressure_amplitude[iz,ir] = + ion_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * ion_source_settings.source_T + upar[iz,ir,is]^2) * - ion_moments.external_source_amplitude[iz,ir] + ion_moments.external_source_amplitude[iz,ir,index] end end elseif ion_source_settings.source_type == "energy" if moments.evolve_upar @loop_r_z ir iz begin - ion_moments.external_source_momentum_amplitude[iz,ir] = + ion_moments.external_source_momentum_amplitude[iz,ir,index] = - density[iz,ir] * upar[iz,ir] * ion_source_settings.source_strength * ion_source_settings.r_amplitude[ir] * @@ -929,7 +1151,7 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, end if moments.evolve_ppar @loop_r_z ir iz begin - ion_moments.external_source_pressure_amplitude[iz,ir] = + ion_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * ion_source_settings.source_T + upar[iz,ir]^2 - ppar[iz,ir]) * ion_source_settings.source_strength * ion_source_settings.r_amplitude[ir] * @@ -950,13 +1172,13 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, ion_source_settings.PI_density_target_ir, is] n_error = ion_source_settings.PI_density_target - n_mid - ion_moments.external_source_controller_integral[1,1] += + ion_moments.external_source_controller_integral[1,1,index] += dt * ion_source_settings.PI_density_controller_I * n_error # Only want a source, so never allow amplitude to be negative amplitude = max( ion_source_settings.PI_density_controller_P * n_error + - ion_moments.external_source_controller_integral[1,1], + ion_moments.external_source_controller_integral[1,1,index], 0) else amplitude = nothing @@ -970,18 +1192,18 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, amplitude = controller_amplitude[1] @loop_r_z ir iz begin - ion_moments.external_source_amplitude[iz,ir] = + ion_moments.external_source_amplitude[iz,ir,index] = amplitude * ion_source_settings.controller_source_profile[iz,ir] end if moments.evolve_density @loop_r_z ir iz begin - ion_moments.external_source_density_amplitude[iz,ir] = + ion_moments.external_source_density_amplitude[iz,ir,index] = amplitude * ion_source_settings.controller_source_profile[iz,ir] end end if moments.evolve_ppar @loop_r_z ir iz begin - ion_moments.external_source_pressure_amplitude[iz,ir] = + ion_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * ion_source_settings.source_T + upar[iz,ir,is]^2) * amplitude * ion_source_settings.controller_source_profile[iz,ir] end @@ -996,20 +1218,20 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, amplitude = ion_moments.external_source_amplitude @loop_r_z ir iz begin n_error = target[iz,ir] - density[iz,ir,is] - integral[iz,ir] += dt * I * n_error + integral[iz,ir,index] += dt * I * n_error # Only want a source, so never allow amplitude to be negative - amplitude[iz,ir] = max(P * n_error + integral[iz,ir], 0) + amplitude[iz,ir,index] = max(P * n_error + integral[iz,ir,index], 0) end if moments.evolve_density @loop_r_z ir iz begin - ion_moments.external_source_density_amplitude[iz,ir] = amplitude[iz,ir] + ion_moments.external_source_density_amplitude[iz,ir,index] = amplitude[iz,ir,index] end end if moments.evolve_ppar @loop_r_z ir iz begin - ion_moments.external_source_pressure_amplitude[iz,ir] = + ion_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * ion_source_settings.source_T + upar[iz,ir,is]^2) * - amplitude[iz,ir] + amplitude[iz,ir,index] end end elseif ion_source_settings.source_type == "alphas" @@ -1027,6 +1249,20 @@ function external_ion_source_controller!(fvec_in, moments, ion_source_settings, return nothing end +""" + total_external_electron_source_controllers!(fvec_in, moments, electron_sources, dt) + +Contribute all of the electron source controllers to fvec_in, one by one. +""" +function total_external_electron_source_controllers!(fvec_in, moments, electron_sources, dt) + for index ∈ eachindex(electron_sources) + if electron_sources[index].active + external_electron_source_controller!(fvec_in, moments, electron_sources[index], index, dt) + end + end + return nothing +end + """ external_electron_source_controller!(fvec_in, moments, electron_source_settings, dt) @@ -1035,35 +1271,35 @@ external source amplitude. As the electron density source must be equal to the ion density source in order not to inject charge into the simulation, the electron source (at least in some modes of -operation) depends on the ion source, so [`external_ion_source_controller`](@ref) must be +operation) depends on the ion source, so [`external_ion_source_controller!`](@ref) must be called before this function is called so that `moments.ion.external_source_amplitude` is up to date. """ function external_electron_source_controller!(fvec_in, moments, electron_source_settings, - dt) + index, dt) begin_r_z_region() is = 1 electron_moments = moments.electron - ion_source_amplitude = moments.ion.external_source_amplitude + @views ion_source_amplitude = moments.ion.external_source_amplitude[:, :, index] if electron_source_settings.source_type == "Maxwellian" @loop_r_z ir iz begin - electron_moments.external_source_pressure_amplitude[iz,ir] = + electron_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * electron_source_settings.source_T + fvec_in.electron_upar[iz,ir,is]^2) * - electron_moments.external_source_amplitude[iz,ir] + electron_moments.external_source_amplitude[iz,ir,index] end elseif electron_source_settings.source_type == "energy" @loop_r_z ir iz begin - electron_moments.external_source_momentum_amplitude[iz,ir] = + electron_moments.external_source_momentum_amplitude[iz,ir,index] = - electron_moments.density[iz,ir] * electron_moments.upar[iz,ir] * electron_source_settings.source_strength * electron_source_settings.r_amplitude[ir] * electron_source_settings.z_amplitude[iz] end @loop_r_z ir iz begin - electron_moments.external_source_pressure_amplitude[iz,ir] = + electron_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * electron_source_settings.source_T + electron_moments.upar[iz,ir]^2 - electron_moments.ppar[iz,ir]) * electron_source_settings.source_strength * @@ -1072,30 +1308,45 @@ function external_electron_source_controller!(fvec_in, moments, electron_source_ end else @loop_r_z ir iz begin - electron_moments.external_source_amplitude[iz,ir] = ion_source_amplitude[iz,ir] + electron_moments.external_source_amplitude[iz,ir,index] = ion_source_amplitude[iz,ir,index] end @loop_r_z ir iz begin - electron_moments.external_source_momentum_amplitude[iz,ir] = + electron_moments.external_source_momentum_amplitude[iz,ir,index] = - electron_moments.density[iz,ir] * electron_moments.upar[iz,ir] * - electron_moments.external_source_amplitude[iz,ir] + electron_moments.external_source_amplitude[iz,ir,index] end @loop_r_z ir iz begin - electron_moments.external_source_pressure_amplitude[iz,ir] = + electron_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * electron_source_settings.source_T + electron_moments.upar[iz,ir]^2 - electron_moments.ppar[iz,ir]) * - electron_moments.external_source_amplitude[iz,ir] + electron_moments.external_source_amplitude[iz,ir,index] end end # Density source is always the same as the ion one @loop_r_z ir iz begin - electron_moments.external_source_density_amplitude[iz,ir] = - moments.ion.external_source_density_amplitude[iz,ir] + electron_moments.external_source_density_amplitude[iz,ir,index] = + moments.ion.external_source_density_amplitude[iz,ir,index] end return nothing end +""" + total_external_neutral_source_controllers!(fvec_in, moments, neutral_sources, dt) + +Contribute all of the neutral source controllers to fvec_in, one by one. +""" +function total_external_neutral_source_controllers!(fvec_in, moments, neutral_sources, r, z, dt) + for index ∈ eachindex(neutral_sources) + if neutral_sources[index].active + external_neutral_source_controller!(fvec_in, moments, neutral_sources[index], + index, r, z, dt) + end + end + return nothing +end + """ external_neutral_source_controller!(fvec_in, moments, neutral_source_settings, r, z, dt) @@ -1103,8 +1354,8 @@ end Calculate the amplitude when using a PI controller for the density to set the external source amplitude. """ -function external_neutral_source_controller!(fvec_in, moments, neutral_source_settings, r, - z, dt) +function external_neutral_source_controller!(fvec_in, moments, neutral_source_settings, index, + r, z, dt) begin_r_z_region() is = 1 @@ -1113,15 +1364,15 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se if neutral_source_settings.source_type == "Maxwellian" if moments.evolve_ppar @loop_r_z ir iz begin - neutral_moments.external_source_pressure_amplitude[iz,ir] = + neutral_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * neutral_source_settings.source_T + fvec_in.upar[iz,ir,is]^2) * - neutral_moments.external_source_amplitude[iz,ir] + neutral_moments.external_source_amplitude[iz,ir,index] end end elseif neutral_source_settings.source_type == "energy" if moments.evolve_upar @loop_r_z ir iz begin - neutral_moments.external_source_momentum_amplitude[iz,ir] = + neutral_moments.external_source_momentum_amplitude[iz,ir,index] = - neutral_moments.density[iz,ir] * neutral_moments.uz[iz,ir] * neutral_source_settings.source_strength * neutral_source_settings.r_amplitude[ir] * @@ -1130,7 +1381,7 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se end if moments.evolve_ppar @loop_r_z ir iz begin - neutral_moments.external_source_pressure_amplitude[iz,ir] = + neutral_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * neutral_source_settings.source_T + neutral_moments.uz[iz,ir]^2 - neutral_moments.pz[iz,ir]) * neutral_source_settings.source_strength * @@ -1153,13 +1404,13 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se is] n_error = neutral_source_settings.PI_density_target - n_mid - neutral_moments.external_source_controller_integral[1,1] += + neutral_moments.external_source_controller_integral[1,1,index] += dt * neutral_source_settings.PI_density_controller_I * n_error # Only want a source, so never allow amplitude to be negative amplitude = max( neutral_source_settings.PI_density_controller_P * n_error + - neutral_moments.external_source_controller_integral[1,1], + neutral_moments.external_source_controller_integral[1,1,index], 0) else amplitude = nothing @@ -1173,20 +1424,20 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se amplitude = controller_amplitude[1] @loop_r_z ir iz begin - neutral_moments.external_source_amplitude[iz,ir] = - amplitude * neutral_source_settings.controller_source_profile[iz,ir] + neutral_moments.external_source_amplitude[iz,ir,index] = + amplitude * neutral_source_settings.controller_source_profile[iz,ir,index] end if moments.evolve_density @loop_r_z ir iz begin - neutral_moments.external_source_density_amplitude[iz,ir] = - amplitude * neutral_source_settings.controller_source_profile[iz,ir] + neutral_moments.external_source_density_amplitude[iz,ir,index] = + amplitude * neutral_source_settings.controller_source_profile[iz,ir,index] end end if moments.evolve_ppar @loop_r_z ir iz begin - neutral_moments.external_source_pressure_amplitude[iz,ir] = + neutral_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * neutral_source_settings.source_T + fvec_in.upar[iz,ir,is]^2) * - amplitude * neutral_source_settings.controller_source_profile[iz,ir] + amplitude * neutral_source_settings.controller_source_profile[iz,ir,index] end end elseif neutral_source_settings.source_type == "density_profile_control" @@ -1200,19 +1451,19 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se amplitude = neutral_moments.external_source_amplitude @loop_r_z ir iz begin n_error = target[iz,ir] - density[iz,ir,is] - PI_integral[iz,ir] += dt * I * n_error - amplitude[iz,ir] = P * n_error + PI_integral[iz,ir] + PI_integral[iz,ir,index] += dt * I * n_error + amplitude[iz,ir,index] = P * n_error + PI_integral[iz,ir,index] end if moments.evolve_density @loop_r_z ir iz begin - neutral_moments.external_source_density_amplitude[iz,ir] = amplitude[iz,ir] + neutral_moments.external_source_density_amplitude[iz,ir,index] = amplitude[iz,ir,index] end end if moments.evolve_ppar @loop_r_z ir iz begin - neutral_moments.external_source_pressure_amplitude[iz,ir] = + neutral_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * neutral_source_settings.source_T + fvec_in.upar[iz,ir,is]^2) * - amplitude[iz,ir] + amplitude[iz,ir,index] end end elseif neutral_source_settings.source_type == "recycling" @@ -1250,18 +1501,18 @@ function external_neutral_source_controller!(fvec_in, moments, neutral_source_se profile = neutral_source_settings.controller_source_profile prefactor = target_flux * neutral_source_settings.recycling_controller_fraction @loop_r_z ir iz begin - amplitude[iz,ir] = prefactor * profile[iz,ir] + amplitude[iz,ir,index] = prefactor * profile[iz,ir] end if moments.evolve_density @loop_r_z ir iz begin - neutral_moments.external_source_density_amplitude[iz,ir] = amplitude[iz,ir] + neutral_moments.external_source_density_amplitude[iz,ir,index] = amplitude[iz,ir,index] end end if moments.evolve_ppar @loop_r_z ir iz begin - neutral_moments.external_source_pressure_amplitude[iz,ir] = + neutral_moments.external_source_pressure_amplitude[iz,ir,index] = (0.5 * neutral_source_settings.source_T + fvec_in.upar[iz,ir,is]^2) * - amplitude[iz,ir] + amplitude[iz,ir,index] end end else diff --git a/moment_kinetics/src/file_io.jl b/moment_kinetics/src/file_io.jl index 5f6adab0d..9b0fafd54 100644 --- a/moment_kinetics/src/file_io.jl +++ b/moment_kinetics/src/file_io.jl @@ -5,6 +5,7 @@ module file_io export input_option_error export get_group export open_output_file, open_ascii_output_file +export setup_io_input export setup_file_io, finish_file_io export write_data_to_ascii @@ -19,6 +20,7 @@ using ..type_definitions: mk_float, mk_int using LibGit2 using MPI using Pkg +using UUIDs @debug_shared_array using ..communication: DebugMPISharedArray @@ -32,6 +34,23 @@ function __init__() end end +""" +Container for I/O settings +""" +Base.@kwdef struct io_input_struct + run_name::String + base_directory::String + ascii_output::Bool + binary_format::binary_format_type + parallel_io::Bool + run_id::String + output_dir::String + write_error_diagnostics::Bool + write_steady_state_diagnostics::Bool + write_electron_error_diagnostics::Bool + write_electron_steady_state_diagnostics::Bool +end + """ structure containing the various input/output streams """ @@ -56,8 +75,7 @@ struct io_moments_info{Tfile, Ttime, Tphi, Tmomi, Tmome, Tmomn, Tchodura_lower, Tchodura_upper, Texti1, Texti2, Texti3, Texti4, Texti5, Textn1, Textn2, Textn3, Textn4, Textn5, Texte1, Texte2, Texte3, Texte4, Tconstri, Tconstrn, Tconstre, Tint, Tfailcause, - Telectrontime, Telectronint, Telectronfailcause, Tnldiagnostics, - Tinput} + Telectrontime, Telectronint, Telectronfailcause, Tnldiagnostics} # file identifier for the binary file to which data is written fid::Tfile # handle for the time variable @@ -211,14 +229,14 @@ struct io_moments_info{Tfile, Ttime, Tphi, Tmomi, Tmome, Tmomn, Tchodura_lower, nl_solver_diagnostics::Tnldiagnostics # Settings for I/O - io_input::Tinput + io_input::io_input_struct end """ structure containing the data/metadata needed for binary file i/o distribution function data only """ -struct io_dfns_info{Tfile, Tfi, Tfe, Tfn, Tmoments, Tinput} +struct io_dfns_info{Tfile, Tfi, Tfe, Tfn, Tmoments} # file identifier for the binary file to which data is written fid::Tfile # handle for the ion species distribution function variable @@ -241,7 +259,7 @@ struct io_dfns_info{Tfile, Tfi, Tfe, Tfn, Tmoments, Tinput} f_neutral_start_last_timestep::Union{Tfn,Nothing} # Settings for I/O - io_input::Tinput + io_input::io_input_struct # Handles for moment variables io_moments::Tmoments @@ -252,8 +270,7 @@ structure containing the data/metadata needed for binary file i/o for electron initialization """ struct io_initial_electron_info{Tfile, Tfe, Tmom, Texte1, Texte2, Texte3, Texte4, - Tconstr, Telectrontime, Telectronint, Telectronfailcause, - Tinput} + Tconstr, Telectrontime, Telectronint, Telectronfailcause} # file identifier for the binary file to which data is written fid::Tfile time::Telectrontime @@ -313,7 +330,54 @@ struct io_initial_electron_info{Tfile, Tfe, Tmom, Texte1, Texte2, Texte3, Texte4 electron_dt_before_last_fail::Telectrontime # Settings for I/O - io_input::Tinput + io_input::io_input_struct +end + +""" +Read the settings for I/O +""" +function setup_io_input(input_dict, timestepping_section; ignore_MPI=false) + io_settings = set_defaults_and_check_section!( + input_dict, "output"; + run_name="", + base_directory="runs", + ascii_output=false, + binary_format=hdf5, + parallel_io="", + ) + if io_settings["run_name"] == "" + error("When passing a Dict directly for input, it is required to set `run_name` " + * "in the `[output]` section") + end + if io_settings["parallel_io"] == "" + io_settings["parallel_io"] = io_has_parallel(Val(io_settings["binary_format"])) + end + # Make copy of the section to avoid modifying the passed-in Dict + io_settings = copy(io_settings) + run_id = string(uuid4()) + if !ignore_MPI + # Communicate run_id to all blocks + # Need to convert run_id to a Vector{Char} for MPI + run_id_chars = [run_id...] + MPI.Bcast!(run_id_chars, 0, comm_world) + run_id = string(run_id_chars...) + end + io_settings["run_id"] = run_id + io_settings["output_dir"] = joinpath(io_settings["base_directory"], io_settings["run_name"]) + io_settings["write_error_diagnostics"] = timestepping_section["write_error_diagnostics"] + io_settings["write_steady_state_diagnostics"] = timestepping_section["write_steady_state_diagnostics"] + io_settings["write_electron_error_diagnostics"] = timestepping_section["electron_t_input"]["write_error_diagnostics"] + io_settings["write_electron_steady_state_diagnostics"] = timestepping_section["electron_t_input"]["write_steady_state_diagnostics"] + + # Create output_dir if it does not exist. + if !ignore_MPI + if global_rank[] == 0 + mkpath(io_settings["output_dir"]) + end + _block_synchronize() + end + + return io_input_struct(; (Symbol(k) => v for (k,v) ∈ io_settings)...) end """ @@ -459,8 +523,7 @@ function setup_electron_io(io_input, vpa, vperp, z, r, composition, collisions, if io_input.write_electron_error_diagnostics io_f_electron_loworder = create_dynamic_variable!(dynamic, "f_electron_loworder", mk_float, - vpa, vperp, z, r; - n_ion_species=composition.n_ion_species, + vpa, vperp, z, r, parallel_io=parallel_io, description="low-order approximation to electron distribution function, used to diagnose timestepping error") else @@ -469,8 +532,7 @@ function setup_electron_io(io_input, vpa, vperp, z, r, composition, collisions, if io_input.write_electron_steady_state_diagnostics io_f_electron_start_last_timestep = create_dynamic_variable!(dynamic, "f_electron_start_last_timestep", - mk_float, vpa, vperp, z, r; - n_ion_species=composition.n_ion_species, + mk_float, vpa, vperp, z, r, parallel_io=parallel_io, description="electron distribution function at the start of the last electron pseudo-timestep before output, used to measure steady state residual") else @@ -599,7 +661,10 @@ Get names of all variables function get_variable_keys end """ - write_single_value!(file_or_group, name, value; description=nothing, units=nothing) + write_single_value!(file_or_group, name, + data::Union{Number, AbstractString, AbstractArray{T,N}}, + coords::Union{coordinate,mk_int,NamedTuple}...; parallel_io, + description=nothing, units=nothing) where {T,N} Write a single variable to a file or group. If a description or units are passed, add as attributes of the variable. @@ -630,10 +695,10 @@ function write_overview!(fid, composition, collisions, parallel_io, evolve_densi write_single_value!(overview, "T_e", composition.T_e, parallel_io=parallel_io, description="fixed electron temperature") write_single_value!(overview, "charge_exchange_frequency", - collisions.charge_exchange, parallel_io=parallel_io, + collisions.reactions.charge_exchange_frequency, parallel_io=parallel_io, description="quantity related to the charge exchange frequency") - write_single_value!(overview, "ionization_frequency", collisions.ionization, - parallel_io=parallel_io, + write_single_value!(overview, "ionization_frequency", + collisions.reactions.ionization_frequency, parallel_io=parallel_io, description="quantity related to the ionization frequency") write_single_value!(overview, "evolve_density", evolve_density, parallel_io=parallel_io, @@ -773,21 +838,24 @@ function write_boundary_distributions!(fid, boundary_distributions, parallel_io, @serial_region begin boundary_distributions_io = create_io_group(fid, "boundary_distributions") + n_ion_species_coord = (name="n_ion_species", n=composition.n_ion_species) + n_neutral_species_coord = (name="n_neutral_species", + n=composition.n_neutral_species) write_single_value!(boundary_distributions_io, "pdf_rboundary_ion_left", boundary_distributions.pdf_rboundary_ion[:,:,:,1,:], vpa, vperp, z, - parallel_io=parallel_io, n_ion_species=composition.n_ion_species, + n_ion_species_coord; parallel_io=parallel_io, description="Initial ion-particle pdf at left radial boundary") write_single_value!(boundary_distributions_io, "pdf_rboundary_ion_right", boundary_distributions.pdf_rboundary_ion[:,:,:,2,:], vpa, vperp, z, - parallel_io=parallel_io, n_ion_species=composition.n_ion_species, + n_ion_species_coord; parallel_io=parallel_io, description="Initial ion-particle pdf at right radial boundary") write_single_value!(boundary_distributions_io, "pdf_rboundary_neutral_left", boundary_distributions.pdf_rboundary_neutral[:,:,:,:,1,:], vz, vr, vzeta, z, - parallel_io=parallel_io, n_neutral_species=composition.n_neutral_species, + n_neutral_species_coord; parallel_io=parallel_io, description="Initial neutral-particle pdf at left radial boundary") write_single_value!(boundary_distributions_io, "pdf_rboundary_neutral_right", boundary_distributions.pdf_rboundary_neutral[:,:,:,:,2,:], vz, vr, vzeta, z, - parallel_io=parallel_io, n_neutral_species=composition.n_neutral_species, + n_neutral_species_coord; parallel_io=parallel_io, description="Initial neutral-particle pdf at right radial boundary") end return nothing @@ -945,7 +1013,8 @@ function define_io_coordinate!(parent, coord, coord_name, description, parallel_ description="discretization used for $coord_name") # write the finite-difference option for the coordinate - write_single_value!(group, "fd_option", coord.fd_option; parallel_io=parallel_io, + write_single_value!(group, "finite_difference_option", + coord.finite_difference_option; parallel_io=parallel_io, description="type of finite difference for $coord_name, if used") write_single_value!(group, "cheb_option", coord.cheb_option; parallel_io=parallel_io, @@ -967,21 +1036,16 @@ function define_io_coordinate!(parent, coord, coord_name, description, parallel_ end """ - create_dynamic_variable!(file_or_group, name, type, coords::coordinate...; - n_ion_species=1, n_neutral_species=1, - diagnostic_var_size=nothing, description=nothing, - units=nothing) + create_dynamic_variable!(file_or_group, name, type, + coords::{coordinate,NamedTuple}...; + description=nothing, units=nothing) Create a time-evolving variable in `file_or_group` named `name` of type `type`. `coords` are the coordinates corresponding to the dimensions of the array, in the order of the -array dimensions. The species dimension does not have a `coordinate`, so the number of -species is passed as `nspecies`. A description and/or units can be added with the keyword -arguments. - -If a Tuple giving an array size is passed to `diagnostic_var_size`, a 'diagnostic' -variable is created - i.e. one that does not depend on the coordinates, so is assumed to -be the same on all processes and only needs to be written from the root process (for each -output file). +array dimensions - they may be either `coordinate` structs or `NamedTuple`s that contain +at least the fields `name`, `n`. The species dimension does not have a `coordinate`, so +the number of species is passed as `nspecies`. A description and/or units can be added +with the keyword arguments. """ function create_dynamic_variable! end @@ -1078,13 +1142,13 @@ function define_dynamic_moment_variables!(fid, n_ion_species, n_neutral_species, n_failure_vars = length(t_params.failure_caused_by) io_failure_caused_by = create_dynamic_variable!( - dynamic, "failure_caused_by", mk_int; diagnostic_var_size=n_failure_vars, + dynamic, "failure_caused_by", mk_int, (name="n_failure_vars", n=n_failure_vars); parallel_io=parallel_io, description="cumulative count of how many times each variable caused a " * "timestep failure for the run") n_limit_vars = length(t_params.limit_caused_by) io_limit_caused_by = create_dynamic_variable!( - dynamic, "limit_caused_by", mk_int; diagnostic_var_size=n_limit_vars, + dynamic, "limit_caused_by", mk_int, (name="n_limit_vars", n=n_limit_vars); parallel_io=parallel_io, description="cumulative count of how many times each factor limited the " * "timestep for the run") @@ -1203,17 +1267,17 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, evolve_ppar, write_error_diagnostics, write_steady_state_diagnostics) dynamic = get_group(fid, "dynamic_data") + n_ion_species_coord = (name="n_ion_species", n=n_ion_species) # io_density is the handle for the ion particle density - io_density = create_dynamic_variable!(dynamic, "density", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_density = create_dynamic_variable!(dynamic, "density", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species density", units="n_ref") if write_error_diagnostics io_density_loworder = - create_dynamic_variable!(dynamic, "density_loworder", mk_float, z, r; - n_ion_species=n_ion_species, parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "density_loworder", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="low-order approximation to ion species density, used to diagnose timestepping error", units="n_ref") else @@ -1221,8 +1285,8 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end if write_steady_state_diagnostics io_density_start_last_timestep = - create_dynamic_variable!(dynamic, "density_start_last_timestep", mk_float, z, r; - n_ion_species=n_ion_species, parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "density_start_last_timestep", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species density at the start of the last timestep before output, used to measure steady state residual", units="n_ref") else @@ -1230,15 +1294,14 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end # io_upar is the handle for the ion parallel flow density - io_upar = create_dynamic_variable!(dynamic, "parallel_flow", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_upar = create_dynamic_variable!(dynamic, "parallel_flow", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species parallel flow", units="c_ref = sqrt(2*T_ref/mi)") if write_error_diagnostics io_upar_loworder = - create_dynamic_variable!(dynamic, "parallel_flow_loworder", mk_float, z, r; - n_ion_species=n_ion_species, parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "parallel_flow_loworder", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="low-order approximation to ion species parallel flow, used to diagnose timestepping error", units="c_ref = sqrt(2*T_ref/mi)") else @@ -1247,7 +1310,7 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, if write_steady_state_diagnostics io_upar_start_last_timestep = create_dynamic_variable!(dynamic, "parallel_flow_start_last_timestep", - mk_float, z, r; n_ion_species=n_ion_species, + mk_float, z, r, n_ion_species_coord; parallel_io=parallel_io, description="ion species parallel flow at the start of the last timestep before output, used to measure steady state residual", units="c_ref = sqrt(2*T_ref/mi)") @@ -1256,15 +1319,14 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end # io_ppar is the handle for the ion parallel pressure - io_ppar = create_dynamic_variable!(dynamic, "parallel_pressure", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_ppar = create_dynamic_variable!(dynamic, "parallel_pressure", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species parallel pressure", units="n_ref*T_ref") if write_error_diagnostics io_ppar_loworder = - create_dynamic_variable!(dynamic, "parallel_pressure_loworder", mk_float, z, r; - n_ion_species=n_ion_species, parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "parallel_pressure_loworder", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="low-order approximation to ion species parallel pressure, used to diagnose timestepping error", units="n_ref*T_ref") else @@ -1273,7 +1335,7 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, if write_steady_state_diagnostics io_ppar_start_last_timestep = create_dynamic_variable!(dynamic, "parallel_pressure_start_last_timestep", - mk_float, z, r; n_ion_species=n_ion_species, + mk_float, z, r, n_ion_species_coord; parallel_io=parallel_io, description="ion species parallel pressure at the start of the last timestep before output, used to measure steady state residual", units="n_ref*T_ref") @@ -1282,15 +1344,14 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end # io_pperp is the handle for the ion parallel pressure - io_pperp = create_dynamic_variable!(dynamic, "perpendicular_pressure", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_pperp = create_dynamic_variable!(dynamic, "perpendicular_pressure", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species perpendicular pressure", units="n_ref*T_ref") if write_error_diagnostics io_pperp_loworder = - create_dynamic_variable!(dynamic, "perpendicular_pressure_loworder", mk_float, z, - r; n_ion_species=n_ion_species, parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "perpendicular_pressure_loworder", mk_float, + z, r, n_ion_species_coord; parallel_io=parallel_io, description="low-order approximation to ion species perpendicular pressure, used to diagnose timestepping error", units="n_ref*T_ref") else @@ -1299,7 +1360,7 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, if write_steady_state_diagnostics io_pperp_start_last_timestep = create_dynamic_variable!(dynamic, "perpendicular_pressure_start_last_timestep", - mk_float, z, r; n_ion_species=n_ion_species, + mk_float, z, r, n_ion_species_coord; parallel_io=parallel_io, description="ion species perpendicular pressure at the start of the last timestep before output, used to measure steady state residual", units="n_ref*T_ref") @@ -1308,35 +1369,33 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end # io_qpar is the handle for the ion parallel heat flux - io_qpar = create_dynamic_variable!(dynamic, "parallel_heat_flux", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_qpar = create_dynamic_variable!(dynamic, "parallel_heat_flux", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species parallel heat flux", units="n_ref*T_ref*c_ref") # io_vth is the handle for the ion thermal speed - io_vth = create_dynamic_variable!(dynamic, "thermal_speed", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_vth = create_dynamic_variable!(dynamic, "thermal_speed", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species thermal speed", units="c_ref") # io_dSdt is the handle for the entropy production (due to collisions) - io_dSdt = create_dynamic_variable!(dynamic, "entropy_production", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, + io_dSdt = create_dynamic_variable!(dynamic, "entropy_production", mk_float, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species entropy production", units="") ion_source_settings = external_source_settings.ion - if ion_source_settings.active + if any(x -> x.active, ion_source_settings) + n_sources = (name="n_ion_sources", n=length(ion_source_settings)) external_source_amplitude = create_dynamic_variable!( - dynamic, "external_source_amplitude", mk_float, z, r; + dynamic, "external_source_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external source for ions", units="n_ref/c_ref^3*c_ref/L_ref") if evolve_density external_source_density_amplitude = create_dynamic_variable!( - dynamic, "external_source_density_amplitude", mk_float, z, r; + dynamic, "external_source_density_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external density source for ions", units="n_ref*c_ref/L_ref") else @@ -1344,7 +1403,7 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end if evolve_upar external_source_momentum_amplitude = create_dynamic_variable!( - dynamic, "external_source_momentum_amplitude", mk_float, z, r; + dynamic, "external_source_momentum_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external momentum source for ions", units="m_ref*n_ref*c_ref*c_ref/L_ref") else @@ -1352,17 +1411,17 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, end if evolve_ppar external_source_pressure_amplitude = create_dynamic_variable!( - dynamic, "external_source_pressure_amplitude", mk_float, z, r; + dynamic, "external_source_pressure_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external pressure source for ions", units="m_ref*n_ref*c_ref^2*c_ref/L_ref") else external_source_pressure_amplitude = nothing end - if ion_source_settings.PI_density_controller_I != 0.0 && - ion_source_settings.source_type ∈ ("density_profile_control", "density_midpoint_control") - if ion_source_settings.source_type == "density_profile_control" + if any(x -> x.PI_density_controller_I != 0.0 && x.source_type ∈ + ("density_profile_control", "density_midpoint_control"), ion_source_settings) + if any(x -> x.source_type == "density_profile_control", ion_source_settings) external_source_controller_integral = create_dynamic_variable!( - dynamic, "external_source_controller_integral", mk_float, z, r; + dynamic, "external_source_controller_integral", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Integral term for the PID controller of the external source for ions") else @@ -1384,41 +1443,38 @@ function define_dynamic_ion_moment_variables!(fid, n_ion_species, r::coordinate, if parallel_io || z.irank == 0 # io_chodura_lower is the handle for the ion thermal speed - io_chodura_lower = create_dynamic_variable!(dynamic, "chodura_integral_lower", mk_float, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, - description="Generalised Chodura integral lower sheath entrance", - units="c_ref") + io_chodura_lower = create_dynamic_variable!(dynamic, "chodura_integral_lower", mk_float, r, + n_ion_species_coord; + parallel_io=parallel_io, + description="Generalised Chodura integral lower sheath entrance", + units="c_ref") else io_chodura_lower = nothing end if parallel_io || z.irank == z.nrank - 1 # io_chodura_upper is the handle for the ion thermal speed - io_chodura_upper = create_dynamic_variable!(dynamic, "chodura_integral_upper", mk_float, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, - description="Generalised Chodura integral upper sheath entrance", - units="c_ref") + io_chodura_upper = create_dynamic_variable!(dynamic, "chodura_integral_upper", mk_float, r, + n_ion_species_coord; + parallel_io=parallel_io, + description="Generalised Chodura integral upper sheath entrance", + units="c_ref") else io_chodura_upper = nothing end if evolve_density || evolve_upar || evolve_ppar ion_constraints_A_coefficient = - create_dynamic_variable!(dynamic, "ion_constraints_A_coefficient", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, - description="'A' coefficient enforcing density constraint for ions") + create_dynamic_variable!(dynamic, "ion_constraints_A_coefficient", mk_float, + z, r, n_ion_species_coord; parallel_io=parallel_io, + description="'A' coefficient enforcing density constraint for ions") ion_constraints_B_coefficient = - create_dynamic_variable!(dynamic, "ion_constraints_B_coefficient", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, - description="'B' coefficient enforcing flow constraint for ions") + create_dynamic_variable!(dynamic, "ion_constraints_B_coefficient", mk_float, + z, r, n_ion_species_coord; parallel_io=parallel_io, + description="'B' coefficient enforcing flow constraint for ions") ion_constraints_C_coefficient = - create_dynamic_variable!(dynamic, "ion_constraints_C_coefficient", mk_float, z, r; - n_ion_species=n_ion_species, - parallel_io=parallel_io, - description="'C' coefficient enforcing pressure constraint for ions") + create_dynamic_variable!(dynamic, "ion_constraints_C_coefficient", mk_float, + z, r, n_ion_species_coord; parallel_io=parallel_io, + description="'C' coefficient enforcing pressure constraint for ions") else ion_constraints_A_coefficient = nothing ion_constraints_B_coefficient = nothing @@ -1449,9 +1505,9 @@ function define_dynamic_electron_moment_variables!(fid, r::coordinate, z::coordi if !electron_only_io # io_density is the handle for the ion particle density io_electron_density = create_dynamic_variable!(dynamic, "electron_density", mk_float, z, r; - parallel_io=parallel_io, - description="electron species density", - units="n_ref") + parallel_io=parallel_io, + description="electron species density", + units="n_ref") if write_error_diagnostics io_electron_density_loworder = create_dynamic_variable!(dynamic, "electron_density_loworder", mk_float, z, r; @@ -1473,9 +1529,9 @@ function define_dynamic_electron_moment_variables!(fid, r::coordinate, z::coordi # io_electron_upar is the handle for the electron parallel flow density io_electron_upar = create_dynamic_variable!(dynamic, "electron_parallel_flow", mk_float, z, r; - parallel_io=parallel_io, - description="electron species parallel flow", - units="c_ref = sqrt(2*T_ref/mi)") + parallel_io=parallel_io, + description="electron species parallel flow", + units="c_ref = sqrt(2*T_ref/mi)") if write_error_diagnostics io_electron_upar_loworder = create_dynamic_variable!(dynamic, "electron_parallel_flow_loworder", mk_float, z, @@ -1530,32 +1586,33 @@ function define_dynamic_electron_moment_variables!(fid, r::coordinate, z::coordi # io_electron_qpar is the handle for the electron parallel heat flux io_electron_qpar = create_dynamic_variable!(dynamic, "electron_parallel_heat_flux", mk_float, z, r; - parallel_io=parallel_io, - description="electron species parallel heat flux", - units="n_ref*T_ref*c_ref") + parallel_io=parallel_io, + description="electron species parallel heat flux", + units="n_ref*T_ref*c_ref") # io_electron_vth is the handle for the electron thermal speed io_electron_vth = create_dynamic_variable!(dynamic, "electron_thermal_speed", mk_float, z, r; - parallel_io=parallel_io, - description="electron species thermal speed", - units="c_ref") + parallel_io=parallel_io, + description="electron species thermal speed", + units="c_ref") electron_source_settings = external_source_settings.electron - if electron_source_settings.active + if any(x -> x.active, electron_source_settings) + n_sources = (name="n_electron_sources", n=length(electron_source_settings)) external_source_electron_amplitude = create_dynamic_variable!( - dynamic, "external_source_electron_amplitude", mk_float, z, r; + dynamic, "external_source_electron_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external source for electrons", units="n_ref/c_ref^3*c_ref/L_ref") external_source_electron_density_amplitude = create_dynamic_variable!( - dynamic, "external_source_electron_density_amplitude", mk_float, z, r; + dynamic, "external_source_electron_density_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external density source for electrons", units="n_ref*c_ref/L_ref") external_source_electron_momentum_amplitude = create_dynamic_variable!( - dynamic, "external_source_electron_momentum_amplitude", mk_float, z, r; + dynamic, "external_source_electron_momentum_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external momentum source for electrons", units="m_ref*n_ref*c_ref*c_ref/L_ref") external_source_electron_pressure_amplitude = create_dynamic_variable!( - dynamic, "external_source_electron_pressure_amplitude", mk_float, z, r; + dynamic, "external_source_electron_pressure_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external pressure source for electrons", units="m_ref*n_ref*c_ref^2*c_ref/L_ref") else @@ -1567,16 +1624,16 @@ function define_dynamic_electron_moment_variables!(fid, r::coordinate, z::coordi electron_constraints_A_coefficient = create_dynamic_variable!(dynamic, "electron_constraints_A_coefficient", mk_float, z, r; - parallel_io=parallel_io, - description="'A' coefficient enforcing density constraint for electrons") + parallel_io=parallel_io, + description="'A' coefficient enforcing density constraint for electrons") electron_constraints_B_coefficient = create_dynamic_variable!(dynamic, "electron_constraints_B_coefficient", mk_float, z, r; - parallel_io=parallel_io, - description="'B' coefficient enforcing flow constraint for electrons") + parallel_io=parallel_io, + description="'B' coefficient enforcing flow constraint for electrons") electron_constraints_C_coefficient = create_dynamic_variable!(dynamic, "electron_constraints_C_coefficient", mk_float, z, r; - parallel_io=parallel_io, - description="'C' coefficient enforcing pressure constraint for electrons") + parallel_io=parallel_io, + description="'C' coefficient enforcing pressure constraint for electrons") if electron_physics ∈ (kinetic_electrons, kinetic_electrons_with_temperature_equation) io_electron_step_counter = create_dynamic_variable!( @@ -1601,15 +1658,15 @@ function define_dynamic_electron_moment_variables!(fid, r::coordinate, z::coordi n_failure_vars = length(t_params.failure_caused_by) io_electron_failure_caused_by = create_dynamic_variable!( - dynamic, "electron_failure_caused_by", mk_int; - diagnostic_var_size=n_failure_vars, parallel_io=parallel_io, + dynamic, "electron_failure_caused_by", mk_int, + (name="n_failure_vars", n=n_failure_vars); parallel_io=parallel_io, description="cumulative count of how many times each variable caused an " * "electron pseudo-timestep failure for the run") n_limit_vars = length(t_params.limit_caused_by) io_electron_limit_caused_by = create_dynamic_variable!( - dynamic, "electron_limit_caused_by", mk_int; diagnostic_var_size=n_limit_vars, - parallel_io=parallel_io, + dynamic, "electron_limit_caused_by", mk_int, + (name="n_limit_vars", n=n_limit_vars); parallel_io=parallel_io, description="cumulative count of how many times each factor limited the " * "electron pseudo-timestep for the run") @@ -1652,18 +1709,18 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo evolve_ppar, write_error_diagnostics, write_steady_state_diagnostics) dynamic = get_group(fid, "dynamic_data") + n_neutral_species_coord = (name="n_neutral_species", n=n_neutral_species) # io_density_neutral is the handle for the neutral particle density - io_density_neutral = create_dynamic_variable!(dynamic, "density_neutral", mk_float, z, r; - n_neutral_species=n_neutral_species, + io_density_neutral = create_dynamic_variable!(dynamic, "density_neutral", mk_float, z, + r, n_neutral_species_coord; parallel_io=parallel_io, description="neutral species density", units="n_ref") if write_error_diagnostics io_density_neutral_loworder = - create_dynamic_variable!(dynamic, "density_neutral_loworder", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "density_neutral_loworder", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="low-order approximation to neutral species density, used to diagnose timestepping error", units="n_ref") else @@ -1671,9 +1728,8 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end if write_steady_state_diagnostics io_density_neutral_start_last_timestep = - create_dynamic_variable!(dynamic, "density_neutral_start_last_timestep", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "density_neutral_start_last_timestep", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species density at the start of the last timestep before output, used to measure steady state residual", units="n_ref") else @@ -1681,16 +1737,15 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end # io_uz_neutral is the handle for the neutral z momentum density - io_uz_neutral = create_dynamic_variable!(dynamic, "uz_neutral", mk_float, z, r; - n_neutral_species=n_neutral_species, + io_uz_neutral = create_dynamic_variable!(dynamic, "uz_neutral", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species mean z velocity", units="c_ref = sqrt(2*T_ref/mi)") if write_error_diagnostics io_uz_neutral_loworder = - create_dynamic_variable!(dynamic, "uz_neutral_loworder", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "uz_neutral_loworder", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="low-order approximation to neutral species mean z velocity, used to diagnose timestepping error", units="c_ref = sqrt(2*T_ref/mi)") else @@ -1698,8 +1753,8 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end if write_steady_state_diagnostics io_uz_neutral_start_last_timestep = - create_dynamic_variable!(dynamic, "uz_neutral_start_last_timestep", mk_float, z, r; - n_neutral_species=n_neutral_species, + create_dynamic_variable!(dynamic, "uz_neutral_start_last_timestep", mk_float, + z, r, n_neutral_species_coord; parallel_io=parallel_io, description="neutral species mean z velocity at the start of the last timestep before output, used to measure steady state residual", units="c_ref = sqrt(2*T_ref/mi)") @@ -1708,16 +1763,15 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end # io_pz_neutral is the handle for the neutral species zz pressure - io_pz_neutral = create_dynamic_variable!(dynamic, "pz_neutral", mk_float, z, r; - n_neutral_species=n_neutral_species, + io_pz_neutral = create_dynamic_variable!(dynamic, "pz_neutral", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species mean zz pressure", units="n_ref*T_ref") if write_error_diagnostics io_pz_neutral_loworder = - create_dynamic_variable!(dynamic, "pz_neutral_loworder", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, + create_dynamic_variable!(dynamic, "pz_neutral_loworder", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="low-order approximation to neutral species mean zz pressure, used to diagnose timestepping error", units="n_ref*T_ref") else @@ -1725,8 +1779,8 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end if write_steady_state_diagnostics io_pz_neutral_start_last_timestep = - create_dynamic_variable!(dynamic, "pz_neutral_start_last_timestep", mk_float, z, r; - n_neutral_species=n_neutral_species, + create_dynamic_variable!(dynamic, "pz_neutral_start_last_timestep", mk_float, + z, r, n_neutral_species_coord; parallel_io=parallel_io, description="neutral species mean zz pressure at the start of the last timestep before output, used to measure steady state residual", units="n_ref*T_ref") @@ -1735,28 +1789,28 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end # io_qz_neutral is the handle for the neutral z heat flux - io_qz_neutral = create_dynamic_variable!(dynamic, "qz_neutral", mk_float, z, r; - n_neutral_species=n_neutral_species, + io_qz_neutral = create_dynamic_variable!(dynamic, "qz_neutral", mk_float, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species z heat flux", units="n_ref*T_ref*c_ref") # io_thermal_speed_neutral is the handle for the neutral thermal speed io_thermal_speed_neutral = create_dynamic_variable!( - dynamic, "thermal_speed_neutral", mk_float, z, r; - n_neutral_species=n_neutral_species, + dynamic, "thermal_speed_neutral", mk_float, z, r, n_neutral_species_coord; parallel_io=parallel_io, description="neutral species thermal speed", units="c_ref") neutral_source_settings = external_source_settings.neutral - if n_neutral_species > 0 && neutral_source_settings.active + if n_neutral_species > 0 && any(x -> x.active, neutral_source_settings) + n_sources = (name="n_neutral_sources", n=length(neutral_source_settings)) external_source_neutral_amplitude = create_dynamic_variable!( - dynamic, "external_source_neutral_amplitude", mk_float, z, r; + dynamic, "external_source_neutral_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external source for neutrals", units="n_ref/c_ref^3*c_ref/L_ref") if evolve_density external_source_neutral_density_amplitude = create_dynamic_variable!( - dynamic, "external_source_neutral_density_amplitude", mk_float, z, r; + dynamic, "external_source_neutral_density_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external density source for neutrals", units="n_ref*c_ref/L_ref") else @@ -1764,7 +1818,7 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end if evolve_upar external_source_neutral_momentum_amplitude = create_dynamic_variable!( - dynamic, "external_source_neutral_momentum_amplitude", mk_float, z, r; + dynamic, "external_source_neutral_momentum_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external momentum source for neutrals", units="m_ref*n_ref*c_ref*c_ref/L_ref") else @@ -1772,17 +1826,17 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo end if evolve_ppar external_source_neutral_pressure_amplitude = create_dynamic_variable!( - dynamic, "external_source_neutral_pressure_amplitude", mk_float, z, r; + dynamic, "external_source_neutral_pressure_amplitude", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Amplitude of the external pressure source for neutrals", units="m_ref*n_ref*c_ref^2*c_ref/L_ref") else external_source_neutral_pressure_amplitude = nothing end - if neutral_source_settings.PI_density_controller_I != 0.0 && - neutral_source_settings.source_type ∈ ("density_profile_control", "density_midpoint_control") - if neutral_source_settings.source_type == "density_profile_control" + if any(x -> x.PI_density_controller_I != 0.0 && x.source_type ∈ + ("density_profile_control", "density_midpoint_control"), neutral_source_settings) + if any(x -> x.source_type == "density_profile_control", neutral_source_settings) external_source_neutral_controller_integral = create_dynamic_variable!( - dynamic, "external_source_neutral_controller_integral", mk_float, z, r; + dynamic, "external_source_neutral_controller_integral", mk_float, z, r, n_sources; parallel_io=parallel_io, description="Integral term for the PID controller of the external source for neutrals") else @@ -1804,20 +1858,20 @@ function define_dynamic_neutral_moment_variables!(fid, n_neutral_species, r::coo if evolve_density || evolve_upar || evolve_ppar neutral_constraints_A_coefficient = - create_dynamic_variable!(dynamic, "neutral_constraints_A_coefficient", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, - description="'A' coefficient enforcing density constraint for neutrals") + create_dynamic_variable!(dynamic, "neutral_constraints_A_coefficient", + mk_float, z, r, n_neutral_species_coord; + parallel_io=parallel_io, + description="'A' coefficient enforcing density constraint for neutrals") neutral_constraints_B_coefficient = - create_dynamic_variable!(dynamic, "neutral_constraints_B_coefficient", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, - description="'B' coefficient enforcing flow constraint for neutrals") + create_dynamic_variable!(dynamic, "neutral_constraints_B_coefficient", + mk_float, z, r, n_neutral_species_coord; + parallel_io=parallel_io, + description="'B' coefficient enforcing flow constraint for neutrals") neutral_constraints_C_coefficient = - create_dynamic_variable!(dynamic, "neutral_constraints_C_coefficient", mk_float, z, r; - n_neutral_species=n_neutral_species, - parallel_io=parallel_io, - description="'C' coefficient enforcing pressure constraint for neutrals") + create_dynamic_variable!(dynamic, "neutral_constraints_C_coefficient", + mk_float, z, r, n_neutral_species_coord; + parallel_io=parallel_io, + description="'C' coefficient enforcing pressure constraint for neutrals") else neutral_constraints_A_coefficient = nothing neutral_constraints_B_coefficient = nothing @@ -1856,16 +1910,15 @@ function define_dynamic_dfn_variables!(fid, r, z, vperp, vpa, vzeta, vr, vz, com nl_solver_params) dynamic = get_group(fid, "dynamic_data") + n_ion_species_coord = (name="n_ion_species", n=composition.n_ion_species) # io_f is the handle for the ion pdf - io_f = create_dynamic_variable!(dynamic, "f", mk_float, vpa, vperp, z, r; - n_ion_species=composition.n_ion_species, - parallel_io=parallel_io, + io_f = create_dynamic_variable!(dynamic, "f", mk_float, vpa, vperp, z, r, + n_ion_species_coord; parallel_io=parallel_io, description="ion species distribution function") if io_input.write_error_diagnostics io_f_loworder = create_dynamic_variable!(dynamic, "f_loworder", mk_float, vpa, - vperp, z, r; - n_ion_species=composition.n_ion_species, + vperp, z, r, n_ion_species_coord; parallel_io=parallel_io, description="low-order approximation to ion species distribution function, used to diagnose timestepping error") else @@ -1874,8 +1927,7 @@ function define_dynamic_dfn_variables!(fid, r, z, vperp, vpa, vzeta, vr, vz, com if io_input.write_steady_state_diagnostics io_f_start_last_timestep = create_dynamic_variable!(dynamic, "f_start_last_timestep", mk_float, vpa, - vperp, z, r; - n_ion_species=composition.n_ion_species, + vperp, z, r, n_ion_species_coord; parallel_io=parallel_io, description="ion species distribution function at the start of the last timestep before output, used to measure steady state residual") else @@ -1913,16 +1965,17 @@ function define_dynamic_dfn_variables!(fid, r, z, vperp, vpa, vzeta, vr, vz, com io_f_electron_start_last_timestep = nothing end + n_neutral_species_coord = (name="n_neutral_species", n=composition.n_neutral_species) + # io_f_neutral is the handle for the neutral pdf - io_f_neutral = create_dynamic_variable!(dynamic, "f_neutral", mk_float, vz, vr, vzeta, z, r; - n_neutral_species=composition.n_neutral_species, + io_f_neutral = create_dynamic_variable!(dynamic, "f_neutral", mk_float, vz, vr, vzeta, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species distribution function") if io_input.write_error_diagnostics io_f_neutral_loworder = create_dynamic_variable!(dynamic, "f_neutral_loworder", mk_float, vz, vr, - vzeta, z, r; - n_ion_species=composition.n_ion_species, + vzeta, z, r, n_neutral_species_coord; parallel_io=parallel_io, description="low-order approximation to neutral species distribution function, used to diagnose timestepping error") else @@ -1931,9 +1984,8 @@ function define_dynamic_dfn_variables!(fid, r, z, vperp, vpa, vzeta, vr, vz, com if io_input.write_steady_state_diagnostics io_f_neutral_start_last_timestep = create_dynamic_variable!(dynamic, "f_neutral_start_last_timestep", - mk_float, vz, vr, vzeta, z, r; - n_ion_species=composition.n_ion_species, - parallel_io=parallel_io, + mk_float, vz, vr, vzeta, z, r, + n_neutral_species_coord; parallel_io=parallel_io, description="neutral species distribution function at the start of the last timestep before output, used to measure steady state residual") else io_f_neutral_start_last_timestep = nothing @@ -1943,7 +1995,7 @@ function define_dynamic_dfn_variables!(fid, r, z, vperp, vpa, vzeta, vr, vz, com io_f_electron, io_f_electron_loworder, io_f_electron_start_last_timestep, io_f_neutral, io_f_neutral_loworder, io_f_neutral_start_last_timestep, - parallel_io, io_moments) + io_input, io_moments) end # For processes other than the root process of each shared-memory group... @@ -2508,34 +2560,35 @@ function write_ion_moments_data_to_binary(scratch, moments, n_ion_species, t_par parallel_io, 0, n_ion_species) end if io_moments.external_source_amplitude !== nothing + n_sources = size(moments.ion.external_source_amplitude)[3] append_to_dynamic_var(io_moments.external_source_amplitude, moments.ion.external_source_amplitude, t_idx, - parallel_io, z, r) + parallel_io, z, r, n_sources) if moments.evolve_density append_to_dynamic_var(io_moments.external_source_density_amplitude, moments.ion.external_source_density_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end if moments.evolve_upar append_to_dynamic_var(io_moments.external_source_momentum_amplitude, moments.ion.external_source_momentum_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end if moments.evolve_ppar append_to_dynamic_var(io_moments.external_source_pressure_amplitude, moments.ion.external_source_pressure_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end end if io_moments.external_source_controller_integral !== nothing - if size(moments.ion.external_source_controller_integral) == (1,1) + if size(moments.ion.external_source_controller_integral) == (1,1, n_sources) append_to_dynamic_var(io_moments.external_source_controller_integral, - moments.ion.external_source_controller_integral[1,1], + moments.ion.external_source_controller_integral, t_idx, parallel_io) else append_to_dynamic_var(io_moments.external_source_controller_integral, moments.ion.external_source_controller_integral, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end end if moments.evolve_density || moments.evolve_upar || moments.evolve_ppar @@ -2606,18 +2659,19 @@ function write_electron_moments_data_to_binary(scratch, moments, t_params, elect append_to_dynamic_var(io_moments.electron_thermal_speed, moments.electron.vth, t_idx, parallel_io, z, r) if io_moments.external_source_electron_amplitude !== nothing + n_sources = size(moments.electron.external_source_amplitude)[3] append_to_dynamic_var(io_moments.external_source_electron_amplitude, moments.electron.external_source_amplitude, t_idx, - parallel_io, z, r) + parallel_io, z, r, n_sources) append_to_dynamic_var(io_moments.external_source_electron_density_amplitude, moments.electron.external_source_density_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) append_to_dynamic_var(io_moments.external_source_electron_momentum_amplitude, moments.electron.external_source_momentum_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) append_to_dynamic_var(io_moments.external_source_electron_pressure_amplitude, moments.electron.external_source_pressure_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end append_to_dynamic_var(io_moments.electron_constraints_A_coefficient, moments.electron.constraints_A_coefficient, t_idx, @@ -2718,29 +2772,30 @@ function write_neutral_moments_data_to_binary(scratch, moments, n_neutral_specie append_to_dynamic_var(io_moments.thermal_speed_neutral, moments.neutral.vth, t_idx, parallel_io, z, r, n_neutral_species) if io_moments.external_source_neutral_amplitude !== nothing + n_sources = size(moments.neutral.external_source_amplitude)[3] append_to_dynamic_var(io_moments.external_source_neutral_amplitude, moments.neutral.external_source_amplitude, t_idx, - parallel_io, z, r) + parallel_io, z, r, n_sources) if moments.evolve_density append_to_dynamic_var(io_moments.external_source_neutral_density_amplitude, moments.neutral.external_source_density_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end if moments.evolve_upar append_to_dynamic_var(io_moments.external_source_neutral_momentum_amplitude, moments.neutral.external_source_momentum_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end if moments.evolve_ppar append_to_dynamic_var(io_moments.external_source_neutral_pressure_amplitude, moments.neutral.external_source_pressure_amplitude, - t_idx, parallel_io, z, r) + t_idx, parallel_io, z, r, n_sources) end end if io_moments.external_source_neutral_controller_integral !== nothing if size(moments.neutral.external_source_neutral_controller_integral) == (1,1) append_to_dynamic_var(io_moments.external_source_neutral_controller_integral, - moments.neutral.external_source_controller_integral[1,1], + moments.neutral.external_source_controller_integral, t_idx, parallel_io) else append_to_dynamic_var(io_moments.external_source_neutral_controller_integral, @@ -2993,21 +3048,32 @@ include("file_io_hdf5.jl") """ """ -function write_data_to_ascii(pdf, moments, fields, vpa, vperp, z, r, t, n_ion_species, - n_neutral_species, ascii_io::Union{ascii_ios,Nothing}) +function write_data_to_ascii(pdf, moments, fields, vz, vr, vzeta, vpa, vperp, z, r, t, + n_ion_species, n_neutral_species, + ascii_io::Union{ascii_ios,Nothing}) if ascii_io === nothing || ascii_io.moments_ion === nothing # ascii I/O is disabled return nothing end + if r.n > 1 || vperp.n > 1 || vzeta.n > 1 || vr.n > 1 + error("Ascii I/O is only implemented for 1D1V case") + end + if vz.n != vpa.n + error("ASCII I/O is only implemented when vz.n($(vz.n))==vpa.n($(vpa.n))") + end + if n_neutral_species != n_ion_species + error("ASCII I/O is only implemented when n_neutral_species($(n_neutral_species))==n_ion_species($(n_ion_species))") + end + @serial_region begin # Only read/write from first process in each 'block' - write_f_ascii(pdf, z, vpa, t, ascii_io.ff) + @views write_f_ascii(pdf, z, vpa, t, ascii_io.ff) write_moments_ion_ascii(moments.ion, z, r, t, n_ion_species, ascii_io.moments_ion) write_moments_electron_ascii(moments.electron, z, r, t, ascii_io.moments_electron) if n_neutral_species > 0 - write_moments_neutral_ascii(moments.neutral, z, r, t, n_neutral_species, ascii_io.moments_neutral) + @views write_moments_neutral_ascii(moments.neutral, z, r, t, n_neutral_species, ascii_io.moments_neutral) end write_fields_ascii(fields, z, r, t, ascii_io.fields) end @@ -3024,11 +3090,11 @@ function write_f_ascii(f, z, vpa, t, ascii_io) @inbounds begin #n_species = size(f,3) #for is ∈ 1:n_species - for j ∈ 1:vpa.n - for i ∈ 1:z.n + for i ∈ 1:z.n + for j ∈ 1:vpa.n println(ascii_io,"t: ", t, " z: ", z.grid[i], - " vpa: ", vpa.grid[j], " fion: ", f.ion.norm[i,j,1], - " fneutral: ", f.neutral.norm[i,j,1]) + " vpa: ", vpa.grid[j], " fion: ", f.ion.norm[j,1,i,1,1], + " fneutral: ", f.neutral.norm[j,1,1,i,1,1]) end println(ascii_io) end diff --git a/moment_kinetics/src/file_io_hdf5.jl b/moment_kinetics/src/file_io_hdf5.jl index 271d79fee..5cb1e4a1f 100644 --- a/moment_kinetics/src/file_io_hdf5.jl +++ b/moment_kinetics/src/file_io_hdf5.jl @@ -11,7 +11,10 @@ function open_output_file_implementation(::Val{hdf5}, prefix, io_input, io_comm, # the hdf5 file will be given by output_dir/run_name with .h5 appended filename = string(prefix, ".h5") - if length(filename) > 255 + # JTO thought the maximum filename length should be 255 according to HDF5.jl, but can + # no longer find the HDF5.jl check for length. However on one test a filename of + # length 245 caused a crash, while 243 was OK, so limit to 243. + if length(filename) > 243 error("Length of filename '$filename' is too long ($(length(filename)) " * "characters), which will cause an error in HDF5.") end @@ -85,8 +88,7 @@ end # HDF5.H5DataStore is the supertype for HDF5.File and HDF5.Group function write_single_value!(file_or_group::HDF5.H5DataStore, name, data::Union{Number, AbstractString, AbstractArray{T,N}}, - coords::Union{coordinate,mk_int}...; parallel_io, - n_ion_species=nothing, n_neutral_species=nothing, + coords::Union{coordinate,mk_int,NamedTuple}...; parallel_io, description=nothing, units=nothing) where {T,N} if isa(data, Union{Number, AbstractString}) file_or_group[name] = data @@ -99,32 +101,18 @@ function write_single_value!(file_or_group::HDF5.H5DataStore, name, return nothing end - if n_ion_species !== nothing && n_neutral_species != nothing - error("Cannot have both ion-species and neutral species dimensions." * - "Got n_ion_species=$n_ion_species, n_neutral_species=$n_neutral_species") + if any(isa(c, mk_int) ? c < 0 : c.n < 0 for c ∈ coords) + error("Got a negative `n` in $coords") end - - if n_ion_species !== nothing - if n_ion_species < 0 - error("n_ion_species must be non-negative, got $n_ion_species") - elseif n_ion_species == 0 - # No data to write - return nothing - end - coords = tuple(coords..., n_ion_species) - elseif n_neutral_species !== nothing - if n_neutral_species < 0 - error("n_neutral_species must be non-negative, got $n_neutral_species") - elseif n_neutral_species == 0 - # No data to write - return nothing - end - coords = tuple(coords..., n_neutral_species) + if any(isa(c, mk_int) ? c == 0 : c.n == 0 for c ∈ coords) + # No data to write + return nothing end + dim_sizes, chunk_sizes = hdf5_get_fixed_dim_sizes(coords, parallel_io) io_var = create_dataset(file_or_group, name, T, dim_sizes, chunk=chunk_sizes) - local_ranges = Tuple(isa(c, mk_int) ? (1:c) : c.local_io_range for c ∈ coords) - global_ranges = Tuple(isa(c, mk_int) ? (1:c) : c.global_io_range for c ∈ coords) + local_ranges = Tuple(isa(c, mk_int) ? (1:c) : isa(c, coordinate) ? c.local_io_range : c.n for c ∈ coords) + global_ranges = Tuple(isa(c, mk_int) ? (1:c) : isa(c, coordinate) ? c.global_io_range : c.n for c ∈ coords) if N == 1 io_var[global_ranges[1]] = @view data[local_ranges[1]] @@ -176,7 +164,7 @@ of species). """ function hdf5_get_fixed_dim_sizes(coords, parallel_io) if parallel_io - dim_sizes = Tuple(isa(c, mk_int) ? c : c.n_global for c in coords) + dim_sizes = Tuple(isa(c, mk_int) ? c : (isa(c, coordinate) ? c.n_global : c.n) for c in coords) else dim_sizes = Tuple(isa(c, mk_int) ? c : c.n for c in coords) end @@ -209,65 +197,24 @@ function hdf5_get_dynamic_dim_sizes(fixed_coords, parallel_io) end function create_dynamic_variable!(file_or_group::HDF5.H5DataStore, name, type, - coords::coordinate...; parallel_io, - n_ion_species=nothing, n_neutral_species=nothing, - diagnostic_var_size=nothing, description=nothing, - units=nothing) - - if n_ion_species !== nothing && n_neutral_species !== nothing - error("Variable should not contain both ion and neutral species dimensions. " - * "Got n_ion_species=$n_ion_species and " - * "n_neutral_species=$n_neutral_species") - end - if diagnostic_var_size !== nothing && n_ion_species !== nothing - error("Diagnostic variable should not contain both ion species dimension. Got " - * "diagnostic_var_size=$diagnostic_var_size and " - * "n_ion_species=$n_ion_species") + coords::Union{coordinate,NamedTuple}...; parallel_io, + description=nothing, units=nothing) + + if any(isa(c, mk_int) ? c < 0 : c.n < 0 for c ∈ coords) + error("Got a negative `n` in $coords") end - if diagnostic_var_size !== nothing && n_neutral_species !== nothing - error("Diagnostic variable should not contain both neutral species dimension. " - * "Got diagnostic_var_size=$diagnostic_var_size and " - * "n_neutral_species=$n_neutral_species") + if any(isa(c, mk_int) ? c == 0 : c.n == 0 for c ∈ coords) + # No data to write + return nothing end - # Add the number of species to the spatial/velocity-space coordinates - if diagnostic_var_size !== nothing - if isa(diagnostic_var_size, Number) - # Make diagnostic_var_size a Tuple - diagnostic_var_size = (diagnostic_var_size,) - end - fixed_coords = diagnostic_var_size - elseif n_ion_species !== nothing - if n_ion_species < 0 - error("n_ion_species must be non-negative, got $n_ion_species") - elseif n_ion_species == 0 - # No data to write - return nothing - end - fixed_coords = tuple(coords..., n_ion_species) - elseif n_neutral_species !== nothing - if n_neutral_species < 0 - error("n_neutral_species must be non-negative, got $n_neutral_species") - elseif n_neutral_species == 0 - # No data to write - return nothing - end - fixed_coords = tuple(coords..., n_neutral_species) - else - fixed_coords = coords - end initial_dim_sizes, max_dim_sizes, chunk_size = - hdf5_get_dynamic_dim_sizes(fixed_coords, parallel_io) + hdf5_get_dynamic_dim_sizes(coords, parallel_io) var = create_dataset(file_or_group, name, type, (initial_dim_sizes, max_dim_sizes), chunk=chunk_size) # Add attribute listing the dimensions belonging to this variable dim_names = Tuple(c.name for c ∈ coords) - if n_ion_species !== nothing - dim_names = tuple(dim_names..., "ion_species") - elseif n_neutral_species !== nothing - dim_names = tuple(dim_names..., "neutral_species") - end add_attribute!(var, "dims", join(dim_names, ",")) if description !== nothing diff --git a/moment_kinetics/src/finite_differences.jl b/moment_kinetics/src/finite_differences.jl index ae18c7d7d..cc2d9583b 100644 --- a/moment_kinetics/src/finite_differences.jl +++ b/moment_kinetics/src/finite_differences.jl @@ -36,11 +36,11 @@ end elementwise_derivative!(coord, f, adv_fac, not_spectral::finite_difference_info) Calculate the derivative of f using finite differences, with particular scheme -specified by coord.fd_option; result stored in coord.scratch_2d. +specified by coord.finite_difference_option; result stored in coord.scratch_2d. """ function elementwise_derivative!(coord, f, adv_fac, not_spectral::finite_difference_info) return derivative_finite_difference!(coord.scratch_2d, f, coord.cell_width, adv_fac, - coord.bc, coord.fd_option, coord.igrid, coord.ielement) + coord.bc, coord.finite_difference_option, coord.igrid, coord.ielement) end """ @@ -79,18 +79,19 @@ end """ """ -function derivative_finite_difference!(df, f, del, adv_fac, bc, fd_option, igrid, ielement) - if fd_option == "second_order_upwind" +function derivative_finite_difference!(df, f, del, adv_fac, bc, finite_difference_option, + igrid, ielement) + if finite_difference_option == "second_order_upwind" upwind_second_order!(df, f, del, adv_fac, bc, igrid, ielement) - elseif fd_option == "third_order_upwind" + elseif finite_difference_option == "third_order_upwind" upwind_third_order!(df, f, del, adv_fac, bc, igrid, ielement) - elseif fd_option == "fourth_order_upwind" + elseif finite_difference_option == "fourth_order_upwind" upwind_fourth_order!(df, f, del, bc, igrid, ielement) - elseif fd_option == "second_order_centered" + elseif finite_difference_option == "second_order_centered" centered_second_order!(df, f, del, bc, igrid, ielement) - elseif fd_option == "fourth_order_centered" + elseif finite_difference_option == "fourth_order_centered" centered_fourth_order!(df, f, del, bc, igrid, ielement) - elseif fd_option == "first_order_upwind" + elseif finite_difference_option == "first_order_upwind" upwind_first_order!(df, f, del, adv_fac, bc, igrid, ielement) end # have not filled df array values for the first grid point in each element @@ -110,10 +111,11 @@ end """ """ -function derivative_finite_difference!(df, f, del, bc, fd_option, igrid, ielement) - if fd_option == "fourth_order_centered" +function derivative_finite_difference!(df, f, del, bc, finite_difference_option, igrid, + ielement) + if finite_difference_option == "fourth_order_centered" centered_fourth_order!(df, f, del, bc, igrid, ielement) - elseif fd_option == "second_order_centered" + elseif finite_difference_option == "second_order_centered" centered_second_order!(df, f, del, bc, igrid, ielement) end return nothing diff --git a/moment_kinetics/src/force_balance.jl b/moment_kinetics/src/force_balance.jl index 902c3901e..9f94d0dbd 100644 --- a/moment_kinetics/src/force_balance.jl +++ b/moment_kinetics/src/force_balance.jl @@ -29,11 +29,13 @@ function force_balance!(pflx, density_out, fvec, moments, fields, collisions, dt 0.5*geometry.bzed[iz,ir]*fields.Ez[iz,ir]*density[iz,ir,is]) end - if ion_source_settings.active && false - source_amplitude = moments.ion.external_source_momentum_amplitude - @loop_s_r_z is ir iz begin - pflx[iz,ir,is] += - dt * source_amplitude[iz,ir] + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active && false + @views source_amplitude = moments.ion.external_source_momentum_amplitude[:, :, index] + @loop_s_r_z is ir iz begin + pflx[iz,ir,is] += + dt * source_amplitude[iz,ir] + end end end @@ -48,15 +50,17 @@ function force_balance!(pflx, density_out, fvec, moments, fields, collisions, dt # if neutrals present account for charge exchange and/or ionization collisions if composition.n_neutral_species > 0 # account for collisional friction between ions and neutrals - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 @loop_s_r_z is ir iz begin - pflx[iz,ir,is] += dt*collisions.charge_exchange*density[iz,ir,is]*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-upar[iz,ir,is]) + pflx[iz,ir,is] += dt*charge_exchange*density[iz,ir,is]*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-upar[iz,ir,is]) end end # account for ionization collisions - if abs(collisions.ionization) > 0.0 + if abs(ionization) > 0.0 @loop_s_r_z is ir iz begin - pflx[iz,ir,is] += dt*collisions.ionization*density[iz,ir,is]*fvec.density_neutral[iz,ir,is]*fvec.uz_neutral[iz,ir,is] + pflx[iz,ir,is] += dt*ionization*density[iz,ir,is]*fvec.density_neutral[iz,ir,is]*fvec.uz_neutral[iz,ir,is] end end end @@ -83,11 +87,13 @@ function neutral_force_balance!(pflx, density_out, fvec, moments, fields, collis 2.0*density[iz,ir,isn]*uz[iz,ir,isn]*moments.neutral.duz_dz_upwind[iz,ir,isn]) end - if neutral_source_settings.active && false - source_amplitude = moments.neutral.external_source_momentum_amplitude - @loop_sn_r_z isn ir iz begin - pflx[iz,ir,isn] += - dt * source_amplitude[iz,ir] + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active && false + @views source_amplitude = moments.neutral.external_source_momentum_amplitude[:, :, index] + @loop_sn_r_z isn ir iz begin + pflx[iz,ir,isn] += + dt * source_amplitude[iz,ir] + end end end @@ -102,15 +108,17 @@ function neutral_force_balance!(pflx, density_out, fvec, moments, fields, collis # if neutrals present account for charge exchange and/or ionization collisions if composition.n_neutral_species > 0 # account for collisional friction between ions and neutrals - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 @loop_sn_r_z isn ir iz begin - pflx[iz,ir,isn] += dt*collisions.charge_exchange*density[iz,ir,isn]*fvec.density[iz,ir,isn]*(fvec.upar[iz,ir,isn]-uz[iz,ir,isn]) + pflx[iz,ir,isn] += dt*charge_exchange*density[iz,ir,isn]*fvec.density[iz,ir,isn]*(fvec.upar[iz,ir,isn]-uz[iz,ir,isn]) end end # account for ionization collisions - if abs(collisions.ionization) > 0.0 + if abs(ionization) > 0.0 @loop_sn_r_z isn ir iz begin - pflx[iz,ir,isn] -= dt*collisions.ionization*fvec.density[iz,ir,isn]*density[iz,ir,isn]*uz[iz,ir,isn] + pflx[iz,ir,isn] -= dt*ionization*fvec.density[iz,ir,isn]*density[iz,ir,isn]*uz[iz,ir,isn] end end end diff --git a/moment_kinetics/src/gauss_legendre.jl b/moment_kinetics/src/gauss_legendre.jl index 9a0afb6b3..7d4b5f2e1 100644 --- a/moment_kinetics/src/gauss_legendre.jl +++ b/moment_kinetics/src/gauss_legendre.jl @@ -82,7 +82,7 @@ struct gausslegendre_base_info Y31::Array{mk_float,3} end -struct gausslegendre_info{TSparse, TLU} <: weak_discretization_info +struct gausslegendre_info{TSparse, TLU, TLmat, TLmatLU} <: weak_discretization_info lobatto::gausslegendre_base_info radau::gausslegendre_base_info # global (1D) mass matrix @@ -94,13 +94,19 @@ struct gausslegendre_info{TSparse, TLU} <: weak_discretization_info K_matrix::TSparse # global (1D) weak Laplacian derivative matrix L_matrix::TSparse - # global (1D) LU object + # global (1D) weak Laplacian derivative matrix with boundary conditions - might be + # `nothing` if boundary conditions are not supported + L_matrix_with_bc::TLmat + # mass matrix global (1D) LU object mass_matrix_lu::TLU + # Laplacian global (1D) LU object - might be + # `nothing` if boundary conditions are not supported + L_matrix_lu::TLmatLU # dummy matrix for local operators Qmat::Array{mk_float,2} end -function setup_gausslegendre_pseudospectral(coord; collision_operator_dim=true, dirichlet_bc=false) +function setup_gausslegendre_pseudospectral(coord; collision_operator_dim=true) lobatto = setup_gausslegendre_pseudospectral_lobatto(coord,collision_operator_dim=collision_operator_dim) radau = setup_gausslegendre_pseudospectral_radau(coord,collision_operator_dim=collision_operator_dim) @@ -114,13 +120,34 @@ function setup_gausslegendre_pseudospectral(coord; collision_operator_dim=true, K_matrix = allocate_float(coord.n,coord.n) L_matrix = allocate_float(coord.n,coord.n) - setup_global_weak_form_matrix!(mass_matrix, lobatto, radau, coord, "M"; dirichlet_bc=dirichlet_bc) - setup_global_weak_form_matrix!(K_matrix, lobatto, radau, coord, "K_with_BC_terms"; dirichlet_bc=dirichlet_bc) - setup_global_weak_form_matrix!(L_matrix, lobatto, radau, coord, "L_with_BC_terms"; dirichlet_bc=dirichlet_bc) + dirichlet_bc = (coord.bc in ["zero", "constant"]) # and further options in future + periodic_bc = (coord.bc == "periodic") + setup_global_weak_form_matrix!(mass_matrix, lobatto, radau, coord, "M"; periodic_bc=periodic_bc) + setup_global_weak_form_matrix!(K_matrix, lobatto, radau, coord, "K_with_BC_terms"; periodic_bc=periodic_bc) + setup_global_weak_form_matrix!(L_matrix, lobatto, radau, coord, "L_with_BC_terms") mass_matrix_lu = lu(sparse(mass_matrix)) + if dirichlet_bc || periodic_bc + L_matrix_with_bc = allocate_float(coord.n,coord.n) + setup_global_weak_form_matrix!(L_matrix_with_bc, lobatto, radau, coord, "L", dirichlet_bc=dirichlet_bc, periodic_bc=periodic_bc) + L_matrix_with_bc = sparse(L_matrix_with_bc ) + L_matrix_lu = lu(sparse(L_matrix_with_bc)) + else + L_matrix_with_bc = nothing + L_matrix_lu = nothing + end + Qmat = allocate_float(coord.ngrid,coord.ngrid) - return gausslegendre_info(lobatto,radau,mass_matrix,sparse(S_matrix),sparse(K_matrix),sparse(L_matrix),mass_matrix_lu,Qmat) + return gausslegendre_info(lobatto,radau,mass_matrix,sparse(S_matrix),sparse(K_matrix),sparse(L_matrix),L_matrix_with_bc, + mass_matrix_lu,L_matrix_lu,Qmat) +end + +function identity_matrix!(I,n) + @. I[:,:] = 0.0 + for i in 1:n + I[i,i] = 1.0 + end + return nothing end function setup_gausslegendre_pseudospectral_lobatto(coord; collision_operator_dim=true) @@ -820,70 +847,58 @@ The 'option' variable is a flag for choosing the type of matrix to be constructed. Currently the function is set up to assemble the elemental matrices without imposing boundary conditions on the -first and final rows of the matrix. This means that +first and final rows of the matrix by default. This means that the operators constructed from this function can only be used -for differentiation, and not solving 1D ODEs. -The shared points in the element assembly are -averaged (instead of simply added) to be consistent with the -derivative_elements_to_full_grid!() function in calculus.jl, -which is used to form the RHS of the equation +for differentiation, and not solving 1D ODEs. +This assembly function assumes that the +coordinate is not distributed. To extend this function to support +distributed-memory MPI, addition of off-memory matrix elements +to the exterior points would be required. + +The typical use of this function is to assemble matrixes M and K in M * d2f = K * f -where M is the mass matrix and K is the stiffness matrix. +where M is the mass matrix and K is the stiffness matrix, and we wish to +solve for d2f given f. To solve 1D ODEs + +K * f = b = M * d2f + +for f given boundary data on f +with periodic or dirichlet boundary conditions, set + +`periodic_bc = true`, `b[end] = 0` + +or + +`dirichlet_bc = true`, `b[1] = f[1]` (except for cylindrical coordinates), `b[end] = f[end]` + +in the function call, and create new matrices for this purpose +in the gausslegendre_info struct. Currently the Laplacian matrix +is supported with boundary conditions. """ function setup_global_weak_form_matrix!(QQ_global::Array{mk_float,2}, lobatto::gausslegendre_base_info, radau::gausslegendre_base_info, - coord,option; dirichlet_bc=false) + coord,option; dirichlet_bc=false, periodic_bc=false) QQ_j = allocate_float(coord.ngrid,coord.ngrid) - QQ_jp1 = allocate_float(coord.ngrid,coord.ngrid) ngrid = coord.ngrid imin = coord.imin imax = coord.imax @. QQ_global = 0.0 - # fill in first element - j = 1 - # N.B. QQ varies with ielement for vperp, but not vpa - # a radau element is used for the vperp grid (see get_QQ_local!()) - get_QQ_local!(QQ_j,j,lobatto,radau,coord,option) - if coord.bc == "periodic" && coord.nrank == 1 - QQ_global[imax[end], imin[j]:imax[j]] .+= QQ_j[1,:] ./ 2.0 - QQ_global[imin[j],imin[j]:imax[j]] .+= QQ_j[1,:] ./ 2.0 - else - QQ_global[imin[j],imin[j]:imax[j]] .+= QQ_j[1,:] - end - for k in 2:imax[j]-imin[j] - QQ_global[k,imin[j]:imax[j]] .+= QQ_j[k,:] - end - if coord.nelement_local > 1 || (coord.bc == "periodic" && coord.nrank == 1) - QQ_global[imax[j],imin[j]:imax[j]] .+= QQ_j[ngrid,:]./2.0 - else - QQ_global[imax[j],imin[j]:imax[j]] .+= QQ_j[ngrid,:] - end - # remaining elements recalling definitions of imax and imin - for j in 2:coord.nelement_local + # assembly below assumes no contributions + # from elements outside of local domain + k = 0 + for j in 1:coord.nelement_local get_QQ_local!(QQ_j,j,lobatto,radau,coord,option) - #lower boundary assembly on element - QQ_global[imin[j]-1,imin[j]-1:imax[j]] .+= QQ_j[1,:]./2.0 - for k in 2:imax[j]-imin[j]+1 - QQ_global[k+imin[j]-2,imin[j]-1:imax[j]] .+= QQ_j[k,:] - end - # upper boundary assembly on element - if j == coord.nelement_local - if coord.bc == "periodic" && coord.nrank == 1 - QQ_global[imax[j],imin[j]-1:imax[j]] .+= QQ_j[ngrid,:] / 2.0 - QQ_global[imin[1],imin[j]-1:imax[j]] .+= QQ_j[ngrid,:] / 2.0 - else - QQ_global[imax[j],imin[j]-1:imax[j]] .+= QQ_j[ngrid,:] - end - else - QQ_global[imax[j],imin[j]-1:imax[j]] .+= QQ_j[ngrid,:]./2.0 - end + iminl = imin[j]-k + imaxl = imax[j] + @. QQ_global[iminl:imaxl,iminl:imaxl] += QQ_j[:,:] + k = 1 end - + if dirichlet_bc # Make matrix diagonal for first/last grid points so it does not change the values # there @@ -898,6 +913,28 @@ function setup_global_weak_form_matrix!(QQ_global::Array{mk_float,2}, QQ_global[end,:] .= 0.0 QQ_global[end,end] = 1.0 end + # requires RHS vector b[1],b[end] = boundary values + end + if periodic_bc + # Make periodic boundary condition by modifying elements of matrix for duplicate point + # add assembly contribution to lower endpoint from upper endpoint + j = coord.nelement_local + get_QQ_local!(QQ_j,j,lobatto,radau,coord,option) + iminl = imin[j] - mk_int(coord.nelement_local > 1) + imaxl = imax[j] + QQ_global[1,iminl:imaxl] .+= QQ_j[end,:] + # Enforce continuity at the periodic boundary + # All-zero row in RHS matrix sets last element of `b` vector in + # `mass_matrix.x = b` to zero + QQ_global[end,:] .= 0.0 + # enforce periodicity `x[1] = x[end]` using the last row of the + # `A.x = b` system. + QQ_global[end,1] = 1.0 + QQ_global[end,end] = -1.0 + if option == "L" # or any other derivative (ODE) matrix requiring two BC (periodicity + value at endpoint) + QQ_global[1,:] .= 0.0 + QQ_global[1,1] = 1.0 + end end return nothing @@ -1016,7 +1053,7 @@ function get_KK_local!(QQ,ielement, end else # assume integrals of form int^infty_-infty (.) d vpa @. QQ = lobatto.K0/scale_factor - if coord.bc !== "periodic" + if coord.bc != "periodic" # boundary terms from integration by parts if explicit_BC_terms && ielement == 1 && coord.irank == 0 @. QQ[1,:] -= lobatto.Dmat[1,:]/scale_factor @@ -1086,12 +1123,14 @@ function get_LL_local!(QQ,ielement, end else # d^2 (.) d vpa^2 -- assume integrals of form int^infty_-infty (.) d vpa @. QQ = lobatto.K0/scale_factor - # boundary terms from integration by parts - if explicit_BC_terms && ielement == 1 && coord.irank == 0 - @. QQ[1,:] -= lobatto.Dmat[1,:]/scale_factor - end - if explicit_BC_terms && ielement == nelement && coord.irank == coord.nrank - 1 - @. QQ[coord.ngrid,:] += lobatto.Dmat[coord.ngrid,:]/scale_factor + if coord.bc != "periodic" + # boundary terms from integration by parts + if explicit_BC_terms && ielement == 1 && coord.irank == 0 + @. QQ[1,:] -= lobatto.Dmat[1,:]/scale_factor + end + if explicit_BC_terms && ielement == nelement && coord.irank == coord.nrank - 1 + @. QQ[coord.ngrid,:] += lobatto.Dmat[coord.ngrid,:]/scale_factor + end end end return nothing diff --git a/moment_kinetics/src/initial_conditions.jl b/moment_kinetics/src/initial_conditions.jl index 8d7db7598..0c9ae84d7 100644 --- a/moment_kinetics/src/initial_conditions.jl +++ b/moment_kinetics/src/initial_conditions.jl @@ -67,14 +67,14 @@ function allocate_pdf_and_moments(composition, r, z, vperp, vpa, vzeta, vr, vz, evolve_moments.density, evolve_moments.parallel_flow, evolve_moments.parallel_pressure, external_source_settings.ion, num_diss_params) - electron = create_moments_electron(z.n, r.n, - composition.electron_physics, num_diss_params) + electron = create_moments_electron(z.n, r.n, composition.electron_physics, + num_diss_params, length(external_source_settings.electron)) neutral = create_moments_neutral(z.n, r.n, composition.n_neutral_species, evolve_moments.density, evolve_moments.parallel_flow, evolve_moments.parallel_pressure, external_source_settings.neutral, num_diss_params) - if abs(collisions.ionization) > 0.0 || z.bc == "wall" + if abs(collisions.reactions.ionization_frequency) > 0.0 || z.bc == "wall" # if ionization collisions are included or wall BCs are enforced, then particle # number is not conserved within each species particle_number_conserved = false @@ -85,7 +85,7 @@ function allocate_pdf_and_moments(composition, r, z, vperp, vpa, vzeta, vr, vz, moments = moments_struct(ion, electron, neutral, evolve_moments.density, particle_number_conserved, - evolve_moments.conservation, + evolve_moments.moments_conservation, evolve_moments.parallel_flow, evolve_moments.parallel_pressure) @@ -281,7 +281,7 @@ function initialize_electrons!(pdf, moments, fields, geometry, composition, r, z # Not restarting, so create initial profiles # initialise the electron thermal speed profile - init_electron_vth!(moments.electron.vth, moments.ion.vth, composition.T_e, composition.me_over_mi, z.grid) + init_electron_vth!(moments.electron.vth, moments.ion.vth, composition, z.grid) begin_r_z_region() # calculate the electron temperature from the thermal speed @loop_r_z ir iz begin @@ -362,10 +362,11 @@ function initialize_electrons!(pdf, moments, fields, geometry, composition, r, z # and this is only a rough initial condition anyway # # q at the boundaries tells us dTe/dz for Braginskii electrons + nu_ei = collisions.electron_fluid.nu_ei if z.irank == 0 dTe_dz_lower = @. -moments.electron.qpar[1,:] * 2.0 / 3.16 / moments.electron.ppar[1,:] * - composition.me_over_mi * collisions.nu_ei + composition.me_over_mi * nu_ei else dTe_dz_lower = nothing end @@ -374,7 +375,7 @@ function initialize_electrons!(pdf, moments, fields, geometry, composition, r, z if z.irank == z.nrank - 1 dTe_dz_upper = @. -moments.electron.qpar[end,:] * 2.0 / 3.16 / moments.electron.ppar[end,:] * - composition.me_over_mi * collisions.nu_ei + composition.me_over_mi * nu_ei else dTe_dz_upper = nothing end @@ -421,8 +422,8 @@ function initialize_electrons!(pdf, moments, fields, geometry, composition, r, z end moments.electron.qpar_updated[] = false calculate_electron_qpar!(moments.electron, pdf.electron, moments.electron.ppar, - moments.electron.upar, moments.ion.upar, collisions.nu_ei, composition.me_over_mi, - composition.electron_physics, vpa) + moments.electron.upar, moments.ion.upar, collisions.electron_fluid.nu_ei, + composition.me_over_mi, composition.electron_physics, vpa) if composition.electron_physics == braginskii_fluid electron_fluid_qpar_boundary_condition!( moments.electron.ppar, moments.electron.upar, moments.electron.dens, @@ -435,7 +436,8 @@ function initialize_electrons!(pdf, moments, fields, geometry, composition, r, z # calculate the electron-ion parallel friction force calculate_electron_parallel_friction_force!(moments.electron.parallel_friction, moments.electron.dens, moments.electron.upar, moments.ion.upar, moments.electron.dT_dz, - composition.me_over_mi, collisions.nu_ei, composition.electron_physics) + composition.me_over_mi, collisions.electron_fluid.nu_ei, + composition.electron_physics) # initialize the scratch arrays containing pdfs and moments for the first RK stage # the electron pdf is yet to be initialised but with the current code logic, the scratch @@ -651,7 +653,7 @@ function initialize_electron_pdf!(scratch, scratch_electron, pdf, moments, field moments.electron.qpar_updated[] = false calculate_electron_qpar!(moments.electron, pdf.electron, moments.electron.ppar, moments.electron.upar, moments.ion.upar, - collisions.nu_ei, composition.me_over_mi, + collisions.electron_fluid.nu_ei, composition.me_over_mi, composition.electron_physics, vpa) # update dqpar/dz for electrons # calculate the zed derivative of the initial electron parallel heat flux @@ -682,7 +684,7 @@ function initialize_electron_pdf!(scratch, scratch_electron, pdf, moments, field end if code_time > 0.0 tind = searchsortedfirst(t_params.electron.moments_output_times, code_time) - n_truncated = length(t_params.electron.moments_output_times) - tind + n_truncated = max(length(t_params.electron.moments_output_times) - tind, 0) truncated_times = t_params.electron.moments_output_times[tind+1:end] resize!(t_params.electron.moments_output_times, n_truncated) t_params.electron.moments_output_times .= truncated_times @@ -1063,14 +1065,18 @@ initialise the electron thermal speed profile. for now the only initialisation option for the temperature is constant in z. returns vth0 = sqrt(2*Ts/Te) """ -function init_electron_vth!(vth_e, vth_i, T_e, me_over_mi, z) +function init_electron_vth!(vth_e, vth_i, composition, z) begin_r_z_region() - # @loop_r_z ir iz begin - # vth_e[iz,ir] = sqrt(T_e) - # end - @loop_r_z ir iz begin - vth_e[iz,ir] = vth_i[iz,ir,1] / sqrt(me_over_mi) - #vth_e[iz,ir] = exp(-5*(z[iz]/z[end])^2)/sqrt(me_over_mi) + if composition.electron_physics ∈ (boltzmann_electron_response, + boltzmann_electron_response_with_simple_sheath) + @loop_r_z ir iz begin + vth_e[iz,ir] = sqrt(composition.T_e / composition.me_over_mi) + end + else + @loop_r_z ir iz begin + vth_e[iz,ir] = vth_i[iz,ir,1] / sqrt(composition.me_over_mi) + #vth_e[iz,ir] = exp(-5*(z[iz]/z[end])^2)/sqrt(composition.me_over_mi) + end end end @@ -1292,7 +1298,7 @@ function init_neutral_pdf_over_density!(pdf, boundary_distributions, spec, compo #if spec.vz_IC.initialization_option == "gaussian" # For now, continue to use 'vpa' initialization options for neutral species - if spec.vpa_IC.initialization_option == "gaussian" + if spec.vz_IC.initialization_option == "gaussian" # initial condition is a Gaussian in the peculiar velocity if z.bc != "wall" for iz ∈ 1:z.n @@ -1516,20 +1522,20 @@ function init_neutral_pdf_over_density!(pdf, boundary_distributions, spec, compo end end #elseif spec.vz_IC.initialization_option == "vzgaussian" - elseif spec.vpa_IC.initialization_option == "vzgaussian" + elseif spec.vz_IC.initialization_option == "vzgaussian" @loop_z_vzeta_vr iz ivzeta ivr begin @. pdf[:,ivr,ivzeta,iz] = vz.grid^2*exp(-vz.scratch^2 - vr[ivr]^2 - vzeta[ivzeta]^2) / vth[iz] end #elseif spec.vz_IC.initialization_option == "sinusoid" - elseif spec.vpa_IC.initialization_option == "sinusoid" + elseif spec.vz_IC.initialization_option == "sinusoid" # initial condition is sinusoid in vz @loop_z_vzeta_vr iz ivzeta ivr begin @. pdf[:,ivr,ivzeta,iz] = spec.vz_IC.amplitude*cospi(2.0*spec.vz_IC.wavenumber*vz.grid/vz.L) end #elseif spec.vz_IC.initialization_option == "monomial" - elseif spec.vpa_IC.initialization_option == "monomial" + elseif spec.vz_IC.initialization_option == "monomial" # linear variation in vz, with offset so that # function passes through zero at upwind boundary @loop_z_vzeta_vr iz ivzeta ivr begin diff --git a/moment_kinetics/src/input_structs.jl b/moment_kinetics/src/input_structs.jl index 2c257d5f1..c4fffaaec 100644 --- a/moment_kinetics/src/input_structs.jl +++ b/moment_kinetics/src/input_structs.jl @@ -3,22 +3,21 @@ module input_structs export advance_info -export evolve_moments_options export time_info -export advection_input, advection_input_mutable -export grid_input, grid_input_mutable -export initial_condition_input, initial_condition_input_mutable +export advection_input +export initial_condition_input export spatial_initial_condition_input, velocity_initial_condition_input -export ion_species_parameters, neutral_species_parameters, species_parameters_mutable +export ion_species_parameters, neutral_species_parameters export species_composition -export drive_input, drive_input_mutable -export collisions_input, krook_collisions_input, fkpl_collisions_input +export em_fields_input +export ion_source_data, electron_source_data, neutral_source_data +export collisions_input, reactions, electron_fluid_collisions, krook_collisions_input, + fkpl_collisions_input, mxwl_diff_collisions_input export io_input export pp_input export geometry_input export set_defaults_and_check_top_level!, set_defaults_and_check_section!, - options_to_TOML, Dict_to_NamedTuple -export merge_dict_with_kwargs!, merge_dict_of_dicts!, merge_dict_of_dicts + check_sections!, options_to_TOML, Dict_to_NamedTuple using ..communication using ..type_definitions: mk_float, mk_int @@ -26,16 +25,6 @@ using ..type_definitions: mk_float, mk_int using MPI using TOML -""" -""" -mutable struct evolve_moments_options - density::Bool - parallel_flow::Bool - parallel_pressure::Bool - conservation::Bool - #advective_form::Bool -end - """ `t_error_sum` is included so that a type which might be mk_float or Float128 can be set by an option but known at compile time when a `time_info` struct is passed as a function @@ -142,19 +131,6 @@ mutable struct advance_info vz_diffusion::Bool #flag to control how vz bc is imposed when vz diffusion terms are present end -""" -""" -mutable struct advection_input_mutable - # advection speed option - option::String - # constant advection speed to use with the "constant" advection option - constant_speed::mk_float - # for option = "oscillating", advection speed is of form - # speed = constant_speed*(1 + oscillation_amplitude*sinpi(frequency*t)) - frequency::mk_float - oscillation_amplitude::mk_float -end - """ """ struct advection_input @@ -184,143 +160,47 @@ export braginskii_fluid export kinetic_electrons export kinetic_electrons_with_temperature_equation -""" -""" -mutable struct grid_input_mutable - # name of the variable associated with this coordinate - name::String - # number of grid points per element - ngrid::mk_int - # number of elements in global grid across ranks - nelement_global::mk_int - # number of elements in local grid on this rank - nelement_local::mk_int - # box length - L::mk_float - # discretization option - discretization::String - # finite difference option (only used if discretization is "finite_difference") - fd_option::String - # cheb option (only used if discretization is "chebyshev_pseudospectral") - cheb_option::String - # boundary option - bc::String - # mutable struct containing advection speed options - advection::advection_input_mutable - # string option determining boundary spacing - element_spacing_option::String -end - -""" -""" -struct grid_input - # name of the variable associated with this coordinate - name::String - # number of grid points per element - ngrid::mk_int - # number of elements globally - nelement_global::mk_int - # number of elements locally - nelement_local::mk_int - # number of ranks involved in the calculation - nrank::mk_int - # rank of this process - irank::mk_int - # box length - L::mk_float - # discretization option - discretization::String - # finite difference option (only used if discretization is "finite_difference") - fd_option::String - # cheb option (only used if discretization is "chebyshev_pseudospectral") - cheb_option::String - # boundary option - bc::String - # struct containing advection speed options - advection::advection_input - # MPI communicator - comm::MPI.Comm - # string option determining boundary spacing - element_spacing_option::String -end - -""" -""" -mutable struct initial_condition_input_mutable - # initialization inputs for one coordinate of a separable distribution function - initialization_option::String - # inputs for "gaussian" initial condition - width::mk_float - # inputs for "sinusoid" initial condition - wavenumber::mk_int - density_amplitude::mk_float - density_phase::mk_float - upar_amplitude::mk_float - upar_phase::mk_float - temperature_amplitude::mk_float - temperature_phase::mk_float - # inputs for "monomial" initial condition - monomial_degree::mk_int -end - """ """ Base.@kwdef struct spatial_initial_condition_input # initialization inputs for one coordinate of a separable distribution function - initialization_option::String + initialization_option::String = "gaussian" # inputs for "gaussian" initial condition - width::mk_float + width::mk_float = 0.125 # inputs for "sinusoid" initial condition - wavenumber::mk_int - density_amplitude::mk_float - density_phase::mk_float - upar_amplitude::mk_float - upar_phase::mk_float - temperature_amplitude::mk_float - temperature_phase::mk_float + wavenumber::mk_int = 1 + density_amplitude::mk_float = 0.001 + density_phase::mk_float = 0.0 + upar_amplitude::mk_float = 0.0 + upar_phase::mk_float = 0.0 + temperature_amplitude::mk_float = 0.0 + temperature_phase::mk_float = 0.0 # inputs for "monomial" initial condition - monomial_degree::mk_int + monomial_degree::mk_int = 2 end """ """ Base.@kwdef struct velocity_initial_condition_input # initialization inputs for one coordinate of a separable distribution function - initialization_option::String + initialization_option::String = "gaussian" # inputs for "gaussian" initial condition - width::mk_float + width::mk_float = 1.0 # inputs for "sinusoid" initial condition - wavenumber::mk_int - density_amplitude::mk_float - density_phase::mk_float - upar_amplitude::mk_float - upar_phase::mk_float - temperature_amplitude::mk_float - temperature_phase::mk_float + wavenumber::mk_int = 1 + density_amplitude::mk_float = 1.0 + density_phase::mk_float = 0.0 + upar_amplitude::mk_float = 0.0 + upar_phase::mk_float = 0.0 + temperature_amplitude::mk_float = 0.0 + temperature_phase::mk_float = 0.0 # inputs for "monomial" initial condition - monomial_degree::mk_int + monomial_degree::mk_int = 2 # inputs for "isotropic-beam", "directed-beam" initial conditions - v0::mk_float - vth0::mk_float - vpa0::mk_float - vperp0::mk_float -end - -""" -""" -mutable struct species_parameters_mutable - # type is the type of species; options are 'ion' or 'neutral' - type::String - # array containing the initial line-averaged temperature for this species - initial_temperature::mk_float - # array containing the initial line-averaged density for this species - initial_density::mk_float - # struct containing the initial condition info in z for this species - z_IC::initial_condition_input_mutable - # struct containing the initial condition info in r for this species - r_IC::initial_condition_input_mutable - # struct containing the initial condition info in vpa for this species - vpa_IC::initial_condition_input_mutable + v0::mk_float = 1.0 + vth0::mk_float = 1.0 + vpa0::mk_float = 1.0 + vperp0::mk_float = 1.0 end """ @@ -359,8 +239,8 @@ Base.@kwdef struct neutral_species_parameters z_IC::spatial_initial_condition_input # struct containing the initial condition info in r for this species r_IC::spatial_initial_condition_input - # struct containing the initial condition info in vpa for this species - vpa_IC::velocity_initial_condition_input + # struct containing the initial condition info in vz for this species + vz_IC::velocity_initial_condition_input end """ @@ -406,33 +286,170 @@ Base.@kwdef struct species_composition end """ -""" -mutable struct drive_input_mutable - # if drive.phi = true, include external electrostatic potential - force_phi::Bool - # if external field included, it is of the form - # phi(z,t=0)*amplitude*sinpi(t*frequency) - amplitude::mk_float - frequency::mk_float -end - -""" -""" -struct drive_input - # if drive.phi = true, include external electrostatic potential - force_phi::Bool - # if external field included, it is of the form - # phi(z,t=0)*amplitude*sinpi(t*frequency) - amplitude::mk_float - frequency::mk_float - # if true, forces Er = 0.0 at wall plates - force_Er_zero_at_wall::Bool +Settings for electronmagenetic fields +""" +Base.@kwdef struct em_fields_input + force_Er_zero_at_wall::Bool = false +end + +""" +Source profile structs for ions and electrons which allows them to have any number +of different sources (from wall perhaps, superposition of core sources, etc.). These +sources are then contained in a vector of structs. + +Since the ion source must be the same as the electron source in all respects (apart +from possibly a different electron temperature or source strength), the electron +vector of source profile structs will be a kind of mirror of the ion vector of structs. +""" +Base.@kwdef struct ion_source_data + # struct containing source data for ions + # is the source active or not + active::Bool + # An overall multiplier for the strength (i.e. 0.0 would turn off the source) + source_strength::mk_float + # For use with "energy" option, Krook source (...) + source_n::mk_float + # Temperature of source (variation along z can be introduced later) + source_T::mk_float + # birth speed for "alphas" option + source_v0::mk_float + # birth vpa for "beam" option + source_vpa0::mk_float + # birth vperp for "beam" option + source_vperp0::mk_float + # strength of sink in "alphas-with-losses" & "beam-with-losses" option + sink_strength::mk_float + # thermal speed for sink in "alphas-with-losses" & "beam-with-losses" option + sink_vth::mk_float + # profile for source in r ('constant' or 'gaussian' or 'parabolic' etc.) + r_profile::String + # width of source in r (doesn't apply to constant profile) + r_width::mk_float + # relative minimum of source in r, acts as the baseline + r_relative_minimum::mk_float + # profile for source in z ('constant' or 'gaussian' or 'parabolic' etc.) + z_profile::String + # width of source in z (doesn't apply to constant profile) + z_width::mk_float + # relative minimum of source in z, acts as the baseline (so you can elevate + # your gaussian source above 0, for example) + z_relative_minimum::mk_float + # velocity profile for the source, Maxwellian would be default, can have beams too + source_type::String #"Maxwellian" "energy", "alphas", "alphas-with-losses", "beam", "beam-with-losses" + # proportional integral controllers - for when you want to find a source profile that matches + # a target density + PI_density_controller_P::mk_float + PI_density_controller_I::mk_float + PI_density_target_amplitude::mk_float + PI_density_target_r_profile::String + PI_density_target_r_width::mk_float + PI_density_target_r_relative_minimum::mk_float + PI_density_target_z_profile::String + PI_density_target_z_width::mk_float + PI_density_target_z_relative_minimum::mk_float + recycling_controller_fraction::mk_float + # r_amplitude through the r coordinate (in 1D this can just be set to 1.0) + r_amplitude::Vector{mk_float} + # z_amplitude through the z coordinate, which will have your gaussian profile, + # constant profile, parabolic, etc.. + z_amplitude::Vector{mk_float} + PI_density_target::Union{mk_float, Nothing, MPISharedArray{mk_float,2}} + PI_controller_amplitude::Union{Nothing, MPISharedArray{mk_float,1}} + controller_source_profile::Union{Nothing, MPISharedArray{mk_float,2}, Array{mk_float, 2}} + PI_density_target_ir::Union{mk_int, Nothing} + PI_density_target_iz::Union{mk_int, Nothing} + PI_density_target_rank::Union{mk_int, Nothing} #possibly this should have Int64 as well, + # in the event that the code is running with mk_int = Int32 but the rank is set to 0::Int64 +end + +Base.@kwdef struct electron_source_data + # most of the electron parameters must be the same as for ions, so only + # source strength (in the case of an ion energy source) and source Temperature + # can be different. The other four are set by the ion source data. + source_strength::mk_float + source_T::mk_float + active::Bool + r_amplitude::Vector{mk_float} + z_amplitude::Vector{mk_float} + source_type::String +end + +Base.@kwdef struct neutral_source_data + # struct containing source data for neutrals + # is the source active or not + active::Bool + # An overall multiplier for the strength (i.e. 0.0 would turn off the source) + source_strength::mk_float + # For use with "energy" option, Krook source (...) + source_n::mk_float + # Temperature of source (variation along z can be introduced later) + source_T::mk_float + # birth speed for "alphas" option + source_v0::mk_float + # birth vpa for "beam" option + source_vpa0::mk_float + # birth vperp for "beam" option + source_vperp0::mk_float + # strength of sink in "alphas-with-losses" & "beam-with-losses" option + sink_strength::mk_float + # thermal speed for sink in "alphas-with-losses" & "beam-with-losses" option + sink_vth::mk_float + # profile for source in r ('constant' or 'gaussian' or 'parabolic' etc.) + r_profile::String + # width of source in r (doesn't apply to constant profile) + r_width::mk_float + # relative minimum of source in r, acts as the baseline + r_relative_minimum::mk_float + # profile for source in z ('constant' or 'gaussian' or 'parabolic' etc.) + z_profile::String + # width of source in z (doesn't apply to constant profile) + z_width::mk_float + # relative minimum of source in z, acts as the baseline (so you can elevate + # your gaussian source above 0, for example) + z_relative_minimum::mk_float + # velocity profile for the source, Maxwellian would be default, can have beams too + source_type::String #"Maxwellian" "energy", "alphas", "alphas-with-losses", "beam", "beam-with-losses" + # proportional integral controllers - for when you want to find a source profile that matches + # a target density + PI_density_controller_P::mk_float + PI_density_controller_I::mk_float + PI_density_target_amplitude::mk_float + PI_density_target_r_profile::String + PI_density_target_r_width::mk_float + PI_density_target_r_relative_minimum::mk_float + PI_density_target_z_profile::String + PI_density_target_z_width::mk_float + PI_density_target_z_relative_minimum::mk_float + recycling_controller_fraction::mk_float + # r_amplitude through the r coordinate (in 1D this can just be set to 1.0) + r_amplitude::Vector{mk_float} + # z_amplitude through the z coordinate, which will have your gaussian profile, + # constant profile, parabolic, etc.. + z_amplitude::Vector{mk_float} + PI_density_target::Union{mk_float, Nothing, MPISharedArray{mk_float,2}} + PI_controller_amplitude::Union{Nothing, MPISharedArray{mk_float,1}} + controller_source_profile::Union{Nothing, MPISharedArray{mk_float,2}, Array{mk_float, 2}} + PI_density_target_ir::Union{mk_int, Nothing} + PI_density_target_iz::Union{mk_int, Nothing} + PI_density_target_rank::Union{mk_int, Nothing} #possibly this should have Int64 as well, + # in the event that the code is running with mk_int = Int32 but the rank is set to 0::Int64 +end + +#Structs set up for the collision operators so far in use. These will each +#be contained in the main collisions_input struct below, as substructs. + +Base.@kwdef struct reactions + charge_exchange_frequency::mk_float = 0.0 + electron_charge_exchange_frequency::mk_float = 0.0 + ionization_frequency::mk_float = 0.0 + electron_ionization_frequency::mk_float = 0.0 + ionization_energy::mk_float = 0.0 +end + +Base.@kwdef struct electron_fluid_collisions + nu_ei::mk_float = 0.0 end -""" -Structs set up for the collision operators so far in use. These will each -be contained in the main collisions_input struct below, as substructs. -""" Base.@kwdef struct mxwl_diff_collisions_input use_maxwell_diffusion::Bool # different diffusion coefficients for each species, has units of @@ -493,18 +510,10 @@ Collisions input struct to contain all the different collisions substructs and o collision input parameters. """ struct collisions_input - # ion-neutral charge exchange collision frequency - charge_exchange::mk_float - # electron-neutral charge exchange collision frequency - charge_exchange_electron::mk_float - # ionization collision frequency - ionization::mk_float - # ionization collision frequency for electrons (probably should be same as for ions) - ionization_electron::mk_float - # ionization energy cost - ionization_energy::mk_float - # electron-ion collision frequency - nu_ei::mk_float + # atomic reaction parameters + reactions::reactions + # electron fluid collision parameters + electron_fluid::electron_fluid_collisions # struct of parameters for the Krook operator krook::krook_collisions_input # struct of parameters for the Fokker-Planck operator @@ -537,18 +546,6 @@ end @enum binary_format_type hdf5 netcdf export binary_format_type, hdf5, netcdf -""" -Settings and input for setting up file I/O -""" -Base.@kwdef struct io_input - output_dir::String - run_name::String - ascii_output::Bool - binary_format::binary_format_type - parallel_io::Bool - run_id::String -end - """ """ struct pp_input @@ -779,15 +776,8 @@ function set_defaults_and_check_top_level!(options::AbstractDict; kwargs...) 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). +function _get_section_and_check_option_names(options, section_name, section_keys) -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)) @@ -804,13 +794,55 @@ function set_defaults_and_check_section!(options::AbstractDict, 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) + unexpected_options = String[] for (key, value) in section if !(key ∈ section_keys) - error("Unexpected option '$key=$value' in section '$section_name'") + push!(unexpected_options, key) end end + if length(unexpected_options) > 0 + error("Unexpected options $(join(("$k=$(section[k])" for k ∈ unexpected_options), ", ", ", and ")) in section '$section_name'") + end + + return section +end + +function _check_for_nothing(section, section_name) + nothing_defaults = Tuple((k,v) for (k,v) ∈ section if v === nothing) + if length(nothing_defaults) > 0 + error("`nothing` cannot be used as a default value, because it cannot be written " + * "to TOML or HDF5. In section [$section_name], found " + * "$(join(("$k=$v" for (k,v) ∈ nothing_defaults), ", ", ", and ")).") + end +end + +function _store_section_name_for_check!(options, section_name) + # Record the defined section_name in a temporary, private subsection of `options`, so + # we can use it to check the existing sections later. + if !(_section_check_store_name ∈ keys(options)) + # If section is not present, create it + options[_section_check_store_name] = String[] + end + push!(options[_section_check_store_name], section_name) + + return nothing +end + +const _section_check_store_name = "_section_check_store" + +""" +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...) + + section_keys_symbols = keys(kwargs) + section_keys = (String(k) for k ∈ section_keys_symbols) + section = _get_section_and_check_option_names(options, section_name, section_keys) # Set default values if a key was not set explicitly for (key_sym, default_value) ∈ kwargs @@ -820,67 +852,100 @@ function set_defaults_and_check_section!(options::AbstractDict, section_name; section[key] = get(section, key, default_value) end + _check_for_nothing(section, section_name) + + _store_section_name_for_check!(options, section_name) + return section end """ -Convert a Dict whose keys are String or Symbol to a NamedTuple + set_defaults_and_check_section!(options::AbstractDict, struct_type::Type, + name::Union{String,Nothing}=nothing) -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 +Alternative form to be used when the options should be stored in a struct of type +`struct_type` rather than a `NamedTuple`. `struct_type` must be defined using `@kwdef`. +The returned instance of `struct_type` is immutable, so if you need to modify the settings +- e.g. to apply some logic to set defaults depending on other settings/parameters - then +you should use the 'standard' version of [`set_defaults_and_check_section!`](@ref) that +returns a `Dict` that can be modified, and then use that `Dict` to initialise the +`struct_type`. + +The name of the section in the options that will be read defaults to the name of +`struct_type`, but can be set using the `section_name` argument. + +Returns an instance of `struct_type`. """ -Dict merge function for named keyword arguments -for case when input Dict is a mixed Dict of Dicts -and non-Dict float/int/string entries, and the -keyword arguments are also a mix of Dicts and non-Dicts -""" +function set_defaults_and_check_section!(options::AbstractDict, struct_type::Type, + section_name::Union{String,Nothing}=nothing) -function merge_dict_with_kwargs!(dict_base; args...) - for (k,v) in args - k = String(k) - if k in keys(dict_base) && isa(v, AbstractDict) - v = merge(dict_base[k], v) - end - dict_base[k] = v + if section_name === nothing + section_name = String(nameof(struct_type)) end - return nothing + section_keys = (String(key) for key ∈ fieldnames(struct_type)) + section = _get_section_and_check_option_names(options, section_name, section_keys) + + # Pass the settings in `section` as kwargs to the constructor for `struct_type`. + # `struct_type` is an `@kwdef` struct, so this constructor takes care of the default + # values. + settings_instance = struct_type(; (Symbol(k) => v for (k,v) ∈ pairs(section))...) + + # Save the settings with defaults applied back into `options` so they can be stored in + # the output file. + for k ∈ fieldnames(struct_type) + section[String(k)] = getfield(settings_instance, k) + end + + _check_for_nothing(section, section_name) + + _store_section_name_for_check!(options, section_name) + + return settings_instance end """ -Dict merge function for merging Dicts of Dicts -In place merge, returns nothing + check_sections!(options::AbstractDict) + +Check that there are no unexpected sections in `options`. The 'expected sections' are the +ones that were defined with [`set_defaults_and_check_section!`](@ref). """ +function check_sections!(options::AbstractDict; check_no_top_level_options=true) -function merge_dict_of_dicts!(dict_base, dict_mod) - for (k,v) in dict_mod - k = String(k) - if k in keys(dict_base) && isa(v, AbstractDict) - v = merge(dict_base[k], v) + expected_section_names = pop!(options, _section_check_store_name) + + unexpected_section_names = String[] + unexpected_top_level_options = String[] + for (k,v) ∈ pairs(options) + if isa(v, AbstractDict) + if k ∉ expected_section_names + push!(unexpected_section_names, k) + end + elseif check_no_top_level_options + push!(unexpected_top_level_options, k) end - dict_base[k] = v end + + if length(unexpected_section_names) > 0 && length(unexpected_top_level_options) > 0 + error("Input had unexpected sections $unexpected_section_names, and unexpected " + * "options in the top level $unexpected_top_level_options") + elseif length(unexpected_section_names) > 0 + error("Input had unexpected sections $unexpected_section_names.") + elseif length(unexpected_top_level_options) > 0 + error("Input had unexpected options in the top level " + * "$unexpected_top_level_options") + end + return nothing end """ -Dict merge function for merging Dicts of Dicts -Creates new dict, which is returned -""" +Convert a Dict whose keys are String or Symbol to a NamedTuple -function merge_dict_of_dicts(dict_base, dict_mod) - dict_new = deepcopy(dict_base) - for (k,v) in dict_mod - k = String(k) - if k in keys(dict_new) && isa(v, AbstractDict) - v = merge(dict_new[k], v) - end - dict_new[k] = v - end - return dict_new +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 """ diff --git a/moment_kinetics/src/ionization.jl b/moment_kinetics/src/ionization.jl index e1becf468..0620f0717 100644 --- a/moment_kinetics/src/ionization.jl +++ b/moment_kinetics/src/ionization.jl @@ -75,9 +75,10 @@ function ion_ionization_collisions_1V!(f_out, fvec_in, vz, vpa, vperp, z, r, vz_ # no need to interpolate if neither upar or ppar evolved separately from pdf vpa.scratch2 .= fvec_in.pdf_neutral[:,1,1,iz,ir,isn] end + ionization = collisions.reactions.ionization_frequency @loop_vpa ivpa begin f_out[ivpa,1,iz,ir,is] += - dt*collisions.ionization*fvec_in.density_neutral[iz,ir,isn]* + dt*ionization*fvec_in.density_neutral[iz,ir,isn]* (vpa.scratch2[ivpa]*vth_ratio - fvec_in.pdf[ivpa,1,iz,ir,is]) end end @@ -88,6 +89,7 @@ function ion_ionization_collisions_1V!(f_out, fvec_in, vz, vpa, vperp, z, r, vz_ # no gyroaverage here as 1V code #NB: used quasineutrality to replace electron density n_e with ion density #NEEDS GENERALISATION TO n_ion_species > 1 (missing species charge: Sum_i Z_i n_i = n_e) + ionization = collisions.reactions.ionization_frequency isn = is @loop_r_z ir iz begin @views interpolate_to_grid_vpa!(vpa.scratch, vpa.grid, @@ -95,7 +97,7 @@ function ion_ionization_collisions_1V!(f_out, fvec_in, vz, vpa, vperp, z, r, vz_ vz_spectral) @loop_vpa ivpa begin # apply ionization collisions to all ion species - f_out[ivpa,1,iz,ir,is] += dt*collisions.ionization*vpa.scratch[ivpa]*fvec_in.density[iz,ir,is] + f_out[ivpa,1,iz,ir,is] += dt*ionization*vpa.scratch[ivpa]*fvec_in.density[iz,ir,is] end end end @@ -117,6 +119,7 @@ function neutral_ionization_collisions_1V!(f_neutral_out, fvec_in, vz, vpa, vper if !moments.evolve_density begin_sn_r_z_vz_region() + ionization = collisions.reactions.ionization_frequency @loop_sn isn begin # ion ionisation rate = < f_n > n_e R_ion # neutral "ionisation" (depopulation) rate = - f_n n_e R_ion @@ -126,7 +129,7 @@ function neutral_ionization_collisions_1V!(f_neutral_out, fvec_in, vz, vpa, vper is = isn @loop_r_z_vz ir iz ivz begin # apply ionization collisions to all neutral species - f_neutral_out[ivz,1,1,iz,ir,isn] -= dt*collisions.ionization*fvec_in.pdf_neutral[ivz,1,1,iz,ir,isn]*fvec_in.density[iz,ir,is] + f_neutral_out[ivz,1,1,iz,ir,isn] -= dt*ionization*fvec_in.pdf_neutral[ivz,1,1,iz,ir,isn]*fvec_in.density[iz,ir,is] end end end @@ -145,7 +148,7 @@ function ion_ionization_collisions_3V!(f_out, f_neutral_gav_in, fvec_in, composi @boundscheck r.n == size(f_neutral_gav_in,4) || throw(BoundsError(f_neutral_gav_in)) @boundscheck composition.n_neutral_species == size(f_neutral_gav_in,5) || throw(BoundsError(f_neutral_gav_in)) - ionization_frequency = collisions.ionization + ionization_frequency = collisions.reactions.ionization_frequency begin_s_r_z_vperp_vpa_region() @@ -173,7 +176,7 @@ function neutral_ionization_collisions_3V!(f_neutral_out, fvec_in, composition, @boundscheck r.n == size(f_neutral_out,5) || throw(BoundsError(f_neutral_out)) @boundscheck composition.n_neutral_species == size(f_neutral_out,6) || throw(BoundsError(f_neutral_out)) - ionization_frequency = collisions.ionization + ionization_frequency = collisions.reactions.ionization_frequency # ion ionization rate = < f_n > n_e R_ion # neutral "ionization" (depopulation) rate = - f_n n_e R_ion diff --git a/moment_kinetics/src/krook_collisions.jl b/moment_kinetics/src/krook_collisions.jl index c05d0cd08..3fb386961 100644 --- a/moment_kinetics/src/krook_collisions.jl +++ b/moment_kinetics/src/krook_collisions.jl @@ -43,6 +43,10 @@ function setup_krook_collisions_input(toml_input::Dict) input_section["nuii0"] = nuii_krook_default input_section["nuee0"] = nuee_krook_default input_section["nuei0"] = nuei_krook_default + elseif frequency_option == "collisionality_scan" + input_section["nuii0"] *= nuii_krook_default + input_section["nuee0"] *= nuee_krook_default + input_section["nuei0"] *= nuei_krook_default elseif frequency_option == "manual" # use the frequency from the input file # do nothing @@ -76,7 +80,7 @@ function get_collision_frequency_ii(collisions, n, vth) colk = collisions.krook nuii0 = colk.nuii0 frequency_option = colk.frequency_option - if frequency_option == "reference_parameters" + if frequency_option ∈ ("reference_parameters", "collisionality_scan") return @. nuii0 * n * vth^(-3) elseif frequency_option == "manual" # Include 0.0*n so that the result gets promoted to an array if n is an array, diff --git a/moment_kinetics/src/load_data.jl b/moment_kinetics/src/load_data.jl index cf2ae9927..1c8aaaca0 100644 --- a/moment_kinetics/src/load_data.jl +++ b/moment_kinetics/src/load_data.jl @@ -66,10 +66,20 @@ const neutral_moment_variables = ("density_neutral", "uz_neutral", "pz_neutral", "thermal_speed_neutral", "temperature_neutral", "qz_neutral", "total_energy_neutral", "total_energy_flux_neutral") +const ion_source_variables = ("external_source_amplitude", "external_source_density_amplitude", + "external_source_momentum_amplitude", "external_source_pressure_amplitude", + "external_source_controller_integral") +const neutral_source_variables = ("external_source_neutral_amplitude", "external_source_neutral_density_amplitude", + "external_source_neutral_momentum_amplitude", "external_source_neutral_pressure_amplitude", + "external_source_neutral_controller_integral") +const electron_source_variables = ("external_source_electron_amplitude", "external_source_electron_density_amplitude", + "external_source_electron_momentum_amplitude", "external_source_electron_pressure_amplitude") const all_moment_variables = tuple(em_variables..., ion_moment_variables..., electron_moment_variables..., - neutral_moment_variables...) - + neutral_moment_variables..., + ion_source_variables..., + electron_source_variables..., + neutral_source_variables...) const ion_dfn_variables = ("f",) const electron_dfn_variables = ("f_electron",) const neutral_dfn_variables = ("f_neutral",) @@ -246,7 +256,9 @@ function load_coordinate_data(fid, name; printout=false, irank=nothing, nrank=no return nothing, nothing, nothing end + input = OptionsDict() ngrid = load_variable(coord_group, "ngrid") + input["ngrid"] = ngrid n_local = load_variable(coord_group, "n_local") n_global = load_variable(coord_group, "n_global") grid = load_variable(coord_group, "grid") @@ -303,31 +315,35 @@ function load_coordinate_data(fid, name; printout=false, irank=nothing, nrank=no chunk_size = n_local - 1 end end + input["nelement"] = nelement_global + input["nelement_local"] = nelement_local # L = global box length - L = load_variable(coord_group, "L") - discretization = load_variable(coord_group, "discretization") - fd_option = load_variable(coord_group, "fd_option") + input["L"] = load_variable(coord_group, "L") + input["discretization"] = load_variable(coord_group, "discretization") + if "finite_difference_option" ∈ keys(coord_group) + input["finite_difference_option"] = load_variable(coord_group, "finite_difference_option") + else + # Older output file + input["finite_difference_option"] = load_variable(coord_group, "fd_option") + end if "cheb_option" ∈ keys(coord_group) - cheb_option = load_variable(coord_group, "cheb_option") + input["cheb_option"] = load_variable(coord_group, "cheb_option") else # Old output file - cheb_option = "FFT" + input["cheb_option"] = "FFT" end - bc = load_variable(coord_group, "bc") + input["bc"] = load_variable(coord_group, "bc") if "element_spacing_option" ∈ keys(coord_group) - element_spacing_option = load_variable(coord_group, "element_spacing_option") + input["element_spacing_option"] = load_variable(coord_group, "element_spacing_option") else - element_spacing_option = "uniform" + input["element_spacing_option"] = "uniform" end - # Define input to create coordinate struct - input = grid_input(name, ngrid, nelement_global, nelement_local, nrank, irank, L, - discretization, fd_option, cheb_option, bc, - advection_input("default", 0.0, 0.0, 0.0), MPI.COMM_NULL, - element_spacing_option) - coord, spectral = define_coordinate(input, nothing, parallel_io; + coord, spectral = define_coordinate(OptionsDict(name => input), name; + parallel_io=parallel_io, run_directory=run_directory, - ignore_MPI=ignore_MPI) + ignore_MPI=ignore_MPI, irank=irank, nrank=nrank, + comm=MPI.COMM_NULL) return coord, spectral, chunk_size end @@ -3507,14 +3523,12 @@ function get_run_info_no_setup(run_dir::Union{AbstractString,Tuple{AbstractStrin else dummy_adv_input = advection_input("default", 1.0, 0.0, 0.0) dummy_comm = MPI.COMM_NULL - dummy_input = grid_input("dummy", 1, 1, 1, 1, 0, 1.0, - "chebyshev_pseudospectral", "", "", "periodic", - dummy_adv_input, dummy_comm, "uniform") - vzeta, vzeta_spectral = define_coordinate(dummy_input, nothing; ignore_MPI = true) + dummy_input = OptionsDict("dummy" => OptionsDict()) + vzeta, vzeta_spectral = define_coordinate(dummy_input, "dummy"; ignore_MPI = true) vzeta_chunk_size = 1 - vr, vr_spectral = define_coordinate(dummy_input, nothing; ignore_MPI = true) + vr, vr_spectral = define_coordinate(dummy_input, "dummy"; ignore_MPI = true) vr_chunk_size = 1 - vz, vz_spectral = define_coordinate(dummy_input, nothing; ignore_MPI = true) + vz, vz_spectral = define_coordinate(dummy_input, "dummy"; ignore_MPI = true) vz_chunk_size = 1 end @@ -4337,28 +4351,30 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dppar_dz = get_z_derivative(run_info, "parallel_pressure") dvth_dz = get_z_derivative(run_info, "thermal_speed") dqpar_dz = get_z_derivative(run_info, "parallel_heat_flux") - if run_info.external_source_settings.ion.active + if any(x -> x.active, run_info.external_source_settings.ion) + n_sources = length(run_info.external_source_settings.ion) external_source_amplitude = get_variable(run_info, "external_source_amplitude") if run_info.evolve_density external_source_density_amplitude = get_variable(run_info, "external_source_density_amplitude") else - external_source_density_amplitude = zeros(0,0,run_info.nt) + external_source_density_amplitude = zeros(0,0,n_sources,run_info.nt) end if run_info.evolve_upar external_source_momentum_amplitude = get_variable(run_info, "external_source_momentum_amplitude") else - external_source_momentum_amplitude = zeros(0,0,run_info.nt) + external_source_momentum_amplitude = zeros(0,0,n_sources,run_info.nt) end if run_info.evolve_ppar external_source_pressure_amplitude = get_variable(run_info, "external_source_pressure_amplitude") else - external_source_pressure_amplitude = zeros(0,0,run_info.nt) + external_source_pressure_amplitude = zeros(0,0,n_sources,run_info.nt) end else - external_source_amplitude = zeros(0,0,run_info.nt) - external_source_density_amplitude = zeros(0,0,run_info.nt) - external_source_momentum_amplitude = zeros(0,0,run_info.nt) - external_source_pressure_amplitude = zeros(0,0,run_info.nt) + n_sources = 0 + external_source_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_density_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_momentum_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_pressure_amplitude = zeros(0,0,n_sources,run_info.nt) end nz, nr, nspecies, nt = size(vth) @@ -4390,10 +4406,10 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dvth_dz=dvth_dz[:,:,:,it], dqpar_dz=dqpar_dz[:,:,:,it], vth=vth[:,:,:,it], - external_source_amplitude=external_source_amplitude[:,:,it], - external_source_density_amplitude=external_source_density_amplitude[:,:,it], - external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,it], - external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,it]), + external_source_amplitude=external_source_amplitude[:,:,n_sources,it], + external_source_density_amplitude=external_source_density_amplitude[:,:,n_sources,it], + external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,n_sources,it], + external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,n_sources,it]), evolve_density=run_info.evolve_density, evolve_upar=run_info.evolve_upar, evolve_ppar=run_info.evolve_ppar) @@ -4476,16 +4492,18 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dppar_dz = get_z_derivative(run_info, "electron_parallel_pressure") dvth_dz = get_z_derivative(run_info, "electron_thermal_speed") dqpar_dz = get_z_derivative(run_info, "electron_parallel_heat_flux") - if run_info.external_source_settings.electron.active + if any(x -> x.active, run_info.external_source_settings.electron) + n_sources = length(run_info.external_source_settings.electron) external_source_amplitude = get_variable(run_info, "external_source_electron_amplitude") external_source_density_amplitude = get_variable(run_info, "external_source_electron_density_amplitude") external_source_momentum_amplitude = get_variable(run_info, "external_source_electron_momentum_amplitude") external_source_pressure_amplitude = get_variable(run_info, "external_source_electron_pressure_amplitude") else - external_source_amplitude = zeros(0,0,run_info.nt) - external_source_density_amplitude = zeros(0,0,run_info.nt) - external_source_momentum_amplitude = zeros(0,0,run_info.nt) - external_source_pressure_amplitude = zeros(0,0,run_info.nt) + n_sources = 0 + external_source_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_density_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_momentum_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_pressure_amplitude = zeros(0,0,n_sources,run_info.nt) end nz, nr, nt = size(vth) @@ -4509,10 +4527,10 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dppar_dz=dppar_dz[:,:,it], dqpar_dz=dqpar_dz[:,:,it], dvth_dz=dvth_dz[:,:,it], - external_source_amplitude=external_source_amplitude[:,:,it], - external_source_density_amplitude=external_source_density_amplitude[:,:,it], - external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,it], - external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,it]),) + external_source_amplitude=external_source_amplitude[:,:,n_sources,it], + external_source_density_amplitude=external_source_density_amplitude[:,:,n_sources,it], + external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,n_sources,it], + external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,n_sources,it]),) @views update_electron_speed_vpa!(advect, density[:,:,it], upar[:,:,it], ppar[:,:,it], moments, run_info.vpa.grid, run_info.external_source_settings.electron) @@ -4594,28 +4612,30 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dpz_dz = get_z_derivative(run_info, "pz_neutral") dvth_dz = get_z_derivative(run_info, "thermal_speed_neutral") dqz_dz = get_z_derivative(run_info, "qz_neutral") - if run_info.external_source_settings.neutral.active + if any(x -> x.active, run_info.external_source_settings.neutral) + n_sources = length(run_info.external_source_settings.neutral) external_source_amplitude = get_variable(run_info, "external_source_neutral_amplitude") if run_info.evolve_density external_source_density_amplitude = get_variable(run_info, "external_source_neutral_density_amplitude") else - external_source_density_amplitude = zeros(0,0,run_info.nt) + external_source_density_amplitude = zeros(0,0,n_sources,run_info.nt) end if run_info.evolve_upar external_source_momentum_amplitude = get_variable(run_info, "external_source_neutral_momentum_amplitude") else - external_source_momentum_amplitude = zeros(0,0,run_info.nt) + external_source_momentum_amplitude = zeros(0,0,n_sources,run_info.nt) end if run_info.evolve_ppar external_source_pressure_amplitude = get_variable(run_info, "external_source_neutral_pressure_amplitude") else - external_source_pressure_amplitude = zeros(0,0,run_info.nt) + external_source_pressure_amplitude = zeros(0,0,n_sources,run_info.nt) end else - external_source_amplitude = zeros(0,0,run_info.nt) - external_source_density_amplitude = zeros(0,0,run_info.nt) - external_source_momentum_amplitude = zeros(0,0,run_info.nt) - external_source_pressure_amplitude = zeros(0,0,run_info.nt) + n_sources = 0 + external_source_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_density_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_momentum_amplitude = zeros(0,0,n_sources,run_info.nt) + external_source_pressure_amplitude = zeros(0,0,n_sources,run_info.nt) end nz, nr, nspecies, nt = size(vth) @@ -4645,10 +4665,10 @@ function get_variable(run_info, variable_name; normalize_advection_speed_shape=t dvth_dz=dvth_dz[:,:,:,it], dqz_dz=dqz_dz[:,:,:,it], vth=vth[:,:,:,it], - external_source_amplitude=external_source_amplitude[:,:,it], - external_source_density_amplitude=external_source_density_amplitude[:,:,it], - external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,it], - external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,it]), + external_source_amplitude=external_source_amplitude[:,:,n_sources,it], + external_source_density_amplitude=external_source_density_amplitude[:,:,n_sources,it], + external_source_momentum_amplitude=external_source_momentum_amplitude[:,:,n_sources,it], + external_source_pressure_amplitude=external_source_pressure_amplitude[:,:,n_sources,it]), evolve_density=run_info.evolve_density, evolve_upar=run_info.evolve_upar, evolve_ppar=run_info.evolve_ppar) @@ -5076,16 +5096,19 @@ end function construct_global_zr_coords(r_local, z_local; ignore_MPI=true) function make_global_input(coord_local) - return grid_input(coord_local.name, coord_local.ngrid, - coord_local.nelement_global, coord_local.nelement_global, 1, 0, coord_local.L, - coord_local.discretization, coord_local.fd_option, coord_local.cheb_option, coord_local.bc, - coord_local.advection, MPI.COMM_NULL, coord_local.element_spacing_option) - end - - r_global, r_global_spectral = define_coordinate(make_global_input(r_local), nothing; - ignore_MPI=ignore_MPI) - z_global, z_global_spectral = define_coordinate(make_global_input(z_local), nothing; - ignore_MPI=ignore_MPI) + return OptionsDict(coord_local.name => OptionsDict("ngrid" => coord_local.ngrid, + "nelement" => coord_local.nelement_global, + "nelement_local" => coord_local.nelement_global, + "L" => coord_local.L, + "discretization" => coord_local.discretization, + "cheb_option" => coord_local.cheb_option, + "bc" => coord_local.bc, + "element_spacing_option" => coord_local.element_spacing_option,), + ) + end + + r_global, r_global_spectral = define_coordinate(make_global_input(r_local), "r"; ignore_MPI=ignore_MPI) + z_global, z_global_spectral = define_coordinate(make_global_input(z_local), "z"; ignore_MPI=ignore_MPI) return r_global, r_global_spectral, z_global, z_global_spectral end diff --git a/moment_kinetics/src/manufactured_solns.jl b/moment_kinetics/src/manufactured_solns.jl index c5feaa503..d3daa22ef 100644 --- a/moment_kinetics/src/manufactured_solns.jl +++ b/moment_kinetics/src/manufactured_solns.jl @@ -8,6 +8,7 @@ export manufactured_electric_fields export manufactured_geometry using ..array_allocation: allocate_shared_float +using ..input_structs using ..looping using ..type_definitions: mk_float, mk_int @@ -27,6 +28,43 @@ function __init__() end end +function setup_manufactured_solutions(input_dict) + use_for_init_is_default = !(("manufactured_solns" ∈ keys(input_dict)) && + ("use_for_init" ∈ keys(input_dict["manufactured_solns"]))) + manufactured_solns_section = set_defaults_and_check_section!( + input_dict, "manufactured_solns"; + use_for_advance=false, + use_for_init=false, + # constant to be used to control Ez divergence in MMS tests + epsilon_offset=0.001, + # bool to control if dfni is a function of vpa or vpabar in MMS test + use_vpabar_in_mms_dfni=true, + alpha_switch=1.0, + type="default", + ) + if use_for_init_is_default && manufactured_solns_section["use_for_advance"] + # if manufactured_solns_section["use_for_init"] was set by default, set + # manufactured_solns_section["use_for_init"] == true + manufactured_solns_section["use_for_init"] = true + end + if manufactured_solns_section["use_for_init"] || manufactured_solns_section["use_for_advance"] + manufactured_solutions_ext = Base.get_extension(@__MODULE__, :manufactured_solns_ext) + if manufactured_solutions_ext === nothing + # If Symbolics is not installed, then the extension manufactured_solns_ext + # will not be loaded, in which case we cannot use manufactured solutions. + error("Symbolics package is not installed, so manufactured solutions are not " + * "available. Re-run machines/machine-setup.sh and activate " + * "manufactured solutions, or install Symbolics.") + end + end + if manufactured_solns_section["use_vpabar_in_mms_dfni"] + manufactured_solns_section["alpha_switch"] = 1.0 + else + manufactured_solns_section["alpha_switch"] = 0.0 + end + return Dict_to_NamedTuple(manufactured_solns_section) +end + # This function is defined here rather than in the extension, because the looping macros # break if used outside the moment_kinetics module. function manufactured_sources(manufactured_solns_input, r_coord, z_coord, vperp_coord, diff --git a/moment_kinetics/src/moment_kinetics.jl b/moment_kinetics/src/moment_kinetics.jl index 4c57e6ed8..86810a66f 100644 --- a/moment_kinetics/src/moment_kinetics.jl +++ b/moment_kinetics/src/moment_kinetics.jl @@ -148,8 +148,8 @@ function run_moment_kinetics(to::Union{TimerOutput,Nothing}, input_dict=Dict(); # Stop code from hanging when running on multiple processes if only one of them # throws an error if global_size[] > 1 - println("$(typeof(e)) on process $(global_rank[]):") - showerror(stdout, e, catch_backtrace()) + println(stderr, "$(typeof(e)) on process $(global_rank[]):") + showerror(stderr, e, catch_backtrace()) flush(stdout) flush(stderr) MPI.Abort(comm_world, 1) @@ -232,7 +232,7 @@ function setup_moment_kinetics(input_dict::AbstractDict; io_input, evolve_moments, t_input, z, z_spectral, r, r_spectral, vpa, vpa_spectral, vperp, vperp_spectral, gyrophase, gyrophase_spectral, vz, vz_spectral, vr, vr_spectral, vzeta, vzeta_spectral, composition, species, collisions, geometry, - drive_input, external_source_settings, num_diss_params, + em_input, external_source_settings, num_diss_params, manufactured_solns_input = input # Create loop range variables for shared-memory-parallel loops @@ -258,8 +258,7 @@ function setup_moment_kinetics(input_dict::AbstractDict; # create the "fields" structure that contains arrays # for the electrostatic potential phi and the electromagnetic fields fields = setup_em_fields(vperp.n, z.n, r.n, composition.n_ion_species, - drive_input.force_phi, drive_input.amplitude, - drive_input.frequency, drive_input.force_Er_zero_at_wall) + em_input) # Allocate arrays and create the pdf and moments structs pdf, moments, boundary_distributions = @@ -362,8 +361,8 @@ function setup_moment_kinetics(input_dict::AbstractDict; restart_time_index, previous_runs_info, time_for_setup, t_params, nl_solver_params) # write initial data to ascii files - write_data_to_ascii(pdf, moments, fields, vpa, vperp, z, r, t_params.t[], - composition.n_ion_species, composition.n_neutral_species, ascii_io) + write_data_to_ascii(pdf, moments, fields, vz, vr, vzeta, vpa, vperp, z, r, + t_params.t[], composition.n_ion_species, composition.n_neutral_species, ascii_io) # write initial data to binary files t_params.moments_output_counter[] += 1 diff --git a/moment_kinetics/src/moment_kinetics_input.jl b/moment_kinetics/src/moment_kinetics_input.jl index 87a29567e..4016c47ff 100644 --- a/moment_kinetics/src/moment_kinetics_input.jl +++ b/moment_kinetics/src/moment_kinetics_input.jl @@ -10,21 +10,22 @@ export read_input_file using ..type_definitions: mk_float, mk_int, OptionsDict using ..array_allocation: allocate_float using ..communication -using ..coordinates: define_coordinate +using ..coordinates: define_coordinate, get_coordinate_input using ..external_sources -using ..file_io: io_has_parallel, input_option_error, open_ascii_output_file +using ..file_io: io_has_parallel, input_option_error, open_ascii_output_file, + setup_io_input using ..krook_collisions: setup_krook_collisions_input using ..maxwell_diffusion: setup_mxwl_diff_collisions_input using ..fokker_planck: setup_fkpl_collisions_input using ..finite_differences: fd_check_option using ..input_structs +using ..manufactured_solns: setup_manufactured_solutions using ..numerical_dissipation: setup_numerical_dissipation using ..reference_parameters using ..geo: init_magnetic_geometry, setup_geometry_input using ..species_input: get_species_input using MPI using TOML -using UUIDs """ Read input from a TOML file @@ -33,8 +34,11 @@ function read_input_file(input_filename::String) input = TOML.parsefile(input_filename) # Use input_filename (without the extension) as default for "run_name" - if !("run_name" in keys(input)) - input["run_name"] = splitdir(splitext(input_filename)[1])[end] + if !("output" ∈ keys(input) && "run_name" in keys(input["output"])) + if !("output" ∈ keys(input)) + input["output"] = OptionsDict() + end + input["output"]["run_name"] = splitdir(splitext(input_filename)[1])[end] end return input @@ -49,86 +53,106 @@ false for other situations (e.g. when post-processing). `ignore_MPI` should be false when actually running a simulation, but defaults to true for other situations (e.g. when post-processing). """ -function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) +function mk_input(input_dict=OptionsDict(); save_inputs_to_txt=false, ignore_MPI=true) # Check for input options that used to exist, but do not any more. If these are # present, the user probably needs to update their input file. - removed_options_list = ("Bzed", "Bmag", "rhostar", "geometry_option", "pitch", "DeltaB", - "n_ion_species","n_neutral_species","recycling_fraction","gyrokinetic_ions","T_e","T_wall", - "z_IC_option1","z_IC_option2","vpa_IC_option1","vpa_IC_option2", - "boltzmann_electron_response","boltzmann_electron_response_with_simple_sheath", - "electron_physics","nstep","dt") + removed_options_list = ("Bzed", "Bmag", "rhostar", "geometry_option", "pitch", + "DeltaB", "n_ion_species", "n_neutral_species", + "recycling_fraction", "gyrokinetic_ions", "T_e", "T_wall", + "z_IC_option1", "z_IC_option2", "vpa_IC_option1", + "vpa_IC_option2", "boltzmann_electron_response", + "boltzmann_electron_response_with_simple_sheath", + "electron_physics", "nstep", "dt", + ("$(c)_$(opt)" + for c ∈ ("r", "z", "vperp", "vpa", "vzeta", "vr", "vz"), + opt ∈ ("ngrid", "nelement", "nelement_local", "L", + "discretization", "cheb_option", + "finite_difference_option", + "element_spacing_option", "bc") + )..., + "force_Er_zero_at_wall", "evolve_moments_density", + "evolve_moments_parallel_flow", + "evolve_moments_parallel_pressure", + "evolve_moments_conservation", "charge_exchange_frequency", + "electron_charge_exchange_frequency", "ionization_frequency", + "electron_ionization_frequency", "ionization_energy", "nu_ei", + "run_name", "base_directory", + ) for opt in removed_options_list - if opt ∈ keys(scan_input) - error("Option '$opt' is no longer used. Please update your input file. You " + if opt ∈ keys(input_dict) + error("Option '$opt' is no longer used. Please update your input file. The " + * "option may have been moved into an input file section - there are " + * "no longer any top-level options (i.e. ones not in a section). You " * "may need to set some new options to replicate the effect of the " * "removed ones.") end end # read composition and species data - composition = get_species_input(scan_input) + composition = get_species_input(input_dict) n_ion_species = composition.n_ion_species n_neutral_species = composition.n_neutral_species - z, r, vpa, vperp, gyrophase, vz, vr, vzeta, drive, evolve_moments = - load_defaults() - - # this is the prefix for all output files associated with this run - run_name = get(scan_input, "run_name", "wallBC") - # this is the directory where the simulation data will be stored - base_directory = get(scan_input, "base_directory", "runs") - output_dir = joinpath(base_directory, run_name) - # if evolve_moments.density = true, evolve density via continuity eqn # and g = f/n via modified drift kinetic equation - evolve_moments.density = get(scan_input, "evolve_moments_density", false) - evolve_moments.parallel_flow = get(scan_input, "evolve_moments_parallel_flow", false) - evolve_moments.parallel_pressure = get(scan_input, "evolve_moments_parallel_pressure", false) - evolve_moments.conservation = get(scan_input, "evolve_moments_conservation", false) + evolve_moments_settings = set_defaults_and_check_section!( + input_dict, "evolve_moments"; + density=false, + parallel_flow=false, + parallel_pressure=false, + moments_conservation=false, + ) + evolve_moments = Dict_to_NamedTuple(evolve_moments_settings) # Reference parameters that define the conversion between physical quantities and # normalised values used in the code. - reference_params = setup_reference_parameters(scan_input) + reference_params = setup_reference_parameters(input_dict) ## set geometry_input - geometry_in = setup_geometry_input(scan_input) + geometry_in = setup_geometry_input(input_dict) - charge_exchange = get(scan_input, "charge_exchange_frequency", 2.0*sqrt(composition.ion[1].initial_temperature)) - charge_exchange_electron = get(scan_input, "electron_charge_exchange_frequency", 0.0) - ionization = get(scan_input, "ionization_frequency", charge_exchange) - ionization_electron = get(scan_input, "electron_ionization_frequency", ionization) - ionization_energy = get(scan_input, "ionization_energy", 0.0) - nu_ei = get(scan_input, "nu_ei", 0.0) + em_input = set_defaults_and_check_section!( + input_dict, em_fields_input, "em_fields" + ) + + manufactured_solns_input = setup_manufactured_solutions(input_dict) + + reactions_input = set_defaults_and_check_section!( + input_dict, reactions + ) + electron_fluid_collisions_input = set_defaults_and_check_section!( + input_dict, electron_fluid_collisions + ) # set up krook collision inputs - krook_input = setup_krook_collisions_input(scan_input) + krook_input = setup_krook_collisions_input(input_dict) # set up Fokker-Planck collision inputs - fkpl_input = setup_fkpl_collisions_input(scan_input) + fkpl_input = setup_fkpl_collisions_input(input_dict) # set up maxwell diffusion collision inputs - mxwl_diff_input = setup_mxwl_diff_collisions_input(scan_input) + mxwl_diff_input = setup_mxwl_diff_collisions_input(input_dict) # write total collision struct using the structs above, as each setup function # for the collisions outputs itself a struct of the type of collision, which # is a substruct of the overall collisions_input struct. - collisions = collisions_input(charge_exchange, charge_exchange_electron, ionization, - ionization_electron, ionization_energy, nu_ei, + collisions = collisions_input(reactions_input, electron_fluid_collisions_input, krook_input, fkpl_input, mxwl_diff_input) + num_diss_params = setup_numerical_dissipation(input_dict) + # parameters related to the time stepping timestepping_section = set_defaults_and_check_section!( - scan_input, "timestepping"; + input_dict, "timestepping"; nstep=5, dt=0.00025/sqrt(composition.ion[1].initial_temperature), CFL_prefactor=-1.0, nwrite=1, - nwrite_dfns=nothing, + nwrite_dfns=-1, type="SSPRK4", split_operators=false, - stopfile_name=joinpath(output_dir, "stop"), steady_state_residual=false, converged_residual_value=-1.0, rtol=1.0e-5, atol=1.0e-12, - atol_upar=nothing, + atol_upar=-1.0, step_update_prefactor=0.9, max_increase_factor=1.05, max_increase_factor_near_last_fail=Inf, @@ -148,23 +172,23 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) if timestepping_section["nwrite"] > timestepping_section["nstep"] timestepping_section["nwrite"] = timestepping_section["nstep"] end - if timestepping_section["nwrite_dfns"] === nothing + if timestepping_section["nwrite_dfns"] < 0 timestepping_section["nwrite_dfns"] = timestepping_section["nstep"] elseif timestepping_section["nwrite_dfns"] > timestepping_section["nstep"] timestepping_section["nwrite_dfns"] = timestepping_section["nstep"] end - if timestepping_section["atol_upar"] === nothing + if timestepping_section["atol_upar"] < 0.0 timestepping_section["atol_upar"] = 1.0e-2 * timestepping_section["rtol"] end # parameters related to electron time stepping electron_timestepping_section = set_defaults_and_check_section!( - scan_input, "electron_timestepping"; + input_dict, "electron_timestepping"; nstep=50000, dt=timestepping_section["dt"] * sqrt(composition.me_over_mi), CFL_prefactor=timestepping_section["CFL_prefactor"], - nwrite=nothing, - nwrite_dfns=nothing, + nwrite=-1, + nwrite_dfns=-1, type=timestepping_section["type"], split_operators=false, converged_residual_value=1.0e-3, @@ -184,12 +208,12 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) no_restart=false, debug_io=false, ) - if electron_timestepping_section["nwrite"] === nothing + if electron_timestepping_section["nwrite"] < 0 electron_timestepping_section["nwrite"] = electron_timestepping_section["nstep"] elseif electron_timestepping_section["nwrite"] > electron_timestepping_section["nstep"] electron_timestepping_section["nwrite"] = electron_timestepping_section["nstep"] end - if electron_timestepping_section["nwrite_dfns"] === nothing + if electron_timestepping_section["nwrite_dfns"] < 0 electron_timestepping_section["nwrite_dfns"] = electron_timestepping_section["nstep"] elseif electron_timestepping_section["nwrite_dfns"] > electron_timestepping_section["nstep"] electron_timestepping_section["nwrite_dfns"] = electron_timestepping_section["nstep"] @@ -198,7 +222,6 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) # do not want to add a value to the `input_dict`. We also add a few dummy inputs that # are not actually used for electrons. electron_timestepping_section = copy(electron_timestepping_section) - electron_timestepping_section["stopfile_name"] = timestepping_section["stopfile_name"] electron_timestepping_section["atol_upar"] = NaN electron_timestepping_section["steady_state_residual"] = true if !(0.0 < electron_timestepping_section["step_update_prefactor"] < 1.0) @@ -278,343 +301,76 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) error("maximum_dt=$(timestepping_section["maximum_dt"]) must be positive") end - use_for_init_is_default = !(("manufactured_solns" ∈ keys(scan_input)) && - ("use_for_init" ∈ keys(scan_input["manufactured_solns"]))) - manufactured_solns_section = set_defaults_and_check_section!( - scan_input, "manufactured_solns"; - use_for_advance=false, - use_for_init=false, - # constant to be used to control Ez divergence in MMS tests - epsilon_offset=0.001, - # bool to control if dfni is a function of vpa or vpabar in MMS test - use_vpabar_in_mms_dfni=true, - alpha_switch=1.0, - type="default", - ) - if use_for_init_is_default && manufactured_solns_section["use_for_advance"] - # if manufactured_solns_section["use_for_init"] was set by default, set - # manufactured_solns_section["use_for_init"] == true - manufactured_solns_section["use_for_init"] = true - end - if manufactured_solns_section["use_for_init"] || manufactured_solns_section["use_for_advance"] - manufactured_solutions_ext = Base.get_extension(@__MODULE__, :manufactured_solns_ext) - if manufactured_solutions_ext === nothing - # If Symbolics is not installed, then the extension manufactured_solns_ext - # will not be loaded, in which case we cannot use manufactured solutions. - error("Symbolics package is not installed, so manufactured solutions are not " - * "available. Re-run machines/machine-setup.sh and activate " - * "manufactured solutions, or install Symbolics.") - end - end - if manufactured_solns_section["use_vpabar_in_mms_dfni"] - manufactured_solns_section["alpha_switch"] = 1.0 - else - manufactured_solns_section["alpha_switch"] = 0.0 - end - manufactured_solns_input = Dict_to_NamedTuple(manufactured_solns_section) - - # overwrite some default parameters related to the r grid - # ngrid is number of grid points per element - r.ngrid = get(scan_input, "r_ngrid", 9) - # nelement_global is the number of elements in total - r.nelement_global = get(scan_input, "r_nelement", 8) - # nelement_local is the number of elements on each process - r.nelement_local = get(scan_input, "r_nelement_local", r.nelement_global) - # L is the box length in units of cs0/Omega_i - r.L = get(scan_input, "r_L", 1.0) - # determine the discretization option for the r grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - r.discretization = get(scan_input, "r_discretization", "finite_difference") - r.fd_option = get(scan_input, "r_finite_difference_option", "third_order_upwind") - # determine the boundary condition to impose in r - # supported options are "periodic" and "Dirichlet" - r.bc = get(scan_input, "r_bc", "periodic") - r.element_spacing_option = get(scan_input, "r_element_spacing_option", "uniform") - - # overwrite some default parameters related to the z grid - # ngrid is number of grid points per element - z.ngrid = get(scan_input, "z_ngrid", 9) - # nelement_global is the number of elements in total - z.nelement_global = get(scan_input, "z_nelement", 8) - # nelement_local is the number of elements on each process - z.nelement_local = get(scan_input, "z_nelement_local", z.nelement_global) - # L is the box length in units of cs0/Omega_i - z.L = get(scan_input, "z_L", 1.0) - # determine the discretization option for the z grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - z.discretization = get(scan_input, "z_discretization", "chebyshev_pseudospectral") - z.fd_option = get(scan_input, "z_finite_difference_option", "third_order_upwind") - # determine the boundary condition to impose in z - # supported options are "constant", "periodic" and "wall" - z.bc = get(scan_input, "z_bc", "wall") - z.element_spacing_option = get(scan_input, "z_element_spacing_option", "uniform") - - # overwrite some default parameters related to the vpa grid - # ngrid is the number of grid points per element - vpa.ngrid = get(scan_input, "vpa_ngrid", 17) - # nelement is the number of elements - vpa.nelement_global = get(scan_input, "vpa_nelement", 10) - # do not parallelise vpa with distributed-memory MPI - vpa.nelement_local = vpa.nelement_global - # L is the box length in units of vthermal_species - vpa.L = get(scan_input, "vpa_L", 8.0*sqrt(composition.ion[1].initial_temperature)) - # determine the boundary condition - # only supported option at present is "zero" and "periodic" - vpa.bc = get(scan_input, "vpa_bc", "periodic") - # determine the discretization option for the vpa grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - vpa.discretization = get(scan_input, "vpa_discretization", "chebyshev_pseudospectral") - vpa.fd_option = get(scan_input, "vpa_finite_difference_option", "third_order_upwind") - vpa.element_spacing_option = get(scan_input, "vpa_element_spacing_option", "uniform") - - # overwrite some default parameters related to the vperp grid - # ngrid is the number of grid points per element - vperp.ngrid = get(scan_input, "vperp_ngrid", 1) - # nelement is the number of elements - vperp.nelement_global = get(scan_input, "vperp_nelement", 1) - # do not parallelise vperp with distributed-memory MPI - vperp.nelement_local = vperp.nelement_global - # L is the box length in units of vthermal_species - vperp.L = get(scan_input, "vperp_L", 8.0*sqrt(composition.ion[1].initial_temperature)) - # Note vperp.bc is set below, after numerical dissipation is initialized, so that it - # can use the numerical dissipation settings to set its default value. - # - # determine the discretization option for the vperp grid - # supported options are "finite_difference_vperp" "chebyshev_pseudospectral" - vperp.discretization = get(scan_input, "vperp_discretization", "chebyshev_pseudospectral") - vperp.element_spacing_option = get(scan_input, "vperp_element_spacing_option", "uniform") - - # overwrite some default parameters related to the gyrophase grid - # ngrid is the number of grid points per element - gyrophase.ngrid = get(scan_input, "gyrophase_ngrid", 17) - # nelement is the number of elements - gyrophase.nelement_global = get(scan_input, "gyrophase_nelement", 10) - # do not parallelise gyrophase with distributed-memory MPI - gyrophase.nelement_local = gyrophase.nelement_global - - if n_neutral_species > 0 - # overwrite some default parameters related to the vz grid - # use vpa grid values as defaults - # ngrid is the number of grid points per element - vz.ngrid = get(scan_input, "vz_ngrid", vpa.ngrid) - # nelement is the number of elements - vz.nelement_global = get(scan_input, "vz_nelement", vpa.nelement_global) - # do not parallelise vz with distributed-memory MPI - vz.nelement_local = vz.nelement_global - # L is the box length in units of vthermal_species - vz.L = get(scan_input, "vz_L", vpa.L) - # determine the boundary condition - # only supported option at present is "zero" and "periodic" - vz.bc = get(scan_input, "vz_bc", "none") - # determine the discretization option for the vz grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - vz.discretization = get(scan_input, "vz_discretization", vpa.discretization) - vz.element_spacing_option = get(scan_input, "vz_element_spacing_option", "uniform") - - # overwrite some default parameters related to the vr grid - # ngrid is the number of grid points per element - vr.ngrid = get(scan_input, "vr_ngrid", 1) - # nelement is the number of elements - vr.nelement_global = get(scan_input, "vr_nelement", 1) - # do not parallelise vz with distributed-memory MPI - vr.nelement_local = vr.nelement_global - # L is the box length in units of vthermal_species - vr.L = get(scan_input, "vr_L", 8.0*sqrt(composition.ion[1].initial_temperature)) - # determine the boundary condition - # only supported option at present is "zero" and "periodic" - vr.bc = get(scan_input, "vr_bc", "none") - # determine the discretization option for the vr grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - vr.discretization = get(scan_input, "vr_discretization", "chebyshev_pseudospectral") - vr.element_spacing_option = get(scan_input, "vr_element_spacing_option", "uniform") - - # overwrite some default parameters related to the vzeta grid - # ngrid is the number of grid points per element - vzeta.ngrid = get(scan_input, "vzeta_ngrid", 1) - # nelement is the number of elements - vzeta.nelement_global = get(scan_input, "vzeta_nelement", 1) - # do not parallelise vz with distributed-memory MPI - vzeta.nelement_local = vzeta.nelement_global - # L is the box length in units of vthermal_species - vzeta.L = get(scan_input, "vzeta_L", 8.0*sqrt(composition.ion[1].initial_temperature)) - # determine the boundary condition - # only supported option at present is "zero" and "periodic" - vzeta.bc = get(scan_input, "vzeta_bc", "none") - # determine the discretization option for the vzeta grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - vzeta.discretization = get(scan_input, "vzeta_discretization", "chebyshev_pseudospectral") - vzeta.element_spacing_option = get(scan_input, "vzeta_element_spacing_option", "uniform") - end - - is_1V = (vperp.ngrid == vperp.nelement_global == 1 && vzeta.ngrid == - vzeta.nelement_global == 1 && vr.ngrid == vr.nelement_global == 1) - - ion_num_diss_param_dict = get(scan_input, "ion_numerical_dissipation", OptionsDict()) - electron_num_diss_param_dict = get(scan_input, "electron_numerical_dissipation", OptionsDict()) - neutral_num_diss_param_dict = get(scan_input, "neutral_numerical_dissipation", OptionsDict()) - num_diss_params = setup_numerical_dissipation(ion_num_diss_param_dict, - electron_num_diss_param_dict, - neutral_num_diss_param_dict, is_1V) - - # vperp.bc is set here (a bit out of place) so that we can use - # num_diss_params.ion.vperp_dissipation_coefficient to set the default. - vperp.bc = get(scan_input, "vperp_bc", - ( collisions.fkpl.nuii > 0.0 || - num_diss_params.ion.vperp_dissipation_coefficient > 0.0) ? - "zero" : "none") - - ######################################################################### - ########## end user inputs. do not modify following code! ############### - ######################################################################### - # set up distributed-memory MPI information for z and r coords # need grid and MPI information to determine these values # MRH just put dummy values now + r_coord_input = get_coordinate_input(input_dict, "r"; ignore_MPI=ignore_MPI) + z_coord_input = get_coordinate_input(input_dict, "z"; ignore_MPI=ignore_MPI) if ignore_MPI irank_z = irank_r = 0 nrank_z = nrank_r = 1 comm_sub_z = comm_sub_r = MPI.COMM_NULL - r.nelement_local = r.nelement_global - z.nelement_local = z.nelement_global - vperp.nelement_local = vperp.nelement_global - vpa.nelement_local = vpa.nelement_global - vzeta.nelement_local = vzeta.nelement_global - vr.nelement_local = vr.nelement_global - vz.nelement_local = vz.nelement_global else - irank_z, nrank_z, comm_sub_z, irank_r, nrank_r, comm_sub_r = setup_distributed_memory_MPI(z.nelement_global,z.nelement_local,r.nelement_global,r.nelement_local) - end - #comm_sub_r = false - #irank_r = 0 - #nrank_r = 0 - #comm_sub_z = false - #irank_z = 0 - #nrank_z = 0 - - # Create output_dir if it does not exist. - if !ignore_MPI - if global_rank[] == 0 - mkpath(output_dir) - end - _block_synchronize() + irank_z, nrank_z, comm_sub_z, irank_r, nrank_r, comm_sub_r = + setup_distributed_memory_MPI(z_coord_input.nelement, + z_coord_input.nelement_local, + r_coord_input.nelement, + r_coord_input.nelement_local) end - # replace mutable structures with immutable ones to optimize performance - # and avoid possible misunderstandings - z_advection_immutable = advection_input(z.advection.option, z.advection.constant_speed, - z.advection.frequency, z.advection.oscillation_amplitude) - z_immutable = grid_input("z", z.ngrid, z.nelement_global, z.nelement_local, nrank_z, irank_z, z.L, - z.discretization, z.fd_option, z.cheb_option, z.bc, z_advection_immutable, comm_sub_z, z.element_spacing_option) - r_advection_immutable = advection_input(r.advection.option, r.advection.constant_speed, - r.advection.frequency, r.advection.oscillation_amplitude) - r_immutable = grid_input("r", r.ngrid, r.nelement_global, r.nelement_local, nrank_r, irank_r, r.L, - r.discretization, r.fd_option, r.cheb_option, r.bc, r_advection_immutable, comm_sub_r, r.element_spacing_option) - # for dimensions below which do not currently use distributed-memory MPI - # assign dummy values to nrank, irank and comm of coord struct - vpa_advection_immutable = advection_input(vpa.advection.option, vpa.advection.constant_speed, - vpa.advection.frequency, vpa.advection.oscillation_amplitude) - vpa_immutable = grid_input("vpa", vpa.ngrid, vpa.nelement_global, vpa.nelement_local, 1, 0, vpa.L, - vpa.discretization, vpa.fd_option, vpa.cheb_option, vpa.bc, vpa_advection_immutable, MPI.COMM_NULL, vpa.element_spacing_option) - vperp_advection_immutable = advection_input(vperp.advection.option, vperp.advection.constant_speed, - vperp.advection.frequency, vperp.advection.oscillation_amplitude) - vperp_immutable = grid_input("vperp", vperp.ngrid, vperp.nelement_global, vperp.nelement_local, 1, 0, vperp.L, - vperp.discretization, vperp.fd_option, vperp.cheb_option, vperp.bc, vperp_advection_immutable, MPI.COMM_NULL, vperp.element_spacing_option) - gyrophase_advection_immutable = advection_input(gyrophase.advection.option, gyrophase.advection.constant_speed, - gyrophase.advection.frequency, gyrophase.advection.oscillation_amplitude) - gyrophase_immutable = grid_input("gyrophase", gyrophase.ngrid, gyrophase.nelement_global, gyrophase.nelement_local, 1, 0, gyrophase.L, - gyrophase.discretization, gyrophase.fd_option, gyrophase.cheb_option, gyrophase.bc, gyrophase_advection_immutable, MPI.COMM_NULL, gyrophase.element_spacing_option) - vz_advection_immutable = advection_input(vz.advection.option, vz.advection.constant_speed, - vz.advection.frequency, vz.advection.oscillation_amplitude) - vz_immutable = grid_input("vz", vz.ngrid, vz.nelement_global, vz.nelement_local, 1, 0, vz.L, - vz.discretization, vz.fd_option, vz.cheb_option, vz.bc, vz_advection_immutable, MPI.COMM_NULL, vz.element_spacing_option) - vr_advection_immutable = advection_input(vr.advection.option, vr.advection.constant_speed, - vr.advection.frequency, vr.advection.oscillation_amplitude) - vr_immutable = grid_input("vr", vr.ngrid, vr.nelement_global, vr.nelement_local, 1, 0, vr.L, - vr.discretization, vr.fd_option, vr.cheb_option, vr.bc, vr_advection_immutable, MPI.COMM_NULL, vr.element_spacing_option) - vzeta_advection_immutable = advection_input(vzeta.advection.option, vzeta.advection.constant_speed, - vzeta.advection.frequency, vzeta.advection.oscillation_amplitude) - vzeta_immutable = grid_input("vzeta", vzeta.ngrid, vzeta.nelement_global, vzeta.nelement_local, 1, 0, vzeta.L, - vzeta.discretization, vzeta.fd_option, vzeta.cheb_option, vzeta.bc, vzeta_advection_immutable, MPI.COMM_NULL, vzeta.element_spacing_option) - - force_Er_zero = get(scan_input, "force_Er_zero_at_wall", false) - drive_immutable = drive_input(drive.force_phi, drive.amplitude, drive.frequency, force_Er_zero) + io_immutable = setup_io_input(input_dict, timestepping_section; ignore_MPI=ignore_MPI) - # inputs for file I/O - io_settings = set_defaults_and_check_section!( - scan_input, "output"; - ascii_output=false, - binary_format=hdf5, - parallel_io=nothing, - ) - if io_settings["parallel_io"] === nothing - io_settings["parallel_io"] = io_has_parallel(Val(io_settings["binary_format"])) - end - # Make copy of the section to avoid modifying the passed-in Dict - io_settings = copy(io_settings) - run_id = string(uuid4()) - if !ignore_MPI - # Communicate run_id to all blocks - # Need to convert run_id to a Vector{Char} for MPI - run_id_chars = [run_id...] - MPI.Bcast!(run_id_chars, 0, comm_world) - run_id = string(run_id_chars...) - end - io_settings["run_id"] = run_id - io_settings["output_dir"] = output_dir - io_settings["run_name"] = run_name - io_settings["write_error_diagnostics"] = timestepping_section["write_error_diagnostics"] - io_settings["write_steady_state_diagnostics"] = timestepping_section["write_steady_state_diagnostics"] - io_settings["write_electron_error_diagnostics"] = timestepping_section["electron_t_input"]["write_error_diagnostics"] - io_settings["write_electron_steady_state_diagnostics"] = timestepping_section["electron_t_input"]["write_steady_state_diagnostics"] - io_immutable = Dict_to_NamedTuple(io_settings) + # this is the directory where the simulation data will be stored + timestepping_section["stopfile_name"] = joinpath(io_immutable.output_dir, "stop") + electron_timestepping_section["stopfile_name"] = joinpath(io_immutable.output_dir, "stop") # initialize z grid and write grid point locations to file if ignore_MPI run_directory = nothing else - run_directory = output_dir + run_directory = io_immutable.output_dir end - z, z_spectral = define_coordinate(z_immutable, scan_input, io_immutable.parallel_io; - run_directory=run_directory, ignore_MPI=ignore_MPI) + z, z_spectral = define_coordinate(z_coord_input; parallel_io=io_immutable.parallel_io, + run_directory=run_directory, ignore_MPI=ignore_MPI, + irank=irank_z, nrank=nrank_z, comm=comm_sub_z) # initialize r grid and write grid point locations to file - r, r_spectral = define_coordinate(r_immutable, scan_input, io_immutable.parallel_io; - run_directory=run_directory, ignore_MPI=ignore_MPI) + r, r_spectral = define_coordinate(r_coord_input; parallel_io=io_immutable.parallel_io, + run_directory=run_directory, ignore_MPI=ignore_MPI, + irank=irank_r, nrank=nrank_r, comm=comm_sub_r) # initialize vpa grid and write grid point locations to file - vpa, vpa_spectral = define_coordinate(vpa_immutable, scan_input, io_immutable.parallel_io; + vpa, vpa_spectral = define_coordinate(input_dict, "vpa"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) # initialize vperp grid and write grid point locations to file - vperp, vperp_spectral = define_coordinate(vperp_immutable, scan_input, io_immutable.parallel_io; + vperp, vperp_spectral = define_coordinate(input_dict, "vperp"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) # initialize gyrophase grid and write grid point locations to file - gyrophase, gyrophase_spectral = define_coordinate(gyrophase_immutable, - scan_input, io_immutable.parallel_io; + gyrophase, gyrophase_spectral = define_coordinate(input_dict, "gyrophase"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) # initialize vz grid and write grid point locations to file - vz, vz_spectral = define_coordinate(vz_immutable, scan_input, io_immutable.parallel_io; + vz, vz_spectral = define_coordinate(input_dict, "vz"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) # initialize vr grid and write grid point locations to file - vr, vr_spectral = define_coordinate(vr_immutable, scan_input, io_immutable.parallel_io; + vr, vr_spectral = define_coordinate(input_dict, "vr"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) # initialize vr grid and write grid point locations to file - vzeta, vzeta_spectral = define_coordinate(vzeta_immutable, scan_input, io_immutable.parallel_io; + vzeta, vzeta_spectral = define_coordinate(input_dict, "vzeta"; + parallel_io=io_immutable.parallel_io, run_directory=run_directory, ignore_MPI=ignore_MPI) - external_source_settings = setup_external_sources!(scan_input, r, z, + external_source_settings = setup_external_sources!(input_dict, r, z, composition.electron_physics) - if global_rank[] == 0 && save_inputs_to_txt - # Make file to log some information about inputs into. - io = open_ascii_output_file(string(output_dir,"/",run_name), "input") - else - io = devnull - end - geometry = init_magnetic_geometry(geometry_in,z,r) if any(geometry.dBdz .!= 0.0) && (evolve_moments.density || evolve_moments.parallel_flow || @@ -623,18 +379,35 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) end species_immutable = (ion = composition.ion, neutral = composition.neutral) + + # Ideally `check_sections!(input_dict) would be called here to check that no + # unexpected sections or top-level options were passed (helps to catch typos in input + # files). However, it needs to be called after calls to `setup_nonlinear_solve()` + # because the inputs for nonlinear solvers are only read there, but before electron + # setup, because `input_dict` needs to be written to the output files, and it cannot + # be with the `_section_check_store` variable still contained in it (which is used and + # removed by `check_sections!()`) - it therefore has to be called in the middle of + # `setup_time_advance!()`. + + if global_rank[] == 0 && save_inputs_to_txt + # Make file to log some information about inputs into. + io = open_ascii_output_file(joinpath(io_immutable.output_dir, io_immutable.run_name), "input") + else + io = devnull + end # check input (and initialized coordinate structs) to catch errors/unsupported options - check_input(io, output_dir, timestepping_section["nstep"], timestepping_section["dt"], r, z, - vpa, vperp, composition, species_immutable, evolve_moments, - num_diss_params, save_inputs_to_txt, collisions) + check_input(io, io_immutable.output_dir, timestepping_section["nstep"], + timestepping_section["dt"], r, z, vpa, vperp, composition, + species_immutable, evolve_moments, num_diss_params, save_inputs_to_txt, + collisions) # return immutable structs for z, vpa, species and composition all_inputs = (io_immutable, evolve_moments, timestepping_section, z, z_spectral, r, r_spectral, vpa, vpa_spectral, vperp, vperp_spectral, gyrophase, gyrophase_spectral, vz, vz_spectral, vr, vr_spectral, vzeta, vzeta_spectral, composition, species_immutable, collisions, geometry, - drive_immutable, external_source_settings, num_diss_params, + em_input, external_source_settings, num_diss_params, manufactured_solns_input) println(io, "\nAll inputs returned from mk_input():") println(io, all_inputs) @@ -643,336 +416,6 @@ function mk_input(scan_input=Dict(); save_inputs_to_txt=false, ignore_MPI=true) return all_inputs end -""" -""" -function load_defaults() - ############## options related to the equations being solved ############### - evolve_density = false - evolve_parallel_flow = false - evolve_parallel_pressure = false - conservation = true - #advective_form = false - evolve_moments = evolve_moments_options(evolve_density, evolve_parallel_flow, evolve_parallel_pressure, conservation)#advective_form) - # cheb option switch - cheb_option = "FFT" # "matrix" # - #################### parameters related to the z grid ###################### - # ngrid_z is number of grid points per element - ngrid_z = 100 - # nelement_z is the number of elements on each process - nelement_local_z = 1 - # nelement_z is the number of elements in total - nelement_global_z = 1 - # L_z is the box length in z - L_z = 1.0 - # determine the boundary condition in z - # currently supported options are "constant" and "periodic" - boundary_option_z = "periodic" - #boundary_option_z = "constant" - # determine the discretization option for the z grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - #discretization_option_z = "chebyshev_pseudospectral" - discretization_option_z = "finite_difference" - # if discretization_option_z = "finite_difference", then - # finite_difference_option_z determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_z = "first_order_upwind" - #finite_difference_option_z = "second_order_upwind" - finite_difference_option_z = "third_order_upwind" - #cheb_option_z = "FFT" # "matrix" - cheb_option_z = cheb_option - # determine the option used for the advection speed in z - # supported options are "constant" and "oscillating", - # in addition to the "default" option which uses dz/dt = vpa as the advection speed - advection_option_z = "default" - # constant advection speed in z to use with advection_option_z = "constant" - advection_speed_z = 1.0 - # for advection_option_z = "oscillating", advection speed is of form - # speed = advection_speed_z*(1 + oscillation_amplitude_z*sinpi(frequency_z*t)) - frequency_z = 1.0 - oscillation_amplitude_z = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_z = advection_input_mutable(advection_option_z, advection_speed_z, - frequency_z, oscillation_amplitude_z) - element_spacing_option_z = "uniform" - # create a mutable structure containing the input info related to the z grid - z = grid_input_mutable("z", ngrid_z, nelement_global_z, nelement_local_z, L_z, - discretization_option_z, finite_difference_option_z, cheb_option_z, boundary_option_z, - advection_z, element_spacing_option_z) - #################### parameters related to the r grid ###################### - # ngrid_r is number of grid points per element - ngrid_r = 1 - # nelement_r is the number of elements in total - nelement_global_r = 1 - # nelement_r is the number of elements on each process - nelement_local_r = 1 - # L_r is the box length in r - L_r = 1.0 - # determine the boundary condition in r - # currently supported options are "constant" and "periodic" - boundary_option_r = "periodic" - #boundary_option_r = "constant" - # determine the discretization option for the r grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - #discretization_option_r = "chebyshev_pseudospectral" - discretization_option_r = "finite_difference" - # if discretization_option_r = "finite_difference", then - # finite_difference_option_r determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_r = "first_order_upwind" - #finite_difference_option_r = "second_order_upwind" - finite_difference_option_r = "third_order_upwind" - #cheb_option_r = "FFT" #"matrix" - cheb_option_r = cheb_option - # determine the option used for the advection speed in r - # supported options are "constant" and "oscillating", - # in addition to the "default" option which uses dr/dt = vpa as the advection speed - advection_option_r = "default" # MRH -- NEED TO CHANGE THIS ASAP! - # constant advection speed in r to use with advection_option_r = "constant" - advection_speed_r = 1.0 - # for advection_option_r = "oscillating", advection speed is of form - # speed = advection_speed_r*(1 + oscillation_amplitude_r*sinpi(frequency_r*t)) - frequency_r = 1.0 - oscillation_amplitude_r = 1.0 - # mutable struct containing advection speed options/inputs for r - advection_r = advection_input_mutable(advection_option_r, advection_speed_r, - frequency_r, oscillation_amplitude_r) - element_spacing_option_r = "uniform" - # create a mutable structure containing the input info related to the r grid - r = grid_input_mutable("r", ngrid_r, nelement_global_r, nelement_local_r, L_r, - discretization_option_r, finite_difference_option_r, cheb_option_r, boundary_option_r, - advection_r, element_spacing_option_r) - ############################################################################ - ################### parameters related to the vpa grid ##################### - # ngrid_vpa is the number of grid points per element - ngrid_vpa = 300 - # nelement_vpa is the number of elements - nelement_vpa = 1 - # L_vpa is the box length in units of vthermal_species - L_vpa = 6.0 - # determine the boundary condition - # currently supported options are "zero" and "periodic" - #boundary_option_vpa = "zero" - boundary_option_vpa = "periodic" - # determine the discretization option for the vpa grid - # supported options are "chebyshev_pseudospectral" and "finite_difference" - #discretization_option_vpa = "chebyshev_pseudospectral" - discretization_option_vpa = "finite_difference" - # if discretization_option_vpa = "finite_difference", then - # finite_difference_option_vpa determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_vpa = "second_order_upwind" - finite_difference_option_vpa = "third_order_upwind" - #cheb_option_vpa = "FFT" # "matrix" - cheb_option_vpa = cheb_option - # determine the option used for the advection speed in vpa - # supported options are "constant" and "oscillating", - # in addition to the "default" option which uses dvpa/dt = q*Ez/m as the advection speed - advection_option_vpa = "default" - # constant advection speed in vpa to use with advection_option_vpa = "constant" - advection_speed_vpa = 1.0 - # for advection_option_vpa = "oscillating", advection speed is of form - # speed = advection_speed_vpa*(1 + oscillation_amplitude_vpa*sinpi(frequency_vpa*t)) - frequency_vpa = 1.0 - oscillation_amplitude_vpa = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_vpa = advection_input_mutable(advection_option_vpa, advection_speed_vpa, - frequency_vpa, oscillation_amplitude_vpa) - element_spacing_option_vpa = "uniform" - # create a mutable structure containing the input info related to the vpa grid - vpa = grid_input_mutable("vpa", ngrid_vpa, nelement_vpa, nelement_vpa, L_vpa, - discretization_option_vpa, finite_difference_option_vpa, cheb_option_vpa, boundary_option_vpa, - advection_vpa, element_spacing_option_vpa) - ############################################################################ - ################### parameters related to the vperp grid ##################### - # ngrid_vperp is the number of grid points per element - ngrid_vperp = 1 - # nelement_vperp is the number of elements - nelement_vperp = 1 - # L_vperp is the box length in units of vthermal_species - L_vperp = 6.0 - # determine the boundary condition - # currently supported options are "zero" and "periodic" - # MRH probably need new bc option here - #boundary_option_vperp = "zero" - boundary_option_vperp = "periodic" - # determine the discretization option for the vperp grid - # supported options are "finite_difference_vperp" - discretization_option_vperp = "finite_difference_vperp" - # if discretization_option_vperp = "finite_difference_vperp", then - # finite_difference_option_vperp determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_vperp = "second_order_upwind" - finite_difference_option_vperp = "third_order_upwind" - #cheb_option_vperp = "FFT" # "matrix" - cheb_option_vperp = cheb_option - # determine the option used for the advection speed in vperp - # supported options are "constant" and "oscillating", - advection_option_vperp = "default" - # constant advection speed in vperp to use with advection_option_vperp = "constant" - advection_speed_vperp = 0.0 - # for advection_option_vperp = "oscillating", advection speed is of form - # speed = advection_speed_vperp*(1 + oscillation_amplitude_vperp*sinpi(frequency_vperp*t)) - frequency_vperp = 1.0 - oscillation_amplitude_vperp = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_vperp = advection_input_mutable(advection_option_vperp, advection_speed_vperp, - frequency_vperp, oscillation_amplitude_vperp) - element_spacing_option_vperp = "uniform" - # create a mutable structure containing the input info related to the vperp grid - vperp = grid_input_mutable("vperp", ngrid_vperp, nelement_vperp, nelement_vperp, L_vperp, - discretization_option_vperp, finite_difference_option_vperp, cheb_option_vperp, boundary_option_vperp, - advection_vperp, element_spacing_option_vperp) - ############################################################################ - ################### parameters related to the gyrophase grid ##################### - # ngrid_gyrophase is the number of grid points per element - ngrid_gyrophase = 300 - # nelement_gyrophase is the number of elements - nelement_gyrophase = 1 - # L_gyrophase is the box length in units of vthermal_species - L_gyrophase = 2*pi - # determine the boundary condition - # currently supported option is "periodic" - boundary_option_gyrophase = "periodic" - discretization_option_gyrophase = "finite_difference" - finite_difference_option_gyrophase = "third_order_upwind" - #cheb_option_gyrophase = "FFT" #"matrix" - cheb_option_gyrophase = cheb_option - advection_option_gyrophase = "default" - advection_speed_gyrophase = 0.0 - frequency_gyrophase = 1.0 - oscillation_amplitude_gyrophase = 1.0 - advection_gyrophase = advection_input_mutable(advection_option_gyrophase, advection_speed_gyrophase, - frequency_gyrophase, oscillation_amplitude_gyrophase) - element_spacing_option_gyrophase = "uniform" - # create a mutable structure containing the input info related to the gyrophase grid - gyrophase = grid_input_mutable("gyrophase", ngrid_gyrophase, nelement_gyrophase, nelement_gyrophase, L_gyrophase, - discretization_option_gyrophase, finite_difference_option_gyrophase, cheb_option_gyrophase, boundary_option_gyrophase, - advection_gyrophase, element_spacing_option_gyrophase) - ############################################################################ - ################### parameters related to the vr grid ##################### - # ngrid_vr is the number of grid points per element - ngrid_vr = 1 - # nelement_vr is the number of elements - nelement_vr = 1 - # L_vr is the box length in units of vthermal_species - L_vr = 1.0 - # determine the boundary condition - # currently supported options are "zero" and "periodic" - boundary_option_vr = "periodic" - # determine the discretization option for the vr grid - # supported options are "finite_difference" "chebyshev_pseudospectral" - discretization_option_vr = "chebyshev_pseudospectral" - # if discretization_option_vr = "finite_difference", then - # finite_difference_option_vr determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_vr = "second_order_upwind" - finite_difference_option_vr = "third_order_upwind" - #cheb_option_vr = "FFT" # "matrix" - cheb_option_vr = cheb_option - # determine the option used for the advection speed in vr - # supported options are "constant" and "oscillating", - advection_option_vr = "default" - # constant advection speed in vr to use with advection_option_vr = "constant" - advection_speed_vr = 0.0 - # for advection_option_vr = "oscillating", advection speed is of form - # speed = advection_speed_vr*(1 + oscillation_amplitude_vr*sinpi(frequency_vr*t)) - frequency_vr = 1.0 - oscillation_amplitude_vr = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_vr = advection_input_mutable(advection_option_vr, advection_speed_vr, - frequency_vr, oscillation_amplitude_vr) - element_spacing_option_vr = "uniform" - # create a mutable structure containing the input info related to the vr grid - vr = grid_input_mutable("vr", ngrid_vr, nelement_vr, nelement_vr, L_vr, - discretization_option_vr, finite_difference_option_vr, cheb_option_vr, boundary_option_vr, - advection_vr, element_spacing_option_vr) - ############################################################################ - ################### parameters related to the vz grid ##################### - # ngrid_vz is the number of grid points per element - ngrid_vz = 1 - # nelement_vz is the number of elements - nelement_vz = 1 - # L_vz is the box length in units of vthermal_species - L_vz = 1.0 - # determine the boundary condition - # currently supported options are "zero" and "periodic" - boundary_option_vz = "periodic" - # determine the discretization option for the vz grid - # supported options are "finite_difference" "chebyshev_pseudospectral" - discretization_option_vz = "chebyshev_pseudospectral" - # if discretization_option_vz = "finite_difference", then - # finite_difference_option_vz determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_vz = "second_order_upwind" - finite_difference_option_vz = "third_order_upwind" - #cheb_option_vz = "FFT" # "matrix" - cheb_option_vz = cheb_option - # determine the option used for the advection speed in vz - # supported options are "constant" and "oscillating", - advection_option_vz = "default" - # constant advection speed in vz to use with advection_option_vz = "constant" - advection_speed_vz = 0.0 - # for advection_option_vz = "oscillating", advection speed is of form - # speed = advection_speed_vz*(1 + oscillation_amplitude_vz*sinpi(frequency_vz*t)) - frequency_vz = 1.0 - oscillation_amplitude_vz = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_vz = advection_input_mutable(advection_option_vz, advection_speed_vz, - frequency_vz, oscillation_amplitude_vz) - element_spacing_option_vz = "uniform" - # create a mutable structure containing the input info related to the vz grid - vz = grid_input_mutable("vz", ngrid_vz, nelement_vz, nelement_vz, L_vz, - discretization_option_vz, finite_difference_option_vz, cheb_option_vz, boundary_option_vz, - advection_vz, element_spacing_option_vz) - ############################################################################ - ################### parameters related to the vzeta grid ##################### - # ngrid_vzeta is the number of grid points per element - ngrid_vzeta = 1 - # nelement_vzeta is the number of elements - nelement_vzeta = 1 - # L_vzeta is the box length in units of vthermal_species - L_vzeta =1.0 - # determine the boundary condition - # currently supported options are "zero" and "periodic" - boundary_option_vzeta = "periodic" - # determine the discretization option for the vzeta grid - # supported options are "finite_difference" "chebyshev_pseudospectral" - discretization_option_vzeta = "chebyshev_pseudospectral" - # if discretization_option_vzeta = "finite_difference", then - # finite_difference_option_vzeta determines the finite difference scheme to be used - # supported options are "third_order_upwind", "second_order_upwind" and "first_order_upwind" - #finite_difference_option_vzeta = "second_order_upwind" - finite_difference_option_vzeta = "third_order_upwind" - #cheb_option_vzeta = "FFT" # "matrix" - cheb_option_vzeta = cheb_option - # determine the option used for the advection speed in vzeta - # supported options are "constant" and "oscillating", - advection_option_vzeta = "default" - # constant advection speed in vzeta to use with advection_option_vzeta = "constant" - advection_speed_vzeta = 0.0 - # for advection_option_vzeta = "oscillating", advection speed is of form - # speed = advection_speed_vzeta*(1 + oscillation_amplitude_vzeta*sinpi(frequency_vzeta*t)) - frequency_vzeta = 1.0 - oscillation_amplitude_vzeta = 1.0 - # mutable struct containing advection speed options/inputs for z - advection_vzeta = advection_input_mutable(advection_option_vzeta, advection_speed_vzeta, - frequency_vzeta, oscillation_amplitude_vzeta) - element_spacing_option_vzeta = "uniform" - # create a mutable structure containing the input info related to the vzeta grid - vzeta = grid_input_mutable("vzeta", ngrid_vzeta, nelement_vzeta, nelement_vzeta, L_vzeta, - discretization_option_vzeta, finite_difference_option_vzeta, cheb_option_vzeta, boundary_option_vzeta, - advection_vzeta, element_spacing_option_vzeta) - - # if drive_phi = true, include external electrostatic potential of form - # phi(z,t=0)*drive_amplitude*sinpi(time*drive_frequency) - drive_phi = false - drive_amplitude = 1.0 - drive_frequency = 1.0 - drive = drive_input_mutable(drive_phi, drive_amplitude, drive_frequency) - - return z, r, vpa, vperp, gyrophase, vz, vr, vzeta, drive, evolve_moments -end - """ check various input options to ensure they are all valid/consistent """ @@ -990,9 +433,8 @@ function check_input(io, output_dir, nstep, dt, r, z, vpa, vperp, composition, s check_coordinate_input(vperp, "vperp", io) # if the parallel flow is evolved separately, then the density must also be evolved separately if evolve_moments.parallel_flow && !evolve_moments.density - print(io,">evolve_moments.parallel_flow = true, but evolve_moments.density = false.") - println(io, "this is not a supported option. forcing evolve_moments.density = true.") - evolve_moments.density = true + error("evolve_moments.parallel_flow = true, but evolve_moments.density = false." + * "this is not a supported option.") end if collisions.fkpl.nuii > 0.0 # check that the grids support the collision operator @@ -1035,9 +477,9 @@ function check_coordinate_input(coord, coord_name, io) println(io,"using a Gauss-Legendre-Lobatto pseudospectral method in $coord_name.") elseif coord.discretization == "finite_difference" println(io,">$coord_name.discretization = 'finite_difference', ", - "and $coord_name.fd_option = ", coord.fd_option, + "and $coord_name.finite_difference_option = ", coord.finite_difference_option, " using finite differences on an equally spaced grid in $coord_name.") - fd_check_option(coord.fd_option, coord.ngrid) + fd_check_option(coord.finite_difference_option, coord.ngrid) else input_option_error("$coord_name.discretization", coord.discretization) end diff --git a/moment_kinetics/src/moment_kinetics_structs.jl b/moment_kinetics/src/moment_kinetics_structs.jl index acb1a378e..a1ef580e2 100644 --- a/moment_kinetics/src/moment_kinetics_structs.jl +++ b/moment_kinetics/src/moment_kinetics_structs.jl @@ -56,11 +56,6 @@ struct em_fields_struct gEr::MPISharedArray{mk_float,4} # gEz is the gyroaveraged parallel electric field gEz::MPISharedArray{mk_float,4} - # if including an external forcing for phi, it is of the form - # phi_external = phi0*drive_amplitude*sinpi(t*drive_frequency) - force_phi::Bool - drive_amplitude::mk_float - drive_frequency::mk_float # if true, force Er = 0 at wall plates force_Er_zero_at_wall::Bool end @@ -132,18 +127,18 @@ struct moments_ion_substruct dvth_dz::Union{MPISharedArray{mk_float,3},Nothing} # this is the entropy production dS/dt = - int (ln f sum_s' C_ss' [f_s,f_s']) d^3 v dSdt::MPISharedArray{mk_float,3} - # Spatially varying amplitude of the external source term - external_source_amplitude::MPISharedArray{mk_float,2} + # Spatially varying amplitude of the external source term (third index is for different sources) + external_source_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the density moment of the external source term - external_source_density_amplitude::MPISharedArray{mk_float,2} + external_source_density_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel momentum moment of the external source # term - external_source_momentum_amplitude::MPISharedArray{mk_float,2} + external_source_momentum_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel pressure moment of the external source # term - external_source_pressure_amplitude::MPISharedArray{mk_float,2} + external_source_pressure_amplitude::MPISharedArray{mk_float,3} # Integral term for the PID controller of the external source term - external_source_controller_integral::MPISharedArray{mk_float,2} + external_source_controller_integral::MPISharedArray{mk_float,3} # Store coefficient 'A' from applying moment constraints so we can write it out as a # diagnostic constraints_A_coefficient::Union{MPISharedArray{mk_float,3},Nothing} @@ -184,15 +179,15 @@ struct moments_electron_substruct # this is the parallel friction force between ions and electrons parallel_friction::MPISharedArray{mk_float,2} # Spatially varying amplitude of the external source term - external_source_amplitude::MPISharedArray{mk_float,2} + external_source_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the density moment of the external source term - external_source_density_amplitude::MPISharedArray{mk_float,2} + external_source_density_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel momentum moment of the external source # term - external_source_momentum_amplitude::MPISharedArray{mk_float,2} + external_source_momentum_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel pressure moment of the external source # term - external_source_pressure_amplitude::MPISharedArray{mk_float,2} + external_source_pressure_amplitude::MPISharedArray{mk_float,3} # if evolve_ppar = true, then the velocity variable is (vpa - upa)/vth, which introduces # a factor of vth for each power of wpa in velocity space integrals. # v_norm_fac accounts for this: it is vth if using the above definition for the parallel velocity, @@ -297,17 +292,17 @@ struct moments_neutral_substruct # this is the z-derivative of the heat flux along z dqz_dz::Union{MPISharedArray{mk_float,3},Nothing} # Spatially varying amplitude of the external source term - external_source_amplitude::MPISharedArray{mk_float,2} + external_source_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the density moment of the external source term - external_source_density_amplitude::MPISharedArray{mk_float,2} + external_source_density_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel momentum moment of the external source # term - external_source_momentum_amplitude::MPISharedArray{mk_float,2} + external_source_momentum_amplitude::MPISharedArray{mk_float,3} # Spatially varying amplitude of the parallel pressure moment of the external source # term - external_source_pressure_amplitude::MPISharedArray{mk_float,2} + external_source_pressure_amplitude::MPISharedArray{mk_float,3} # Integral term for the PID controller of the external source term - external_source_controller_integral::MPISharedArray{mk_float,2} + external_source_controller_integral::MPISharedArray{mk_float,3} # Store coefficient 'A' from applying moment constraints so we can write it out as a # diagnostic constraints_A_coefficient::Union{MPISharedArray{mk_float,3},Nothing} diff --git a/moment_kinetics/src/neutral_vz_advection.jl b/moment_kinetics/src/neutral_vz_advection.jl index 96b61cd39..79858a22f 100644 --- a/moment_kinetics/src/neutral_vz_advection.jl +++ b/moment_kinetics/src/neutral_vz_advection.jl @@ -111,10 +111,12 @@ function update_speed_n_u_p_evolution_neutral!(advect, fvec, moments, vz, z, r, end end # add in contributions from charge exchange and ionization collisions - if abs(collisions.charge_exchange) > 0.0 || abs(collisions.ionization) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 || abs(ionization) > 0.0 @loop_r_z_vzeta_vr ir iz ivzeta ivr begin @views @. advect[isn].speed[:,ivr,ivzeta,iz,ir] += - collisions.charge_exchange * + charge_exchange * (0.5*vz.grid/fvec.pz_neutral[iz,ir,isn] * (fvec.density[iz,ir,isn]*fvec.pz_neutral[iz,ir,isn] - fvec.density_neutral[iz,ir,isn]*fvec.ppar[iz,ir,isn] @@ -126,25 +128,28 @@ function update_speed_n_u_p_evolution_neutral!(advect, fvec, moments, vz, z, r, end end end - if neutral_source_settings.active - source_density_amplitude = moments.neutral.external_source_density_amplitude - source_momentum_amplitude = moments.neutral.external_source_momentum_amplitude - source_pressure_amplitude = moments.neutral.external_source_pressure_amplitude - density = fvec.density_neutral - uz = fvec.uz_neutral - pz = fvec.pz_neutral - vth = moments.neutral.vth - vz_grid = vz.grid - @loop_s_r_z is ir iz begin - term1 = source_density_amplitude[iz,ir] * uz[iz,ir,is]/(density[iz,ir,is]*vth[iz,ir,is]) - term2_over_vpa = - -0.5 * (source_pressure_amplitude[iz,ir] + - 2.0 * uz[iz,ir,is] * source_momentum_amplitude[iz,ir]) / - pz[iz,ir,is] + - 0.5 * source_density_amplitude[iz,ir] / density[iz,ir,is] - @loop_vzeta_vr_vz ivzeta ivr ivz begin - advect[is].speed[ivz,ivr,ivzeta,iz,ir] += term1 + - vz_grid[ivz] * term2_over_vpa + + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_density_amplitude = moments.neutral.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.neutral.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.neutral.external_source_pressure_amplitude[:, :, index] + density = fvec.density_neutral + uz = fvec.uz_neutral + pz = fvec.pz_neutral + vth = moments.neutral.vth + vz_grid = vz.grid + @loop_s_r_z is ir iz begin + term1 = source_density_amplitude[iz,ir] * uz[iz,ir,is]/(density[iz,ir,is]*vth[iz,ir,is]) + term2_over_vpa = + -0.5 * (source_pressure_amplitude[iz,ir] + + 2.0 * uz[iz,ir,is] * source_momentum_amplitude[iz,ir]) / + pz[iz,ir,is] + + 0.5 * source_density_amplitude[iz,ir] / density[iz,ir,is] + @loop_vzeta_vr_vz ivzeta ivr ivz begin + advect[is].speed[ivz,ivr,ivzeta,iz,ir] += term1 + + vz_grid[ivz] * term2_over_vpa + end end end end @@ -173,18 +178,19 @@ function update_speed_n_p_evolution_neutral!(advect, fields, fvec, moments, vz, vz.grid*moments.neutral.duz_dz[iz,ir,isn] end end - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + if abs(charge_exchange) > 0.0 # add in contributions from charge exchange and ionization collisions error("suspect the charge exchange and ionization contributions here may be " * "wrong because (upar[is]-upar[isp])^2 type terms were missed in the " * "energy equation when it was substituted in to derive them.") @loop_r_z_vzeta_vr ir iz ivzeta ivr begin - @views @. advect[is].speed[:,ivr,ivzeta,iz,ir] += collisions.charge_exchange * + @views @. advect[is].speed[:,ivr,ivzeta,iz,ir] += charge_exchange * 0.5*vz.grid*fvec.density_neutral[iz,ir,is] * (1.0-fvec.ppar[iz,ir,is]/fvec.pz_neutral[iz,ir,is]) end end end - if ion_source_settings.active + if any(x -> x.active, neutral_source_settings) error("External source not implemented for evolving n and ppar case") end end @@ -212,22 +218,25 @@ function update_speed_n_u_evolution_neutral!(advect, fvec, moments, vz, z, r, co # if neutrals present compute contribution to parallel acceleration due to charge exchange # and/or ionization collisions betweens ions and neutrals - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + if abs(charge_exchange) > 0.0 # include contribution to neutral acceleration due to collisional friction with ions @loop_r_z_vzeta_vr ir iz ivzeta ivr begin - @views @. advect[isn].speed[:,ivr,ivzeta,iz,ir] -= collisions.charge_exchange*fvec.density[iz,ir,isn]*(fvec.upar[iz,ir,isn]-fvec.uz_neutral[iz,ir,isn]) + @views @. advect[isn].speed[:,ivr,ivzeta,iz,ir] -= charge_exchange*fvec.density[iz,ir,isn]*(fvec.upar[iz,ir,isn]-fvec.uz_neutral[iz,ir,isn]) end end end - if neutral_source_settings.active - source_density_amplitude = moments.neutral.external_source_density_amplitude - density = fvec.density_neutral - uz = fvec.uz_neutral - vth = moments.neutral.vth - @loop_sn_r_z isn ir iz begin - term = source_density_amplitude[iz,ir] * uz[iz,ir,isn] / density[iz,ir,isn] - @loop_vzeta_vr_vz ivzeta ivr ivz begin - advect[isn].speed[ivz,ivr,ivzeta,iz,ir] += term + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_density_amplitude = moments.neutral.external_source_density_amplitude[:, :, index] + density = fvec.density_neutral + uz = fvec.uz_neutral + vth = moments.neutral.vth + @loop_sn_r_z isn ir iz begin + term = source_density_amplitude[iz,ir] * uz[iz,ir,isn] / density[iz,ir,isn] + @loop_vzeta_vr_vz ivzeta ivr ivz begin + advect[isn].speed[ivz,ivr,ivzeta,iz,ir] += term + end end end end diff --git a/moment_kinetics/src/nonlinear_solvers.jl b/moment_kinetics/src/nonlinear_solvers.jl index 365b91295..5726da782 100644 --- a/moment_kinetics/src/nonlinear_solvers.jl +++ b/moment_kinetics/src/nonlinear_solvers.jl @@ -74,7 +74,7 @@ layout of the variable to be solved (i.e. fastest-varying first). The nonlinear solver will be called inside a loop over `outer_coords`, so we might need for example a preconditioner object for each point in that outer loop. """ -function setup_nonlinear_solve(input_dict, coords, outer_coords=(); default_rtol=1.0e-5, +function setup_nonlinear_solve(active, input_dict, coords, outer_coords=(); default_rtol=1.0e-5, default_atol=1.0e-12, serial_solve=false, electron_ppar_pdf_solve=false, preconditioner_type=nothing) nl_solver_section = set_defaults_and_check_section!( @@ -88,6 +88,13 @@ function setup_nonlinear_solve(input_dict, coords, outer_coords=(); default_rtol linear_max_restarts=0, preconditioner_update_interval=300, ) + + if !active + # This solver will not be used. Return here, after reading the options, so that we + # can always check that input file sections are supposed to exist. + return nothing + end + nl_solver_input = Dict_to_NamedTuple(nl_solver_section) coord_sizes = Tuple(isa(c, coordinate) ? c.n : c for c ∈ coords) diff --git a/moment_kinetics/src/numerical_dissipation.jl b/moment_kinetics/src/numerical_dissipation.jl index f48a158c6..911375341 100644 --- a/moment_kinetics/src/numerical_dissipation.jl +++ b/moment_kinetics/src/numerical_dissipation.jl @@ -15,33 +15,9 @@ using ..looping using ..calculus: derivative!, second_derivative!, laplacian_derivative! using ..derivatives: derivative_r!, derivative_z!, second_derivative_r!, second_derivative_z! +using ..input_structs using ..type_definitions: mk_float - -############################################################# -########### Numerical Dissipation Parameter setup ########### -""" -Define the dissipation parameters for each species, which means -there need to be three sections in each input file that specify -the parameters required of each species, as follows: - -``` -[ion_numerical_dissipation] -vpa_dissipation_coefficient -... - -[electron_numerical_dissipation] -vpa_dissipation_coefficient -... - -[neutral_numerical_dissipation] -vz_dissipation_coefficient -... -``` - -There will still be the -1.0 default parameters. -""" - # define individual structs for each species with their particular parameters Base.@kwdef struct ion_num_diss_params vpa_boundary_buffer_damping_rate::mk_float = -1.0 @@ -51,7 +27,7 @@ Base.@kwdef struct ion_num_diss_params z_dissipation_coefficient::mk_float = -1.0 r_dissipation_coefficient::mk_float = -1.0 moment_dissipation_coefficient::mk_float = -1.0 - force_minimum_pdf_value::Union{Nothing,mk_float} = nothing + force_minimum_pdf_value::mk_float = -Inf end Base.@kwdef struct electron_num_diss_params @@ -62,7 +38,7 @@ Base.@kwdef struct electron_num_diss_params z_dissipation_coefficient::mk_float = -1.0 r_dissipation_coefficient::mk_float = -1.0 moment_dissipation_coefficient::mk_float = -1.0 - force_minimum_pdf_value::Union{Nothing,mk_float} = nothing + force_minimum_pdf_value::mk_float = -Inf end Base.@kwdef struct neutral_num_diss_params @@ -70,7 +46,7 @@ Base.@kwdef struct neutral_num_diss_params z_dissipation_coefficient::mk_float = -1.0 r_dissipation_coefficient::mk_float = -1.0 moment_dissipation_coefficient::mk_float = -1.0 - force_minimum_pdf_value::Union{Nothing,mk_float} = nothing + force_minimum_pdf_value::mk_float = -Inf end struct numerical_dissipation_parameters @@ -79,25 +55,39 @@ struct numerical_dissipation_parameters neutral::neutral_num_diss_params end -######### End Of Numerical Dissipation Parameter setup ######### -################################################################ - -function setup_numerical_dissipation(ion_input::Dict, electron_input::Dict, - neutral_input::Dict, is_1V) - if is_1V && "vpa_dissipation_coefficient" ∈ keys(ion_input) - # Set default for vz_dissipation_coefficient the same as - # ion_vpa_dissipation_coefficient for 1V case - neutral_input["vz_dissipation_coefficient"] = - get(neutral_input, "vz_dissipation_coefficient", - ion_input["vpa_dissipation_coefficient"]) - end +############################################################# +########### Numerical Dissipation Parameter setup ########### +""" +Define the dissipation parameters for each species, which means +there need to be three sections in each input file that specify +the parameters required of each species, as follows: + +``` +[ion_numerical_dissipation] +vpa_dissipation_coefficient +... - ion_input_dict = Dict(Symbol(k)=>v for (k,v) in ion_input) - ion_params = ion_num_diss_params(; ion_input_dict...) - electron_input_dict = Dict(Symbol(k)=>v for (k,v) in electron_input) - electron_params = electron_num_diss_params(; electron_input_dict...) - neutral_input_dict = Dict(Symbol(k)=>v for (k,v) in neutral_input) - neutral_params = neutral_num_diss_params(; neutral_input_dict...) +[electron_numerical_dissipation] +vpa_dissipation_coefficient +... + +[neutral_numerical_dissipation] +vz_dissipation_coefficient +... +``` + +There will still be the -1.0 default parameters. +""" +function setup_numerical_dissipation(input_dict) + ion_params = set_defaults_and_check_section!( + input_dict, ion_num_diss_params, "ion_numerical_dissipation" + ) + electron_params = set_defaults_and_check_section!( + input_dict, electron_num_diss_params, "electron_numerical_dissipation" + ) + neutral_params = set_defaults_and_check_section!( + input_dict, neutral_num_diss_params, "neutral_numerical_dissipation" + ) return numerical_dissipation_parameters(ion_params, electron_params, neutral_params) end @@ -574,7 +564,7 @@ force_minimum_pdf_value = 0.0 """ function force_minimum_pdf_value!(f, minval) - if minval === nothing + if minval == -Inf return nothing end diff --git a/moment_kinetics/src/parameter_scans.jl b/moment_kinetics/src/parameter_scans.jl index 4cd896e0e..fc7ebcf28 100644 --- a/moment_kinetics/src/parameter_scans.jl +++ b/moment_kinetics/src/parameter_scans.jl @@ -33,10 +33,10 @@ parameter scan. function get_scan_inputs(scan_inputs::AbstractDict) scan_inputs = OrderedDict{String,Any}(scan_inputs) - if "base_directory" ∉ keys(scan_inputs) + if "base_directory" ∉ keys(scan_inputs["output"]) # Set up base_directory so that the runs in the scan are created in subdirectories # under a directory for the whole scan. - scan_inputs["base_directory"] = joinpath("runs", scan_inputs["run_name"]) + scan_inputs["output"]["base_directory"] = joinpath("runs", scan_inputs["output"]["run_name"]) end combine_outer = pop!(scan_inputs, "combine_outer", String[]) @@ -64,7 +64,7 @@ function get_scan_inputs(scan_inputs::AbstractDict) result = Vector{OrderedDict}(undef, length_inner_product) for i ∈ 1:length_inner_product - run_name = scan_inputs["run_name"] + run_name = scan_inputs["output"]["run_name"] result[i] = OrderedDict{String,Any}() for (k,v) ∈ scan_inputs if v isa Vector @@ -76,7 +76,7 @@ function get_scan_inputs(scan_inputs::AbstractDict) result[i][k] = v end end - result[i]["run_name"] = run_name + result[i]["output"]["run_name"] = run_name end # Combine 'result' with 'combine_outer' fields @@ -104,7 +104,7 @@ function get_scan_inputs(scan_inputs::AbstractDict) new_dict[key] = vals[j] # Truncate `key` - seems that if file names are too long, HDF5 has a # buffer overflow - new_dict["run_name"] = new_dict["run_name"] * + new_dict["output"]["run_name"] = new_dict["output"]["run_name"] * "_$(key[1:min(3, length(key))])_$(vals[j])" new_scan_inputs[count] = new_dict end @@ -122,7 +122,7 @@ function get_scan_inputs(scan_inputs::AbstractDict) println("Running scan:") for x in result - println(x["run_name"]) + println(x["output"]["run_name"]) end return result @@ -178,12 +178,12 @@ function generate_scan_input_files(scan_input::AbstractDict, dirname::AbstractSt for input ∈ input_dicts # Write the file, but do not overwrite - filename = joinpath(dirname, input["run_name"] * ".toml") + filename = joinpath(dirname, input["output"]["run_name"] * ".toml") ispath(filename) && error("The file $filename already exists.") open(filename, "w") do io # The run name will be created from the name of the input file, so do not need # to save "run_name" in the file. - pop!(input, "run_name") + pop!(input["output"], "run_name") options_to_TOML(io, input) end end diff --git a/moment_kinetics/src/source_terms.jl b/moment_kinetics/src/source_terms.jl index 9850d6f23..b9678a815 100644 --- a/moment_kinetics/src/source_terms.jl +++ b/moment_kinetics/src/source_terms.jl @@ -27,7 +27,7 @@ function source_terms!(pdf_out, fvec_in, moments, vpa, z, r, dt, spectral, compo moments.ion.dvth_dz[:,:,is], moments.ion.dqpar_dz[:,:,is], moments, z, r, dt, spectral, ion_source_settings) if composition.n_neutral_species > 0 - if abs(collisions.charge_exchange) > 0.0 || abs(collisions.ionization) > 0.0 + if abs(collisions.reactions.charge_exchange_frequency) > 0.0 || abs(collisions.reactions.ionization_frequency) > 0.0 @views source_terms_evolve_ppar_collisions!( pdf_out[:,:,:,:,is], fvec_in.pdf[:,:,:,:,is], fvec_in.density[:,:,is], fvec_in.upar[:,:,is], @@ -64,12 +64,14 @@ function source_terms_evolve_density!(pdf_out, pdf_in, dens, upar, ddens_dz, dup end end - if ion_source_settings.active - source_density_amplitude = moments.ion.external_source_density_amplitude - @loop_r_z ir iz begin - term = dt * source_density_amplitude[iz,ir] / dens[iz,ir] - @loop_vperp_vpa ivperp ivpa begin - pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_density_amplitude = moments.ion.external_source_density_amplitude[:, :, index] + @loop_r_z ir iz begin + term = dt * source_density_amplitude[iz,ir] / dens[iz,ir] + @loop_vperp_vpa ivperp ivpa begin + pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + end end end end @@ -96,16 +98,18 @@ function source_terms_evolve_ppar_no_collisions!(pdf_out, pdf_in, dens, upar, pp end end - if ion_source_settings.active - source_density_amplitude = moments.ion.external_source_density_amplitude - source_momentum_amplitude = moments.ion.external_source_momentum_amplitude - source_pressure_amplitude = moments.ion.external_source_pressure_amplitude - @loop_r_z ir iz begin - term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - - (0.5 * source_pressure_amplitude[iz,ir] + - source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) - @loop_vperp_vpa ivperp ivpa begin - pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_density_amplitude = moments.ion.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.ion.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.ion.external_source_pressure_amplitude[:, :, index] + @loop_r_z ir iz begin + term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - + (0.5 * source_pressure_amplitude[iz,ir] + + source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) + @loop_vperp_vpa ivperp ivpa begin + pdf_out[ivpa,ivperp,iz,ir] -= term * pdf_in[ivpa,ivperp,iz,ir] + end end end end @@ -120,14 +124,16 @@ kinetic equation arising due to the re-normalization of the pdf as g = f * vth / function source_terms_evolve_ppar_collisions!(pdf_out, pdf_in, dens, upar, ppar, dens_neutral, upar_neutral, ppar_neutral, composition, collisions, dt, z, r) + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency @loop_r_z_vperp_vpa ir iz ivperp ivpa begin @views pdf_out[ivpa,ivperp,iz,ir] -= 0.5*dt*pdf_in[ivpa,ivperp,iz,ir] * - (collisions.charge_exchange + (charge_exchange * (dens_neutral[iz,ir]*ppar[iz,ir] - dens[iz,ir]*ppar_neutral[iz,ir] - dens[iz,ir]*dens_neutral[iz,ir] * (upar[iz,ir] - upar_neutral[iz,ir])^2) / ppar[iz,ir] - + collisions.ionization + + ionization * (3.0*dens_neutral[iz,ir] - dens[iz,ir]*(ppar_neutral[iz,ir] + dens_neutral[iz,ir]*(upar[iz,ir] - upar_neutral[iz,ir])^2) @@ -155,7 +161,7 @@ function source_terms_neutral!(pdf_out, fvec_in, moments, vpa, z, r, dt, spectra moments.neutral.qz[:,:,isn], moments.neutral.ddens_dz[:,:,isn], moments.neutral.dvth_dz[:,:,isn], moments.neutral.dqz_dz[:,:,isn], moments, z, r, dt, spectral, neutral_source_settings) - if abs(collisions.charge_exchange) > 0.0 || abs(collisions.ionization) > 0.0 + if abs(collisions.reactions.charge_exchange_frequency) > 0.0 || abs(collisions.reactions.ionization_frequency) > 0.0 @views source_terms_evolve_ppar_collisions_neutral!( pdf_out[:,:,:,:,:,isn], fvec_in.pdf_neutral[:,:,:,:,:,isn], fvec_in.density_neutral[:,:,isn], fvec_in.uz_neutral[:,:,isn], @@ -192,12 +198,14 @@ function source_terms_evolve_density_neutral!(pdf_out, pdf_in, dens, upar, ddens end end - if neutral_source_settings.active - source_density_amplitude = moments.neutral.external_source_density_amplitude - @loop_r_z ir iz begin - term = dt * source_density_amplitude[iz,ir] / dens[iz,ir] - @loop_vzeta_vr_vz ivzeta ivr ivz begin - pdf_out[ivz,ivr,ivzeta,iz,ir] -= term * pdf_in[ivz,ivr,ivzeta,iz,ir] + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_density_amplitude = moments.neutral.external_source_density_amplitude[:, :, index] + @loop_r_z ir iz begin + term = dt * source_density_amplitude[iz,ir] / dens[iz,ir] + @loop_vzeta_vr_vz ivzeta ivr ivz begin + pdf_out[ivz,ivr,ivzeta,iz,ir] -= term * pdf_in[ivz,ivr,ivzeta,iz,ir] + end end end end @@ -223,20 +231,22 @@ function source_terms_evolve_ppar_no_collisions_neutral!(pdf_out, pdf_in, dens, end end - if neutral_source_settings.active - source_density_amplitude = moments.neutral.external_source_density_amplitude - source_momentum_amplitude = moments.neutral.external_source_momentum_amplitude - source_pressure_amplitude = moments.neutral.external_source_pressure_amplitude - @loop_r_z ir iz begin - term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - - (0.5 * source_pressure_amplitude[iz,ir] + - source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) - @loop_vzeta_vr_vz ivzeta ivr ivz begin - pdf_out[ivz,ivr,ivzeta,iz,ir] -= term * pdf_in[ivz,ivr,ivzeta,iz,ir] + for index ∈ eachindex(neutral_source_settings) + if neutral_source_settings[index].active + @views source_density_amplitude = moments.neutral.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.neutral.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.neutral.external_source_pressure_amplitude[:, :, index] + @loop_r_z ir iz begin + term = dt * (1.5 * source_density_amplitude[iz,ir] / dens[iz,ir] - + (0.5 * source_pressure_amplitude[iz,ir] + + source_momentum_amplitude[iz,ir]) / ppar[iz,ir]) + @loop_vzeta_vr_vz ivzeta ivr ivz begin + pdf_out[ivz,ivr,ivzeta,iz,ir] -= term * pdf_in[ivz,ivr,ivzeta,iz,ir] + end end end end - + return nothing end @@ -247,13 +257,15 @@ kinetic equation arising due to the re-normalization of the pdf as g = f * vth / function source_terms_evolve_ppar_collisions_neutral!(pdf_out, pdf_in, dens, upar, ppar, dens_ion, upar_ion, ppar_ion, composition, collisions, dt, z, r) + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency @loop_r_z_vzeta_vr_vz ir iz ivzeta ivr ivz begin @views pdf_out[ivz,ivr,ivzeta,iz,ir] -= 0.5*dt*pdf_in[ivz,ivr,ivzeta,iz,ir] * - (collisions.charge_exchange + (charge_exchange * (dens_ion[iz,ir]*ppar[iz,ir] - dens[iz,ir]*ppar_ion[iz,ir] - dens[iz,ir]*dens_ion[iz,ir] * (upar[iz,ir] - upar_ion[iz,ir])^2)/ppar[iz,ir] - - 2.0*collisions.ionization*dens_ion[iz,ir]) + - 2.0*ionization*dens_ion[iz,ir]) end return nothing end diff --git a/moment_kinetics/src/species_input.jl b/moment_kinetics/src/species_input.jl index 35d8755e0..59d7043fe 100644 --- a/moment_kinetics/src/species_input.jl +++ b/moment_kinetics/src/species_input.jl @@ -67,61 +67,22 @@ function get_species_input(toml_input) # initial temperature initial_temperature = 1.0) - z_IC_section = set_defaults_and_check_section!(toml_input, "z_IC_ion_species_$is", - # [ion_z_IC_species_1], [ion_z_IC_species_2], etc - initialization_option = "gaussian", - width = 0.125, - wavenumber = 1, - density_amplitude = 0.001, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2) - z_IC_input = Dict(Symbol(k)=>v for (k,v) in z_IC_section) - z_IC = spatial_initial_condition_input(; z_IC_input...) + z_IC = set_defaults_and_check_section!(toml_input, + spatial_initial_condition_input, + "z_IC_ion_species_$is") - r_IC_section = set_defaults_and_check_section!(toml_input, "r_IC_ion_species_$is", - # [ion_r_IC_species_1], [ion_r_IC_species_2], etc - initialization_option = "gaussian", - width = 0.125, - wavenumber = 1, - density_amplitude = 0.001, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2) - r_IC_input= Dict(Symbol(k)=>v for (k,v) in r_IC_section) - r_IC = spatial_initial_condition_input(; r_IC_input...) + r_IC = set_defaults_and_check_section!(toml_input, + spatial_initial_condition_input, + "r_IC_ion_species_$is") - vpa_IC_section = set_defaults_and_check_section!(toml_input, "vpa_IC_ion_species_$is", - # [ion_vpa_IC_species_1], [ion_vpa_IC_species_2], etc - initialization_option = "gaussian", - width = 1.0, - wavenumber = 1, - density_amplitude = 1.0, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2, - # need to read resolutions before setting defaults here - v0 = 1.0, - vth0 = 1.0, - vpa0 = 1.0, - vperp0 = 1.0) - vpa_IC_input= Dict(Symbol(k)=>v for (k,v) in vpa_IC_section) - vpa_IC = velocity_initial_condition_input(; vpa_IC_input...) + vpa_IC = set_defaults_and_check_section!(toml_input, + velocity_initial_condition_input, + "vpa_IC_ion_species_$is") - IC_input = Dict("z_IC" => z_IC, "r_IC" => r_IC, "vpa_IC" => vpa_IC) - type_input = Dict("type" => "ion") - spec_section = merge(spec_section, IC_input, type_input) spec_input = Dict(Symbol(k)=>v for (k,v) in spec_section) - ion_spec_params_list[is] = ion_species_parameters(; spec_input...) + ion_spec_params_list[is] = ion_species_parameters(; type="ion", z_IC=z_IC, + r_IC=r_IC, vpa_IC=vpa_IC, + spec_input...) end for isn in 1:nspec_neutral spec_section = set_defaults_and_check_section!(toml_input, "neutral_species_$isn", @@ -133,68 +94,29 @@ function get_species_input(toml_input) # initial temperature initial_temperature = 1.0) - z_IC_section = set_defaults_and_check_section!(toml_input, "z_IC_neutral_species_$isn", - # [neutral_z_IC_species_1], [neutral_z_IC_species_2], etc - initialization_option = "gaussian", - width = 0.125, - wavenumber = 1, - density_amplitude = 0.001, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2) - z_IC_input = Dict(Symbol(k)=>v for (k,v) in z_IC_section) - z_IC = spatial_initial_condition_input(; z_IC_input...) + z_IC = set_defaults_and_check_section!(toml_input, + spatial_initial_condition_input, + "z_IC_neutral_species_$isn") - r_IC_section = set_defaults_and_check_section!(toml_input, "r_IC_neutral_species_$isn", - # [neutral_r_IC_species_1], [neutral_r_IC_species_2], etc - initialization_option = "gaussian", - width = 0.125, - wavenumber = 1, - density_amplitude = 0.001, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2) - r_IC_input= Dict(Symbol(k)=>v for (k,v) in r_IC_section) - r_IC = spatial_initial_condition_input(; r_IC_input...) + r_IC = set_defaults_and_check_section!(toml_input, + spatial_initial_condition_input, + "r_IC_neutral_species_$isn") - vpa_IC_section = set_defaults_and_check_section!(toml_input, "vz_IC_neutral_species_$isn", - # [neutral_vpa_IC_species_1], [neutral_vpa_IC_species_2], etc - initialization_option = "gaussian", - width = 1.0, - wavenumber = 1, - density_amplitude = 1.0, - density_phase = 0.0, - upar_amplitude = 0.0, - upar_phase = 0.0, - temperature_amplitude = 0.0, - temperature_phase = 0.0, - monomial_degree = 2, - # need to read resolutions before setting defaults here - v0 = 1.0, - vth0 = 1.0, - vpa0 = 1.0, - vperp0 = 1.0) - vpa_IC_input= Dict(Symbol(k)=>v for (k,v) in vpa_IC_section) - vpa_IC = velocity_initial_condition_input(; vpa_IC_input...) + vz_IC = set_defaults_and_check_section!(toml_input, + velocity_initial_condition_input, + "vz_IC_neutral_species_$isn") - IC_input = Dict("z_IC" => z_IC, "r_IC" => r_IC, "vpa_IC" => vpa_IC) - type_input = Dict("type" => "neutral") - spec_section = merge(spec_section, IC_input, type_input) spec_input = Dict(Symbol(k)=>v for (k,v) in spec_section) - neutral_spec_params_list[isn] = neutral_species_parameters(; spec_input...) + neutral_spec_params_list[isn] = neutral_species_parameters(; type="neutral", + z_IC=z_IC, r_IC=r_IC, + vz_IC=vz_IC, + spec_input...) end - # construct composition dict - species_dict = Dict("n_species" => nspec_tot, "ion" => ion_spec_params_list, "neutral" => neutral_spec_params_list) - composition_section = merge(composition_section,species_dict) - input = Dict(Symbol(k)=>v for (k,v) in composition_section) # construct composition struct - composition = species_composition(; input...) + composition_input = Dict(Symbol(k)=>v for (k,v) in composition_section) + composition = species_composition(; n_species=nspec_tot, ion=ion_spec_params_list, + neutral=neutral_spec_params_list, + composition_input...) ## checks and errors if !(0.0 <= composition.recycling_fraction <= 1.0) diff --git a/moment_kinetics/src/time_advance.jl b/moment_kinetics/src/time_advance.jl index a244b293a..634699653 100644 --- a/moment_kinetics/src/time_advance.jl +++ b/moment_kinetics/src/time_advance.jl @@ -325,7 +325,7 @@ function setup_time_info(t_input, n_variables, code_time, dt_reload, # Makes no sense to use write_error_diagnostics because non-adaptive schemes have # no error estimate - input_dict["write_error_diagnostics"] = false + input_dict["timestepping"]["write_error_diagnostics"] = false end if adaptive && t_input["write_error_diagnostics"] && !t_input["write_after_fixed_step_count"] @@ -655,52 +655,34 @@ function setup_time_advance!(pdf, fields, vz, vr, vzeta, vpa, vperp, z, r, gyrop # Set up parameters for Jacobian-free Newton-Krylov solver used for implicit part of # timesteps. - if t_params.implicit_braginskii_conduction - # Should really have options to set solver tolerance, etc. - electron_conduction_nl_solve_parameters = setup_nonlinear_solve(input_dict, (z=z,); - default_rtol=t_params.rtol / 10.0, - default_atol=t_params.atol / 10.0) - else - electron_conduction_nl_solve_parameters = nothing - end - if t_params.implicit_electron_advance - nl_solver_electron_advance_params = - setup_nonlinear_solve(input_dict, - (r=r, z=z, vperp=vperp, vpa=vpa), - (); - default_rtol=t_params.rtol / 10.0, - default_atol=t_params.atol / 10.0, - electron_ppar_pdf_solve=true, - preconditioner_type="lu") - else - nl_solver_electron_advance_params = nothing - end - if t_params.implicit_ion_advance - # Implicit solve for vpa_advection term should be done in serial, as it will be - # called within a parallelised s_r_z_vperp loop. - nl_solver_ion_advance_params = - setup_nonlinear_solve(input_dict, - (s=composition.n_ion_species, r=r, z=z, vperp=vperp, - vpa=vpa), - (); - default_rtol=t_params.rtol / 10.0, - default_atol=t_params.atol / 10.0, - preconditioner_type="lu") - else - nl_solver_ion_advance_params = nothing - end - if t_params.implicit_vpa_advection - # Implicit solve for vpa_advection term should be done in serial, as it will be - # called within a parallelised s_r_z_vperp loop. - nl_solver_vpa_advection_params = - setup_nonlinear_solve(input_dict, (vpa=vpa,), - (composition.n_ion_species, r, z, vperp); - default_rtol=t_params.rtol / 10.0, - default_atol=t_params.atol / 10.0, - serial_solve=true, preconditioner_type="lu") - else - nl_solver_vpa_advection_params = nothing - end + electron_conduction_nl_solve_parameters = setup_nonlinear_solve(t_params.implicit_braginskii_conduction, + input_dict, (z=z,); + default_rtol=t_params.rtol / 10.0, + default_atol=t_params.atol / 10.0) + nl_solver_electron_advance_params = + setup_nonlinear_solve(t_params.implicit_electron_advance, input_dict, + (r=r, z=z, vperp=vperp, vpa=vpa), + (); + default_rtol=t_params.rtol / 10.0, + default_atol=t_params.atol / 10.0, + electron_ppar_pdf_solve=true, + preconditioner_type="lu") + nl_solver_ion_advance_params = + setup_nonlinear_solve(t_params.implicit_ion_advance, input_dict, + (s=composition.n_ion_species, r=r, z=z, vperp=vperp, + vpa=vpa), + (); + default_rtol=t_params.rtol / 10.0, + default_atol=t_params.atol / 10.0, + preconditioner_type="lu") + # Implicit solve for vpa_advection term should be done in serial, as it will be called + # within a parallelised s_r_z_vperp loop. + nl_solver_vpa_advection_params = + setup_nonlinear_solve(t_params.implicit_vpa_advection, input_dict, (vpa=vpa,), + (composition.n_ion_species, r, z, vperp); + default_rtol=t_params.rtol / 10.0, + default_atol=t_params.atol / 10.0, + serial_solve=true, preconditioner_type="lu") if nl_solver_ion_advance_params !== nothing && nl_solver_vpa_advection_params !== nothing error("Cannot use implicit_ion_advance and implicit_vpa_advection at the same " @@ -715,6 +697,14 @@ function setup_time_advance!(pdf, fields, vz, vr, vzeta, vpa, vperp, z, r, gyrop ion_advance=nl_solver_ion_advance_params, vpa_advection=nl_solver_vpa_advection_params,) + # Check that no unexpected sections or top-level options were passed (helps to catch + # typos in input files). Needs to be called after calls to `setup_nonlinear_solve()` + # because the inputs for nonlinear solvers are only read there, but before electron + # setup, because `input_dict` needs to be written to the output files, and it cannot + # be with the `_section_check_store` variable still contained in it (which is used and + # removed by `check_sections!()`). + check_sections!(input_dict) + begin_serial_region() # create an array of structs containing scratch arrays for the pdf and low-order moments @@ -795,7 +785,8 @@ function setup_time_advance!(pdf, fields, vz, vr, vzeta, vpa, vperp, z, r, gyrop # calculate the electron-ion parallel friction force calculate_electron_parallel_friction_force!(moments.electron.parallel_friction, moments.electron.dens, moments.electron.upar, moments.ion.upar, moments.electron.dT_dz, - composition.me_over_mi, collisions.nu_ei, composition.electron_physics) + composition.me_over_mi, collisions.electron_fluid.nu_ei, + composition.electron_physics) # initialize the electrostatic potential begin_serial_region() update_phi!(fields, scratch[1], vperp, z, r, composition, collisions, moments, @@ -1025,7 +1016,7 @@ function setup_time_advance!(pdf, fields, vz, vr, vzeta, vpa, vperp, z, r, gyrop scratch_dummy.buffer_rs_4[:,1], z_spectral, z) # calculate the electron parallel heat flux calculate_electron_qpar!(moments.electron, pdf.electron, moments.electron.ppar, - moments.electron.upar, moments.ion.upar, collisions.nu_ei, + moments.electron.upar, moments.ion.upar, collisions.electron_fluid.nu_ei, composition.me_over_mi, composition.electron_physics, vpa) if composition.electron_physics == braginskii_fluid electron_fluid_qpar_boundary_condition!( @@ -1062,7 +1053,8 @@ function setup_time_advance!(pdf, fields, vz, vr, vzeta, vpa, vperp, z, r, gyrop # calculate the electron-ion parallel friction force calculate_electron_parallel_friction_force!(moments.electron.parallel_friction, moments.electron.dens, moments.electron.upar, moments.ion.upar, moments.electron.dT_dz, - composition.me_over_mi, collisions.nu_ei, composition.electron_physics) + composition.me_over_mi, collisions.electron_fluid.nu_ei, + composition.electron_physics) calculate_ion_moment_derivatives!(moments, scratch[1], scratch_dummy, z, z_spectral, ion_mom_diss_coeff) @@ -1157,7 +1149,7 @@ function setup_advance_flags(moments, composition, t_params, collisions, end # if charge exchange collision frequency non-zero, # account for charge exchange collisions - if abs(collisions.charge_exchange) > 0.0 + if abs(collisions.reactions.charge_exchange_frequency) > 0.0 if vperp.n == 1 && vr.n == 1 && vzeta.n == 1 advance_ion_cx_1V = !t_params.implicit_ion_advance advance_neutral_cx_1V = true @@ -1172,7 +1164,7 @@ function setup_advance_flags(moments, composition, t_params, collisions, end # if ionization collision frequency non-zero, # account for ionization collisions - if abs(collisions.ionization) > 0.0 + if abs(collisions.reactions.ionization_frequency) > 0.0 if vperp.n == 1 && vr.n == 1 && vzeta.n == 1 advance_ion_ionization_1V = !t_params.implicit_ion_advance advance_neutral_ionization_1V = true @@ -1197,8 +1189,8 @@ function setup_advance_flags(moments, composition, t_params, collisions, if collisions.mxwl_diff.D_nn > 0.0 advance_maxwell_diffusion_nn = true end - advance_external_source = external_source_settings.ion.active && !t_params.implicit_ion_advance - advance_neutral_external_source = external_source_settings.neutral.active + advance_external_source = any(x -> x.active, external_source_settings.ion) && !t_params.implicit_ion_advance + advance_neutral_external_source = any(x -> x.active, external_source_settings.neutral) advance_ion_numerical_dissipation = !(t_params.implicit_ion_advance || t_params.implicit_vpa_advection) advance_neutral_numerical_dissipation = true # if evolving the density, must advance the continuity equation, @@ -1346,7 +1338,7 @@ function setup_implicit_advance_flags(moments, composition, t_params, collisions advance_vperp_advection = vperp.n > 1 && z.n > 1 advance_z_advection = z.n > 1 advance_r_advection = r.n > 1 - if abs(collisions.charge_exchange) > 0.0 + if abs(collisions.reactions.charge_exchange_frequency) > 0.0 if vperp.n == 1 && vr.n == 1 && vzeta.n == 1 advance_ion_cx_1V = true elseif vperp.n > 1 && vr.n > 1 && vzeta.n > 1 @@ -1357,7 +1349,7 @@ function setup_implicit_advance_flags(moments, composition, t_params, collisions * "vpa.n=$(vpa.n), vz.n=$(vz.n)") end end - if abs(collisions.ionization) > 0.0 + if abs(collisions.reactions.ionization_frequency) > 0.0 if vperp.n == 1 && vr.n == 1 && vzeta.n == 1 advance_ion_ionization_1V = true elseif vperp.n > 1 && vr.n > 1 && vzeta.n > 1 @@ -1369,7 +1361,7 @@ function setup_implicit_advance_flags(moments, composition, t_params, collisions end end advance_krook_collisions_ii = collisions.krook.nuii0 > 0.0 - advance_external_source = external_source_settings.ion.active + advance_external_source = any(x -> x.active, external_source_settings.ion) advance_ion_numerical_dissipation = true advance_sources = moments.evolve_density || moments.evolve_upar || moments.evolve_ppar explicit_weakform_fp_collisions = collisions.fkpl.nuii > 0.0 && vperp.n > 1 @@ -1904,9 +1896,9 @@ function time_advance!(pdf, scratch, scratch_implicit, scratch_electron, t_param print(Dates.format(now(), dateformat"H:MM:SS")) end end - write_data_to_ascii(pdf, moments, fields, vpa, vperp, z, r, t_params.t[], - composition.n_ion_species, composition.n_neutral_species, - ascii_io) + write_data_to_ascii(pdf, moments, fields, vz, vr, vzeta, vpa, vperp, z, r, + t_params.t[], composition.n_ion_species, + composition.n_neutral_species, ascii_io) write_all_moments_data_to_binary(scratch, moments, fields, composition.n_ion_species, composition.n_neutral_species, io_moments, @@ -2074,7 +2066,7 @@ function time_advance_split_operators!(pdf, scratch, scratch_implicit, scratch_e advance.z_advection = false # account for charge exchange collisions between ions and neutrals if composition.n_neutral_species > 0 - if collisions.charge_exchange > 0.0 + if collisions.reactions.charge_exchange_frequency > 0.0 advance.ion_cx_collisions = true time_advance_no_splitting!(pdf, scratch, scratch_implicit, scratch_electron, t_params, vpa, z, vpa_spectral, z_spectral, @@ -2090,7 +2082,7 @@ function time_advance_split_operators!(pdf, scratch, scratch_implicit, scratch_e advance_implicit, istep) advance.neutral_cx_collisions = false end - if collisions.ionization > 0.0 + if collisions.reactions.ionization_frequency > 0.0 advance.ion_ionization_collisions = true time_advance_no_splitting!(pdf, scratch, scratch_implicit, scratch_electron, t_params, z, vpa, z_spectral, vpa_spectral, @@ -2192,7 +2184,7 @@ function time_advance_split_operators!(pdf, scratch, scratch_implicit, scratch_e end # account for charge exchange collisions between ions and neutrals if composition.n_neutral_species > 0 - if collisions.ionization > 0.0 + if collisions.reactions.ionization_frequency > 0.0 advance.neutral_ionization = true time_advance_no_splitting!(pdf, scratch, scratch_implicit, scratch_electron, t_params, z, vpa, z_spectral, vpa_spectral, @@ -2208,7 +2200,7 @@ function time_advance_split_operators!(pdf, scratch, scratch_implicit, scratch_e advance_implicit, istep) advance.ion_ionization = false end - if collisions.charge_exchange > 0.0 + if collisions.reactions.charge_exchange_frequency > 0.0 advance.neutral_cx_collisions = true time_advance_no_splitting!(pdf, scratch, scratch_implicit, scratch_electron, t_params, vpa, z, vpa_spectral, z_spectral, @@ -2420,7 +2412,8 @@ function apply_all_bcs_constraints_update_moments!( calculate_electron_parallel_friction_force!( moments.electron.parallel_friction, this_scratch.electron_density, this_scratch.electron_upar, this_scratch.upar, moments.electron.dT_dz, - composition.me_over_mi, collisions.nu_ei, composition.electron_physics) + composition.me_over_mi, collisions.electron_fluid.nu_ei, + composition.electron_physics) # update the electrostatic potential phi update_phi!(fields, this_scratch, vperp, z, r, composition, collisions, moments, @@ -3223,11 +3216,11 @@ function euler_time_advance!(fvec_out, fvec_in, pdf, fields, moments, neutral_z_advect, neutral_r_advect, neutral_vz_advect = advect_objects.neutral_z_advect, advect_objects.neutral_r_advect, advect_objects.neutral_vz_advect if advance.external_source - external_ion_source_controller!(fvec_in, moments, external_source_settings.ion, + total_external_ion_source_controllers!(fvec_in, moments, external_source_settings.ion, dt) end if advance.neutral_external_source - external_neutral_source_controller!(fvec_in, moments, + total_external_neutral_source_controllers!(fvec_in, moments, external_source_settings.neutral, r, z, dt) end @@ -3299,22 +3292,22 @@ function euler_time_advance!(fvec_out, fvec_in, pdf, fields, moments, # account for charge exchange collisions between ions and neutrals if advance.ion_cx_collisions_1V ion_charge_exchange_collisions_1V!(fvec_out.pdf, fvec_in, moments, composition, - vpa, vz, collisions.charge_exchange, + vpa, vz, collisions.reactions.charge_exchange_frequency, vpa_spectral, vz_spectral, dt) elseif advance.ion_cx_collisions ion_charge_exchange_collisions_3V!(fvec_out.pdf, pdf.ion.buffer, fvec_in, composition, vz, vr, vzeta, vpa, vperp, z, r, - collisions.charge_exchange, dt) + collisions.reactions.charge_exchange_frequency, dt) end if advance.neutral_cx_collisions_1V neutral_charge_exchange_collisions_1V!(fvec_out.pdf_neutral, fvec_in, moments, composition, vpa, vz, - collisions.charge_exchange, vpa_spectral, + collisions.reactions.charge_exchange_frequency, vpa_spectral, vz_spectral, dt) elseif advance.neutral_cx_collisions neutral_charge_exchange_collisions_3V!(fvec_out.pdf_neutral, pdf.neutral.buffer, fvec_in, composition, vz, vr, vzeta, vpa, - vperp, z, r, collisions.charge_exchange, + vperp, z, r, collisions.reactions.charge_exchange_frequency, dt) end # account for ionization collisions between ions and neutrals @@ -3351,11 +3344,11 @@ function euler_time_advance!(fvec_out, fvec_in, pdf, fields, moments, end if advance.external_source - external_ion_source!(fvec_out.pdf, fvec_in, moments, external_source_settings.ion, + total_external_ion_sources!(fvec_out.pdf, fvec_in, moments, external_source_settings.ion, vperp, vpa, dt, scratch_dummy) end if advance.neutral_external_source - external_neutral_source!(fvec_out.pdf_neutral, fvec_in, moments, + total_external_neutral_sources!(fvec_out.pdf_neutral, fvec_in, moments, external_source_settings.neutral, vzeta, vr, vz, dt) end @@ -3407,7 +3400,7 @@ function euler_time_advance!(fvec_out, fvec_in, pdf, fields, moments, end if advance.continuity continuity_equation!(fvec_out.density, fvec_in, moments, composition, dt, - z_spectral, collisions.ionization, + z_spectral, collisions.reactions.ionization_frequency, external_source_settings.ion, num_diss_params) end if advance.force_balance @@ -3429,7 +3422,8 @@ function euler_time_advance!(fvec_out, fvec_in, pdf, fields, moments, end if advance.neutral_continuity neutral_continuity_equation!(fvec_out.density_neutral, fvec_in, moments, - composition, dt, z_spectral, collisions.ionization, + composition, dt, z_spectral, + collisions.reactions.ionization_frequency, external_source_settings.neutral, num_diss_params) end if advance.neutral_force_balance diff --git a/moment_kinetics/src/utils.jl b/moment_kinetics/src/utils.jl index 2118c0407..b5b0863bb 100644 --- a/moment_kinetics/src/utils.jl +++ b/moment_kinetics/src/utils.jl @@ -4,7 +4,7 @@ Utility functions module utils export get_unnormalized_parameters, print_unnormalized_parameters, to_seconds, to_minutes, - to_hours + to_hours, recursive_merge, merge_dict_with_kwargs! using ..communication using ..constants @@ -54,7 +54,7 @@ function get_unnormalized_parameters(input::Dict) mi = reference_params.mref * Unitful.kg parameters = OrderedDict{String,Any}() - parameters["run_name"] = run_name + parameters["run_name"] = io_input.run_name parameters["Nnorm"] = Nnorm parameters["Tnorm"] = Tnorm @@ -72,10 +72,10 @@ function get_unnormalized_parameters(input::Dict) parameters["T_e"] = Tnorm * composition.T_e parameters["T_wall"] = Tnorm * composition.T_wall - parameters["CX_rate_coefficient"] = collisions.charge_exchange / Nnorm / timenorm - parameters["ionization_rate_coefficient"] = collisions.ionization / Nnorm / timenorm + parameters["CX_rate_coefficient"] = collisions.reactions.charge_exchange_frequency / Nnorm / timenorm + parameters["ionization_rate_coefficient"] = collisions.reactions.ionization_frequency / Nnorm / timenorm parameters["coulomb_collision_frequency0"] = - collisions.coulomb_collision_frequency_prefactor / timenorm + collisions.krook.nu_ii0 / timenorm return parameters end @@ -294,6 +294,43 @@ function enum_from_string(enum_type, name) return nothing end +""" + recursive_merge(a, b) + +Merge two AbstractDicts `a` and `b`. Any elements that are AbstractDicts are also merged +(rather than just replacing with the entry in `b`). +""" +function recursive_merge end +function recursive_merge(a::AbstractDict, b::AbstractDict) + return mergewith(recursive_merge, a, b) +end +function recursive_merge(a::AbstractDict, b) + error("Cannot merge a Dict with a non-Dict, got $a and $b") +end +function recursive_merge(a, b::AbstractDict) + error("Cannot merge a Dict with a non-Dict, got $a and $b") +end +function recursive_merge(a, b) + return b +end + +""" +Dict merge function for named keyword arguments +for case when input Dict is a mixed Dict of Dicts +and non-Dict float/int/string entries, and the +keyword arguments are also a mix of Dicts and non-Dicts +""" +function merge_dict_with_kwargs!(dict_base; args...) + for (k,v) in args + k = String(k) + if k in keys(dict_base) && isa(v, AbstractDict) + v = recursive_merge(dict_base[k], v) + end + dict_base[k] = v + end + return nothing +end + # Utility functions for timestepping """ diff --git a/moment_kinetics/src/velocity_moments.jl b/moment_kinetics/src/velocity_moments.jl index 29684c26a..096dae7b2 100644 --- a/moment_kinetics/src/velocity_moments.jl +++ b/moment_kinetics/src/velocity_moments.jl @@ -138,39 +138,40 @@ function create_moments_ion(nz, nr, n_species, evolve_density, evolve_upar, entropy_production = allocate_shared_float(nz, nr, n_species) - if ion_source_settings.active - external_source_amplitude = allocate_shared_float(nz, nr) + n_sources = length(ion_source_settings) + if any(x -> x.active, ion_source_settings) + external_source_amplitude = allocate_shared_float(nz, nr, n_sources) if evolve_density - external_source_density_amplitude = allocate_shared_float(nz, nr) + external_source_density_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_density_amplitude = allocate_shared_float(1, 1) + external_source_density_amplitude = allocate_shared_float(1, 1, n_sources) end if evolve_upar - external_source_momentum_amplitude = allocate_shared_float(nz, nr) + external_source_momentum_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_momentum_amplitude = allocate_shared_float(1, 1) + external_source_momentum_amplitude = allocate_shared_float(1, 1, n_sources) end if evolve_ppar - external_source_pressure_amplitude = allocate_shared_float(nz, nr) + external_source_pressure_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_pressure_amplitude = allocate_shared_float(1, 1) + external_source_pressure_amplitude = allocate_shared_float(1, 1, n_sources) end - if ion_source_settings.PI_density_controller_I != 0.0 && - ion_source_settings.source_type ∈ ("density_profile_control", "density_midpoint_control") - if ion_source_settings.source_type == "density_profile_control" - external_source_controller_integral = allocate_shared_float(nz, nr) + if any(x -> x.PI_density_controller_I != 0.0 && x.source_type ∈ + ("density_profile_control", "density_midpoint_control"), ion_source_settings) + if any(x -> x.source_type == "density_profile_control", ion_source_settings) + external_source_controller_integral = allocate_shared_float(nz, nr, n_sources) else - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end else - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end else - external_source_amplitude = allocate_shared_float(1, 1) - external_source_density_amplitude = allocate_shared_float(1, 1) - external_source_momentum_amplitude = allocate_shared_float(1, 1) - external_source_pressure_amplitude = allocate_shared_float(1, 1) - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_density_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_momentum_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_pressure_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end if evolve_density || evolve_upar || evolve_ppar @@ -199,7 +200,7 @@ end """ create a moment struct containing information about the electron moments """ -function create_moments_electron(nz, nr, electron_model, num_diss_params) +function create_moments_electron(nz, nr, electron_model, num_diss_params, n_sources) # allocate array used for the particle density density = allocate_shared_float(nz, nr) # initialise Bool variable that indicates if the density is updated for each species @@ -222,11 +223,11 @@ function create_moments_electron(nz, nr, electron_model, num_diss_params) parallel_heat_flux_updated = Ref(false) # allocate array used for the election-ion parallel friction force parallel_friction_force = allocate_shared_float(nz, nr) - # allocate arrays used for external sources - external_source_amplitude = allocate_shared_float(nz, nr) - external_source_density_amplitude = allocate_shared_float(nz, nr) - external_source_momentum_amplitude = allocate_shared_float(nz, nr) - external_source_pressure_amplitude = allocate_shared_float(nz, nr) + # allocate arrays used for external sources (third index is for the different sources) + external_source_amplitude = allocate_shared_float(nz, nr, n_sources) + external_source_density_amplitude = allocate_shared_float(nz, nr, n_sources) + external_source_momentum_amplitude = allocate_shared_float(nz, nr, n_sources) + external_source_pressure_amplitude = allocate_shared_float(nz, nr, n_sources) # allocate array used for the thermal speed thermal_speed = allocate_shared_float(nz, nr) # if evolving the electron pdf, it will be a function of the vth-normalised peculiar velocity @@ -363,39 +364,40 @@ function create_moments_neutral(nz, nr, n_species, evolve_density, evolve_upar, dvth_dz = nothing end - if neutral_source_settings.active - external_source_amplitude = allocate_shared_float(nz, nr) + n_sources = length(neutral_source_settings) + if any(x -> x.active, neutral_source_settings) + external_source_amplitude = allocate_shared_float(nz, nr, n_sources) if evolve_density - external_source_density_amplitude = allocate_shared_float(nz, nr) + external_source_density_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_density_amplitude = allocate_shared_float(1, 1) + external_source_density_amplitude = allocate_shared_float(1, 1, n_sources) end if evolve_upar - external_source_momentum_amplitude = allocate_shared_float(nz, nr) + external_source_momentum_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_momentum_amplitude = allocate_shared_float(1, 1) + external_source_momentum_amplitude = allocate_shared_float(1, 1, n_sources) end if evolve_ppar - external_source_pressure_amplitude = allocate_shared_float(nz, nr) + external_source_pressure_amplitude = allocate_shared_float(nz, nr, n_sources) else - external_source_pressure_amplitude = allocate_shared_float(1, 1) + external_source_pressure_amplitude = allocate_shared_float(1, 1, n_sources) end - if neutral_source_settings.PI_density_controller_I != 0.0 && - neutral_source_settings.source_type ∈ ("density_profile_control", "density_midpoint_control") - if neutral_source_settings.source_type == "density_profile_control" - external_source_controller_integral = allocate_shared_float(nz, nr) + if any(x -> x.PI_density_controller_I != 0.0 && x.source_type ∈ + ("density_profile_control", "density_midpoint_control"), neutral_source_settings) + if any(x -> x.source_type == "density_profile_control", neutral_source_settings) + external_source_controller_integral = allocate_shared_float(nz, nr, n_sources) else - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end else - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end else - external_source_amplitude = allocate_shared_float(1, 1) - external_source_density_amplitude = allocate_shared_float(1, 1) - external_source_momentum_amplitude = allocate_shared_float(1, 1) - external_source_pressure_amplitude = allocate_shared_float(1, 1) - external_source_controller_integral = allocate_shared_float(1, 1) + external_source_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_density_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_momentum_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_pressure_amplitude = allocate_shared_float(1, 1, n_sources) + external_source_controller_integral = allocate_shared_float(1, 1, n_sources) end if evolve_density || evolve_upar || evolve_ppar diff --git a/moment_kinetics/src/vpa_advection.jl b/moment_kinetics/src/vpa_advection.jl index bd70b3503..74033245d 100644 --- a/moment_kinetics/src/vpa_advection.jl +++ b/moment_kinetics/src/vpa_advection.jl @@ -404,13 +404,15 @@ function update_speed_n_u_p_evolution!(advect, fvec, moments, vpa, z, r, composi end end # add in contributions from charge exchange and ionization collisions + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency if composition.n_neutral_species > 0 && - (abs(collisions.charge_exchange) > 0.0 || abs(collisions.ionization) > 0.0) + (abs(charge_exchange) > 0.0 || abs(ionization) > 0.0) @loop_s is begin @loop_r_z_vperp ir iz ivperp begin @views @. advect[is].speed[:,ivperp,iz,ir] += - collisions.charge_exchange * + charge_exchange * (0.5*vpa.grid/fvec.ppar[iz,ir,is] * (fvec.density_neutral[iz,ir,is]*fvec.ppar[iz,ir,is] - fvec.density[iz,ir,is]*fvec.pz_neutral[iz,ir,is] @@ -419,7 +421,7 @@ function update_speed_n_u_p_evolution!(advect, fvec, moments, vpa, z, r, composi - fvec.density_neutral[iz,ir,is] * (fvec.uz_neutral[iz,ir,is]-fvec.upar[iz,ir,is]) / moments.ion.vth[iz,ir,is]) + - collisions.ionization * + ionization * (0.5*vpa.grid * (fvec.density_neutral[iz,ir,is] - fvec.density[iz,ir,is]*fvec.pz_neutral[iz,ir,is] @@ -433,24 +435,26 @@ function update_speed_n_u_p_evolution!(advect, fvec, moments, vpa, z, r, composi end end end - if ion_source_settings.active - source_density_amplitude = moments.ion.external_source_density_amplitude - source_momentum_amplitude = moments.ion.external_source_momentum_amplitude - source_pressure_amplitude = moments.ion.external_source_pressure_amplitude - density = fvec.density - upar = fvec.upar - ppar = fvec.ppar - vth = moments.ion.vth - vpa_grid = vpa.grid - @loop_s_r_z is ir iz begin - term1 = source_density_amplitude[iz,ir] * upar[iz,ir,is]/(density[iz,ir,is]*vth[iz,ir,is]) - term2_over_vpa = - -0.5 * (source_pressure_amplitude[iz,ir] + - 2.0 * upar[iz,ir,is] * source_momentum_amplitude[iz,ir]) / - ppar[iz,ir,is] + - 0.5 * source_density_amplitude[iz,ir] / density[iz,ir,is] - @loop_vperp_vpa ivperp ivpa begin - advect[is].speed[ivpa,ivperp,iz,ir] += term1 + vpa_grid[ivpa] * term2_over_vpa + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_density_amplitude = moments.ion.external_source_density_amplitude[:, :, index] + @views source_momentum_amplitude = moments.ion.external_source_momentum_amplitude[:, :, index] + @views source_pressure_amplitude = moments.ion.external_source_pressure_amplitude[:, :, index] + density = fvec.density + upar = fvec.upar + ppar = fvec.ppar + vth = moments.ion.vth + vpa_grid = vpa.grid + @loop_s_r_z is ir iz begin + term1 = source_density_amplitude[iz,ir] * upar[iz,ir,is]/(density[iz,ir,is]*vth[iz,ir,is]) + term2_over_vpa = + -0.5 * (source_pressure_amplitude[iz,ir] + + 2.0 * upar[iz,ir,is] * source_momentum_amplitude[iz,ir]) / + ppar[iz,ir,is] + + 0.5 * source_density_amplitude[iz,ir] / density[iz,ir,is] + @loop_vperp_vpa ivperp ivpa begin + advect[is].speed[ivpa,ivperp,iz,ir] += term1 + vpa_grid[ivpa] * term2_over_vpa + end end end end @@ -485,16 +489,18 @@ function update_speed_n_p_evolution!(advect, fields, fvec, moments, vpa, z, r, error("suspect the charge exchange and ionization contributions here may be " * "wrong because (upar[is]-upar[isp])^2 type terms were missed in the " * "energy equation when it was substituted in to derive them.") - if abs(collisions.charge_exchange + collisions.ionization) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange + ionization) > 0.0 @loop_s is begin @loop_r_z_vperp ir iz ivperp begin - @views @. advect[is].speed[:,ivperp,iz,ir] += (collisions.charge_exchange + collisions.ionization) * + @views @. advect[is].speed[:,ivperp,iz,ir] += (charge_exchange + ionization) * 0.5*vpa.grid*fvec.density[iz,ir,is] * (1.0-fvec.pz_neutral[iz,ir,is]/fvec.ppar[iz,ir,is]) end end end end - if ion_source_settings.active + if any(x -> x.active, ion_source_settings) error("External source not implemented for evolving n and ppar case") end end @@ -523,33 +529,37 @@ function update_speed_n_u_evolution!(advect, fvec, moments, vpa, z, r, compositi # and/or ionization collisions betweens ions and neutrals if composition.n_neutral_species > 0 # account for collisional charge exchange friction between ions and neutrals - if abs(collisions.charge_exchange) > 0.0 + charge_exchange = collisions.reactions.charge_exchange_frequency + ionization = collisions.reactions.ionization_frequency + if abs(charge_exchange) > 0.0 @loop_s is begin @loop_r_z_vperp ir iz ivperp begin - @views @. advect[is].speed[:,ivperp,iz,ir] -= collisions.charge_exchange*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-fvec.upar[iz,ir,is]) + @views @. advect[is].speed[:,ivperp,iz,ir] -= charge_exchange*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-fvec.upar[iz,ir,is]) end end end - if abs(collisions.ionization) > 0.0 + if abs(ionization) > 0.0 @loop_s is begin @loop_r_z_vperp ir iz ivperp begin - @views @. advect[is].speed[:,ivperp,iz,ir] -= collisions.ionization*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-fvec.upar[iz,ir,is]) + @views @. advect[is].speed[:,ivperp,iz,ir] -= ionization*fvec.density_neutral[iz,ir,is]*(fvec.uz_neutral[iz,ir,is]-fvec.upar[iz,ir,is]) end end end end - if ion_source_settings.active - source_density_amplitude = moments.ion.external_source_density_amplitude - source_strength = ion_source_settings.source_strength - r_amplitude = ion_source_settings.r_amplitude - z_amplitude = ion_source_settings.z_amplitude - density = fvec.density - upar = fvec.upar - vth = moments.ion.vth - @loop_s_r_z is ir iz begin - term = source_density_amplitude[iz,ir] * upar[iz,ir,is] / density[iz,ir,is] - @loop_vperp_vpa ivperp ivpa begin - advect[is].speed[ivpa,ivperp,iz,ir] += term + for index ∈ eachindex(ion_source_settings) + if ion_source_settings[index].active + @views source_density_amplitude = moments.ion.external_source_density_amplitude[:, :, index] + source_strength = ion_source_settings[index].source_strength + r_amplitude = ion_source_settings[index].r_amplitude + z_amplitude = ion_source_settings[index].z_amplitude + density = fvec.density + upar = fvec.upar + vth = moments.ion.vth + @loop_s_r_z is ir iz begin + term = source_density_amplitude[iz,ir] * upar[iz,ir,is] / density[iz,ir,is] + @loop_vperp_vpa ivperp ivpa begin + advect[is].speed[ivpa,ivperp,iz,ir] += term + end end end end diff --git a/moment_kinetics/test/Krook_collisions_tests.jl b/moment_kinetics/test/Krook_collisions_tests.jl index 806bad279..b3768217b 100644 --- a/moment_kinetics/test/Krook_collisions_tests.jl +++ b/moment_kinetics/test/Krook_collisions_tests.jl @@ -6,15 +6,14 @@ include("setup.jl") using Base.Filesystem: tempname -using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.load_data: open_readonly_output_file, load_coordinate_data, load_species_data, load_fields_data, load_ion_moments_data, load_pdf_data, load_neutral_particle_moments_data, load_neutral_pdf_data, load_time_data, load_species_data using moment_kinetics.interpolation: interpolate_to_grid_z, interpolate_to_grid_vpa -using moment_kinetics.type_definitions: mk_float, OptionsDict +using moment_kinetics.type_definitions: mk_float +using moment_kinetics.utils: merge_dict_with_kwargs! # Useful parameters const z_L = 1.0 # always 1 in normalized units? @@ -85,76 +84,79 @@ const expected = 0.024284888662941113 0.010011392733734206 0.008423252360063494 0.019281192435730943 0.036719507768509525 0.041644492169994836 0.03692283098105331 0.03638215764882269 0.04191389118981368 0.04071460358290303 0.024284888662941134]) # default inputs for tests -test_input_full_f = Dict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0, - "T_wall" => 1.0), - "ion_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.5, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.5, - "temperature_phase" => mk_float(π)), - "neutral_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.5, - "density_phase" => mk_float(π), - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.5, - "temperature_phase" => 0.0), - "run_name" => "full_f", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "krook_collisions" => OptionsDict("use_krook" => true,"frequency_option" => "reference_parameters"), - "charge_exchange_frequency" => 2*π*0.1, - "ionization_frequency" => 0.0, - "timestepping" => OptionsDict("nstep" => 100, - "dt" => 0.001, - "nwrite" => 100, - "nwrite_dfns" => 100, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 4, - "z_bc" => "periodic", - "z_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 8, - "vpa_L" => vpa_L, - "vpa_bc" => "periodic", - "vpa_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 8, - "vz_L" => vpa_L, - "vz_bc" => "periodic", - "vz_discretization" => "chebyshev_pseudospectral") +test_input_full_f = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0, + "T_wall" => 1.0), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => mk_float(π)), + "neutral_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => mk_float(π), + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => 0.0), + "output" => OptionsDict("run_name" => "full_f"), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "krook_collisions" => OptionsDict("use_krook" => true,"frequency_option" => "reference_parameters"), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*π*0.1, + "ionization_frequency" => 0.0), + "timestepping" => OptionsDict("nstep" => 100, + "dt" => 0.001, + "nwrite" => 100, + "nwrite_dfns" => 100, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("ngrid" => 9, + "nelement" => 4, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 17, + "nelement" => 8, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 17, + "nelement" => 8, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral") + ) test_input_split_1_moment = - merge(test_input_full_f, - Dict("run_name" => "split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(test_input_full_f, + OptionsDict("output" => OptionsDict("run_name" => "split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_split_2_moments = - merge(test_input_split_1_moment, - Dict("run_name" => "split_2_moments", - "evolve_moments_parallel_flow" => true)) + recursive_merge(test_input_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_split_3_moments = - merge(test_input_split_2_moments, - Dict("run_name" => "split_3_moments", - "evolve_moments_parallel_pressure" => true, - "vpa_L" => 12.0, "vz_L" => 12.0)) + recursive_merge(test_input_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("L" => 12.0), + "vz" => OptionsDict("L" => 12.0), + )) """ @@ -170,7 +172,7 @@ function run_test(test_input, rtol, atol; args...) input = deepcopy(test_input) # Convert keyword arguments to a unique name - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -183,7 +185,7 @@ function run_test(test_input, rtol, atol; args...) # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running quietoutput() do @@ -209,7 +211,7 @@ function run_test(test_input, rtol, atol; args...) # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name, name) + path = joinpath(realpath(input["output"]["base_directory"]), name, name) # open the netcdf file containing moments data and give it the handle 'fid' fid = open_readonly_output_file(path, "moments") @@ -254,7 +256,7 @@ function run_test(test_input, rtol, atol; args...) f_neutral = f_neutral_vzvrvzetazrst[:,1,1,:,1,:,:] # Unnormalize f - if input["evolve_moments_density"] + if input["evolve_moments"]["density"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] .*= n_ion[iz,is,it] end @@ -262,7 +264,7 @@ function run_test(test_input, rtol, atol; args...) f_neutral[:,iz,isn,it] .*= n_neutral[iz,isn,it] end end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] ./= v_t_ion[iz,is,it] end @@ -356,10 +358,10 @@ function run_test(test_input, rtol, atol; args...) size(newgrid_f_ion, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_ion[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_ion[iz,1] end newgrid_f_ion[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vpa, vpa_spectral) @@ -387,10 +389,10 @@ function run_test(test_input, rtol, atol; args...) size(newgrid_f_neutral, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_neutral[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_neutral[iz,1] end newgrid_f_neutral[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vpa, vpa_spectral) @@ -417,19 +419,19 @@ function runtests() # Benchmark data is taken from this run (full-f with no splitting) @testset "full-f" begin - test_input_full_f["base_directory"] = test_output_directory + test_input_full_f["output"]["base_directory"] = test_output_directory run_test(test_input_full_f, 1.e-10, 3.e-16) end @testset "split 1" begin - test_input_split_1_moment["base_directory"] = test_output_directory + test_input_split_1_moment["output"]["base_directory"] = test_output_directory run_test(test_input_split_1_moment, 1.e-3, 1.e-15) end @testset "split 2" begin - test_input_split_2_moments["base_directory"] = test_output_directory + test_input_split_2_moments["output"]["base_directory"] = test_output_directory run_test(test_input_split_2_moments, 1.e-3, 1.e-15) end @testset "split 3" begin - test_input_split_3_moments["base_directory"] = test_output_directory + test_input_split_3_moments["output"]["base_directory"] = test_output_directory run_test(test_input_split_3_moments, 1.e-3, 1.e-15) end end diff --git a/moment_kinetics/test/braginskii_electrons_imex_tests.jl b/moment_kinetics/test/braginskii_electrons_imex_tests.jl index 4bf902b8c..5a2ba1daa 100644 --- a/moment_kinetics/test/braginskii_electrons_imex_tests.jl +++ b/moment_kinetics/test/braginskii_electrons_imex_tests.jl @@ -9,22 +9,20 @@ include("setup.jl") using Base.Filesystem: tempname using MPI -using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.interpolation: interpolate_to_grid_z using moment_kinetics.load_data: get_run_info_no_setup, close_run_info, get_variable -using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: merge_dict_with_kwargs! # default inputs for tests test_input = OptionsDict( "composition" => OptionsDict("n_ion_species" => 1, "n_neutral_species" => 1, "electron_physics" => "braginskii_fluid", "T_e" => 0.2), - "run_name" => "braginskii-electrons-imex", - "evolve_moments_density" => true, - "evolve_moments_parallel_flow" => true, - "evolve_moments_parallel_pressure" => true, - "evolve_moments_conservation" => true, + "output" => OptionsDict("run_name" => "braginskii-electrons-imex"), + "evolve_moments" => OptionsDict("density" => true, + "parallel_flow" => true, + "parallel_pressure" => true, + "moments_conservation" => true), "ion_species_1" => OptionsDict("initial_density" => 1.0, "initial_temperature" => 1.0), "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", @@ -50,17 +48,18 @@ test_input = OptionsDict( "composition" => OptionsDict("n_ion_species" => 1, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "vpa_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "nu_ei" => 1.0e3, - "charge_exchange_frequency" => 0.75, - "ionization_frequency" => 0.5, - "constant_ionization_rate" => false, + "vz_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "electron_fluid_collisions" => OptionsDict("nu_ei" => 1.0e3), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.75, + "electron_charge_exchange_frequency" => 0.0, + "ionization_frequency" => 0.5, + "electron_ionization_frequency" => 0.5), "timestepping" => OptionsDict("type" => "KennedyCarpenterARK324", "implicit_ion_advance" => false, "implicit_vpa_advection" => false, @@ -71,22 +70,22 @@ test_input = OptionsDict( "composition" => OptionsDict("n_ion_species" => 1, "nwrite" => 10000, "high_precision_error_sum" => true), "nonlinear_solver" => OptionsDict("nonlinear_max_iterations" => 100), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 17, - "z_nelement" => 16, - "z_bc" => "periodic", - "z_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 6, - "vpa_nelement" => 31, - "vpa_L" => 12.0, - "vpa_bc" => "zero", - "vpa_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 6, - "vz_nelement" => 31, - "vz_L" => 12.0, - "vz_bc" => "zero", - "vz_discretization" => "chebyshev_pseudospectral", + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 17, + "nelement" => 16, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 6, + "nelement" => 31, + "L" => 12.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 6, + "nelement" => 31, + "L" => 12.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral"), "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, "vpa_dissipation_coefficient" => 1e0), "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, @@ -94,7 +93,7 @@ test_input = OptionsDict( "composition" => OptionsDict("n_ion_species" => 1, if global_size[] > 2 && global_size[] % 2 == 0 # Test using distributed-memory - test_input["z_nelement_local"] = test_input["z_nelement"] ÷ 2 + test_input["z"]["nelement_local"] = test_input["z"]["nelement"] ÷ 2 end """ @@ -110,7 +109,7 @@ function run_test(test_input, expected_p, expected_q, expected_vt; rtol=1.e-6, input = deepcopy(test_input) # Convert keyword arguments to a unique name - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -123,7 +122,7 @@ function run_test(test_input, expected_p, expected_q, expected_vt; rtol=1.e-6, # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running p = undef @@ -139,7 +138,7 @@ function run_test(test_input, expected_p, expected_q, expected_vt; rtol=1.e-6, # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name) + path = joinpath(realpath(input["output"]["base_directory"]), name) # open the output file run_info = get_run_info_no_setup(path) @@ -283,15 +282,15 @@ function runtests() end else @testset "Split 3" begin - test_input["base_directory"] = test_output_directory + test_input["output"]["base_directory"] = test_output_directory run_test(test_input, expected_p, expected_q, expected_vt) end @long @testset "Check other timestep - $type" for type ∈ ("KennedyCarpenterARK437",) timestep_check_input = deepcopy(test_input) - timestep_check_input["base_directory"] = test_output_directory - timestep_check_input["run_name"] = type + timestep_check_input["output"]["base_directory"] = test_output_directory + timestep_check_input["output"]["run_name"] = type timestep_check_input["timestepping"]["type"] = type run_test(timestep_check_input, expected_p, expected_q, expected_vt, rtol=2.e-4, atol=1.e-10) diff --git a/moment_kinetics/test/calculus_tests.jl b/moment_kinetics/test/calculus_tests.jl index 9608371ee..58fc00f1f 100644 --- a/moment_kinetics/test/calculus_tests.jl +++ b/moment_kinetics/test/calculus_tests.jl @@ -2,8 +2,7 @@ module CalculusTests include("setup.jl") -using moment_kinetics.input_structs: grid_input, advection_input -using moment_kinetics.coordinates: define_coordinate +using moment_kinetics.coordinates: define_test_coordinate using moment_kinetics.calculus: derivative!, second_derivative!, integral using moment_kinetics.calculus: laplacian_derivative! @@ -14,7 +13,7 @@ function runtests() @testset "calculus" verbose=use_verbose begin println("calculus tests") @testset "fundamental theorem of calculus" begin - @testset "$discretization $ngrid $nelement" for + @testset "$discretization $ngrid $nelement $cheb_option" for (discretization, element_spacing_option, etol, cheb_option) ∈ (("finite_difference", "uniform", 1.0e-15, ""), ("chebyshev_pseudospectral", "uniform", 1.0e-15, "FFT"), ("chebyshev_pseudospectral", "uniform", 2.0e-15, "matrix"), ("chebyshev_pseudospectral", "sqrt", 1.0e-2, "FFT"), ("gausslegendre_pseudospectral", "uniform", 1.0e-14, "")), ngrid ∈ (5,6,7,8,9,10), nelement ∈ (1, 2, 3, 4, 5) @@ -29,24 +28,23 @@ function runtests() # define inputs needed for the test L = 6.0 - bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant + if discretization == "finite_difference" + bc = "periodic" + else + bc = "none" + end fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - discretization, fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization=discretization, + finite_difference_option=fd_option, + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # create array for the function f(x) to be differentiated/integrated f = Array{Float64,1}(undef, x.n) # create array for the derivative df/dx @@ -80,33 +78,28 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - element_spacing_option = "uniform" # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "finite_difference", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) + element_spacing_option = "uniform" # dummy value # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="finite_difference", + finite_difference_option=fd_option, + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # create array for the derivative df/dx and the expected result df = Array{Float64,1}(undef, x.n) # initialize f and expected df offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) # differentiate f derivative!(df, f, x, spectral) @@ -114,6 +107,7 @@ function runtests() rtol = 1.e2 / (nelement*(ngrid-1))^4 @test isapprox(df, expected_df, rtol=rtol, atol=1.e-15, norm=maxabs_norm) + @test df[1] == df[end] end end @@ -132,33 +126,28 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant fd_option = "fourth_order_centered" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "finite_difference", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="finite_difference", + finite_difference_option=fd_option, + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # create array for the derivative df/dx and the expected result df = Array{Float64,1}(undef, x.n) # initialize f and expected df offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) for advection ∈ (-1.0, 0.0, 1.0) adv_fac = similar(f) @@ -170,6 +159,7 @@ function runtests() rtol = 1.e2 / (nelement*(ngrid-1))^order @test isapprox(df, expected_df, rtol=rtol, atol=1.e-15, norm=maxabs_norm) + df[1] == df[end] end end end @@ -180,25 +170,19 @@ function runtests() # define inputs needed for the test L = 6.0 - # fd_option and adv_input not actually used so given values unimportant fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "finite_difference", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="finite_difference", + finite_difference_option=fd_option, + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # create array for the derivative df/dx and the expected result df = Array{Float64,1}(undef, x.n) @@ -237,24 +221,18 @@ function runtests() # define inputs needed for the test L = 6.0 - # fd_option and adv_input not actually used so given values unimportant - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "finite_difference", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="finite_difference", + finite_difference_option=fd_option, + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # create array for the derivative df/dx and the expected result df = Array{Float64,1}(undef, x.n) @@ -292,7 +270,7 @@ function runtests() end @testset "Chebyshev pseudospectral derivatives (4 argument), periodic" verbose=false begin - @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ + @testset "$nelement $ngrid $cheb_option" for (nelement, ngrid, rtol) ∈ ( (1, 5, 8.e-1), (1, 6, 2.e-1), @@ -301,13 +279,13 @@ function runtests() (1, 9, 5.e-3), (1, 10, 3.e-3), (1, 11, 1.e-4), - (1, 12, 5.e-6), + (1, 12, 1.e-5), (1, 13, 3.e-6), - (1, 14, 8.e-8), + (1, 14, 1.e-7), (1, 15, 4.e-8), - (1, 16, 8.e-10), + (1, 16, 1.e-8), (1, 17, 4.e-10), - (1, 18, 4.e-12), + (1, 18, 1.e-10), (1, 19, 2.e-12), (1, 20, 2.e-13), (1, 21, 2.e-13), @@ -327,15 +305,15 @@ function runtests() (2, 4, 2.e-1), (2, 5, 4.e-2), (2, 6, 2.e-2), - (2, 7, 4.e-4), + (2, 7, 1.e-3), (2, 8, 2.e-4), - (2, 9, 4.e-6), + (2, 9, 1.e-5), (2, 10, 2.e-6), - (2, 11, 2.e-8), + (2, 11, 1.e-7), (2, 12, 1.e-8), - (2, 13, 1.e-10), + (2, 13, 1.e-9), (2, 14, 5.e-11), - (2, 15, 4.e-13), + (2, 15, 1.e-12), (2, 16, 2.e-13), (2, 17, 2.e-13), (2, 18, 2.e-13), @@ -455,28 +433,22 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) # create array for the derivative df/dx df = similar(f) @@ -486,26 +458,27 @@ function runtests() @test isapprox(df, expected_df, rtol=rtol, atol=1.e-14, norm=maxabs_norm) + @test df[1] == df[end] end end @testset "Chebyshev pseudospectral derivatives upwinding (5 argument), periodic" verbose=false begin - @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ + @testset "$nelement $ngrid $cheb_option" for (nelement, ngrid, rtol) ∈ ( (1, 5, 8.e-1), (1, 6, 2.e-1), (1, 7, 1.e-1), - (1, 8, 1.e-2), + (1, 8, 5.e-2), (1, 9, 5.e-3), (1, 10, 3.e-3), (1, 11, 1.e-4), - (1, 12, 5.e-6), + (1, 12, 3.e-5), (1, 13, 3.e-6), - (1, 14, 8.e-8), + (1, 14, 4.e-7), (1, 15, 4.e-8), - (1, 16, 8.e-10), + (1, 16, 4.e-9), (1, 17, 4.e-10), - (1, 18, 4.e-12), + (1, 18, 4.e-11), (1, 19, 2.e-12), (1, 20, 2.e-13), (1, 21, 2.e-13), @@ -523,17 +496,17 @@ function runtests() (1, 33, 2.e-13), (2, 4, 2.e-1), - (2, 5, 4.e-2), + (2, 5, 6.e-2), (2, 6, 2.e-2), - (2, 7, 4.e-4), + (2, 7, 2.e-3), (2, 8, 2.e-4), - (2, 9, 4.e-6), + (2, 9, 2.e-5), (2, 10, 2.e-6), - (2, 11, 2.e-8), + (2, 11, 1.e-7), (2, 12, 1.e-8), - (2, 13, 1.e-10), + (2, 13, 1.e-9), (2, 14, 5.e-11), - (2, 15, 4.e-13), + (2, 15, 2.e-12), (2, 16, 2.e-13), (2, 17, 2.e-13), (2, 18, 2.e-13), @@ -653,28 +626,22 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) # create array for the derivative df/dx df = similar(f) @@ -688,34 +655,29 @@ function runtests() @test isapprox(df, expected_df, rtol=rtol, atol=1.e-12, norm=maxabs_norm) + @test df[1] == df[end] end end end @testset "Chebyshev pseudospectral derivatives (4 argument), polynomials" verbose=false begin - @testset "$nelement $ngrid" for bc ∈ ("constant", "zero"), element_spacing_option ∈ ("uniform", "sqrt"), + @testset "$nelement $ngrid $bc $element_spacing_option $cheb_option" for + bc ∈ ("constant", "zero"), element_spacing_option ∈ ("uniform", "sqrt"), nelement ∈ (1:5), ngrid ∈ (3:33), cheb_option in ("FFT","matrix") # define inputs needed for the test L = 1.0 bc = "constant" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # test polynomials up to order ngrid-1 for n ∈ 0:ngrid-1 # create array for the function f(x) to be differentiated/integrated @@ -745,29 +707,23 @@ function runtests() end @testset "Chebyshev pseudospectral derivatives upwinding (5 argument), polynomials" verbose=false begin - @testset "$nelement $ngrid" for bc ∈ ("constant", "zero"), element_spacing_option ∈ ("uniform", "sqrt"), + @testset "$nelement $ngrid $bc $element_spacing_option $cheb_option" for + bc ∈ ("constant", "zero"), element_spacing_option ∈ ("uniform", "sqrt"), nelement ∈ (1:5), ngrid ∈ (3:33), cheb_option in ("FFT","matrix") # define inputs needed for the test L = 1.0 bc = "constant" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # test polynomials up to order ngrid-1 for n ∈ 0:ngrid-1 # create array for the function f(x) to be differentiated/integrated @@ -812,26 +768,26 @@ function runtests() (1, 9, 5.e-3), (1, 10, 3.e-3), (1, 11, 5.e-4), - (1, 12, 5.e-6), + (1, 12, 1.e-5), (1, 13, 3.e-6), - (1, 14, 8.e-8), + (1, 14, 3.e-7), (1, 15, 4.e-8), - (1, 16, 8.e-10), + (1, 16, 4.e-9), (1, 17, 8.e-10), (2, 4, 2.e-1), (2, 5, 4.e-2), (2, 6, 2.e-2), - (2, 7, 4.e-4), + (2, 7, 1.e-3), (2, 8, 2.e-4), - (2, 9, 4.e-6), + (2, 9, 1.e-5), (2, 10, 2.e-6), - (2, 11, 2.e-8), + (2, 11, 1.e-7), (2, 12, 1.e-8), - (2, 13, 1.e-10), + (2, 13, 1.e-9), (2, 14, 5.e-11), - (2, 15, 4.e-13), + (2, 15, 2.e-12), (2, 16, 2.e-13), (2, 17, 2.e-13), @@ -887,29 +843,20 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) # create array for the derivative df/dx df = similar(f) @@ -919,6 +866,7 @@ function runtests() @test isapprox(df, expected_df, rtol=rtol, atol=1.e-14, norm=maxabs_norm) + @test df[1] == df[end] end end @@ -926,31 +874,31 @@ function runtests() @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ ( (1, 5, 8.e-1), - (1, 6, 2.e-1), + (1, 6, 3.e-1), (1, 7, 1.e-1), - (1, 8, 1.e-2), + (1, 8, 2.e-2), (1, 9, 5.e-3), (1, 10, 3.e-3), (1, 11, 8.e-4), - (1, 12, 5.e-6), + (1, 12, 3.e-5), (1, 13, 3.e-6), - (1, 14, 8.e-8), + (1, 14, 5.e-7), (1, 15, 4.e-8), - (1, 16, 8.e-10), + (1, 16, 8.e-9), (1, 17, 8.e-10), (2, 4, 2.e-1), - (2, 5, 4.e-2), + (2, 5, 8.e-2), (2, 6, 2.e-2), - (2, 7, 4.e-4), + (2, 7, 2.e-3), (2, 8, 2.e-4), - (2, 9, 4.e-6), + (2, 9, 2.e-5), (2, 10, 2.e-6), - (2, 11, 2.e-8), + (2, 11, 2.e-7), (2, 12, 1.e-8), - (2, 13, 1.e-10), + (2, 13, 1.e-9), (2, 14, 5.e-11), - (2, 15, 4.e-13), + (2, 15, 5.e-12), (2, 16, 2.e-13), (2, 17, 2.e-13), @@ -979,7 +927,7 @@ function runtests() (4, 9, 8.e-8), (4, 10, 4.e-9), (4, 11, 5.e-10), - (4, 12, 4.e-12), + (4, 12, 1.e-11), (4, 13, 2.e-13), (4, 14, 2.e-13), (4, 15, 2.e-13), @@ -989,7 +937,7 @@ function runtests() (5, 3, 2.e-1), (5, 4, 2.e-2), (5, 5, 2.e-3), - (5, 6, 1.e-4), + (5, 6, 2.e-4), (5, 7, 1.e-5), (5, 8, 4.e-7), (5, 9, 2.e-8), @@ -1006,29 +954,22 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_df = @. 2.0 * π / L * cospi(2.0 * x.grid / L + phase) # create array for the derivative df/dx df = similar(f) @@ -1042,6 +983,7 @@ function runtests() @test isapprox(df, expected_df, rtol=rtol, atol=1.e-12, norm=maxabs_norm) + @test df[1] == df[end] end end end @@ -1053,24 +995,16 @@ function runtests() # define inputs needed for the test L = 1.0 bc = "constant" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" #not used - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # test polynomials up to order ngrid-1 for n ∈ 0:ngrid-1 # create array for the function f(x) to be differentiated/integrated @@ -1106,24 +1040,16 @@ function runtests() # define inputs needed for the test L = 1.0 bc = "constant" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" # not used - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) # test polynomials up to order ngrid-1 for n ∈ 0:ngrid-1 # create array for the function f(x) to be differentiated/integrated @@ -1159,22 +1085,22 @@ function runtests() end @testset "Chebyshev pseudospectral second derivatives (4 argument), periodic" verbose=false begin - @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ + @testset "$nelement $ngrid $cheb_option" for (nelement, ngrid, rtol) ∈ ( (1, 5, 8.e-1), (1, 6, 2.e-1), (1, 7, 1.e-1), - (1, 8, 1.e-2), + (1, 8, 4.e-2), (1, 9, 5.e-3), (1, 10, 3.e-3), (1, 11, 2.e-4), - (1, 12, 5.e-6), - (1, 13, 4.e-6), - (1, 14, 1.e-7), + (1, 12, 2.e-4), + (1, 13, 8.e-6), + (1, 14, 4.e-6), (1, 15, 1.e-7), - (1, 16, 2.e-9), + (1, 16, 1.e-7), (1, 17, 1.e-9), - (1, 18, 4.e-12), + (1, 18, 1.e-9), (1, 19, 2.e-12), (1, 20, 2.e-13), (1, 21, 2.e-13), @@ -1192,15 +1118,15 @@ function runtests() (1, 33, 2.e-13), (2, 4, 2.e-1), - (2, 5, 4.e-2), + (2, 5, 8.e-2), (2, 6, 2.e-2), - (2, 7, 4.e-4), - (2, 8, 2.e-4), - (2, 9, 4.e-6), + (2, 7, 8.e-3), + (2, 8, 4.e-4), + (2, 9, 2.e-4), (2, 10, 4.e-6), - (2, 11, 4.e-8), + (2, 11, 2.e-6), (2, 12, 4.e-8), - (2, 13, 2.e-10), + (2, 13, 2.e-8), (2, 14, 2.e-10), (2, 15, 4.e-13), (2, 16, 2.e-13), @@ -1225,7 +1151,7 @@ function runtests() (3, 3, 4.e-1), (3, 4, 1.e-1), (3, 5, 2.e-2), - (3, 6, 4.e-3), + (3, 6, 8.e-3), (3, 7, 1.e-3), (3, 8, 1.e-4), (3, 9, 1.e-5), @@ -1288,7 +1214,7 @@ function runtests() (5, 3, 4.e-1), (5, 4, 4.e-2), - (5, 5, 4.e-3), + (5, 5, 8.e-3), (5, 6, 1.e-3), (5, 7, 4.e-5), (5, 8, 1.e-5), @@ -1322,28 +1248,22 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_d2f = @. -4.0 * π^2 / L^2 * sinpi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_d2f = @. -4.0 * π^2 / L^2 * sinpi(2.0 * x.grid / L + phase) # create array for the derivative d2f/dx2 d2f = similar(f) @@ -1353,11 +1273,12 @@ function runtests() @test isapprox(d2f, expected_d2f, rtol=rtol, atol=1.e-10, norm=maxabs_norm) + @test d2f[1] == d2f[end] end end @testset "Chebyshev pseudospectral cylindrical laplacian derivatives (4 argument), zero" verbose=false begin - @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ + @testset "$nelement $ngrid $cheb_option" for (nelement, ngrid, rtol) ∈ ( (4, 7, 2.e-1), (4, 8, 2.e-1), @@ -1419,24 +1340,17 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "zero" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("vperp", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "chebyshev_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("vperp"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="chebyshev_pseudospectral", + cheb_option=cheb_option, bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) f = @. exp(-x.grid^2) expected_d2f = @. 4.0*(x.grid^2 - 1.0)*exp(-x.grid^2) @@ -1526,29 +1440,22 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("coord"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) offset = randn(rng) - f = @. sinpi(2.0 * x.grid / L) + offset - expected_d2f = @. -4.0 * π^2 / L^2 * sinpi(2.0 * x.grid / L) + phase = 0.42 + f = @. sinpi(2.0 * x.grid / L + phase) + offset + expected_d2f = @. -4.0 * π^2 / L^2 * sinpi(2.0 * x.grid / L + phase) # create array for the derivative d2f/dx2 d2f = similar(f) @@ -1558,20 +1465,21 @@ function runtests() @test isapprox(d2f, expected_d2f, rtol=rtol, atol=1.e-10, norm=maxabs_norm) + @test d2f[1] == d2f[end] end end - @testset "GaussLegendre pseudospectral cylindrical laplacian derivatives (4 argument), zero" verbose=false begin + @testset "GaussLegendre pseudospectral cylindrical laplacian derivatives (4 argument), zero" verbose=false begin @testset "$nelement $ngrid" for (nelement, ngrid, rtol) ∈ ( - (1, 8, 5.e-2), + (1, 8, 1.e-1), (1, 9, 1.e-1), (1, 10, 2.e-1), - (1, 11, 5.e-2), + (1, 11, 6.e-2), (1, 12, 5.e-2), (1, 13, 5.e-2), (1, 14, 5.e-2), - (1, 15, 5.e-3), + (1, 15, 1.e-2), (1, 16, 5.e-2), (1, 17, 5.e-3), @@ -1633,25 +1541,17 @@ function runtests() # define inputs needed for the test L = 6.0 bc = "zero" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "" - # create the 'input' struct containing input info needed to create a - # coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value element_spacing_option = "uniform" - input = grid_input("vperp", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - "gausslegendre_pseudospectral", fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) - # create the coordinate struct 'x' and info for derivatives, etc. - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - x, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + # create the coordinate struct 'x' + # This test runs effectively in serial, so implicitly uses + # `ignore_MPI=true` to avoid errors due to communicators not being fully + # set up. + x, spectral = define_test_coordinate("vperp"; ngrid=ngrid, + nelement=nelement, L=L, + discretization="gausslegendre_pseudospectral", + bc=bc, + element_spacing_option=element_spacing_option, + collision_operator_dim=false) f = @. exp(-x.grid^2) expected_d2f = @. 4.0*(x.grid^2 - 1.0)*exp(-x.grid^2) diff --git a/moment_kinetics/test/fokker_planck_tests.jl b/moment_kinetics/test/fokker_planck_tests.jl index 8472de5c7..8f2dafbd7 100644 --- a/moment_kinetics/test/fokker_planck_tests.jl +++ b/moment_kinetics/test/fokker_planck_tests.jl @@ -8,7 +8,6 @@ using LinearAlgebra: mul!, ldiv! using moment_kinetics.communication using moment_kinetics.looping using moment_kinetics.array_allocation: allocate_float, allocate_shared_float -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.type_definitions: mk_float, mk_int using moment_kinetics.velocity_moments: get_density, get_upar, get_ppar, get_pperp, get_pressure @@ -33,32 +32,27 @@ function create_grids(ngrid,nelement_vpa,nelement_vperp; nelement_local_vperp = nelement_vperp # number of elements per rank nelement_global_vperp = nelement_local_vperp # total number of elements bc = "zero" # used only in derivative! functions - # fd_option and adv_input not actually used so given values unimportant #discretization = "chebyshev_pseudospectral" discretization = "gausslegendre_pseudospectral" - fd_option = "fourth_order_centered" - cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = MPI.COMM_NULL # create the 'input' struct containing input info needed to create a # coordinate element_spacing_option = "uniform" - vpa_input = grid_input("vpa", ngrid, nelement_global_vpa, nelement_local_vpa, - nrank, irank, Lvpa, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - vperp_input = grid_input("vperp", ngrid, nelement_global_vperp, nelement_local_vperp, - nrank, irank, Lvperp, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - # create the coordinate struct 'x' - #println("made inputs") - #println("vpa: ngrid: ",ngrid," nelement: ",nelement_local_vpa, " Lvpa: ",Lvpa) - #println("vperp: ngrid: ",ngrid," nelement: ",nelement_local_vperp, " Lvperp: ",Lvperp) + coords_input = OptionsDict( + "vperp"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global_vperp, + "nelement_local"=>nelement_local_vperp, "L"=>Lvperp, + "discretization"=>discretization, "bc"=>bc, + "element_spacing_option"=>element_spacing_option), + "vpa"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global_vpa, + "nelement_local"=>nelement_local_vpa, "L"=>Lvpa, + "discretization"=>discretization, "bc"=>bc, + "element_spacing_option"=>element_spacing_option), + ) # Set up MPI initialize_comms!() setup_distributed_memory_MPI(1,1,1,1) - vpa, vpa_spectral = define_coordinate(vpa_input, nothing) - vperp, vperp_spectral = define_coordinate(vperp_input, nothing) + vperp, vperp_spectral = define_coordinate(coords_input, "vperp") + vpa, vpa_spectral = define_coordinate(coords_input, "vpa") looping.setup_loop_ranges!(block_rank[], block_size[]; s=1, sn=1, r=1, z=1, vperp=vperp.n, vpa=vpa.n, diff --git a/moment_kinetics/test/fokker_planck_time_evolution_tests.jl b/moment_kinetics/test/fokker_planck_time_evolution_tests.jl index 544a5fafa..41cf44957 100644 --- a/moment_kinetics/test/fokker_planck_time_evolution_tests.jl +++ b/moment_kinetics/test/fokker_planck_time_evolution_tests.jl @@ -4,13 +4,12 @@ include("setup.jl") using Base.Filesystem: tempname using MPI -using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.load_data: open_readonly_output_file, load_coordinate_data, load_species_data, load_fields_data, load_ion_moments_data, load_pdf_data, load_time_data, load_species_data -using moment_kinetics.type_definitions: mk_float, OptionsDict +using moment_kinetics.type_definitions: mk_float +using moment_kinetics.utils: merge_dict_with_kwargs! const analytical_rtol = 3.e-2 const regression_rtol = 2.e-8 @@ -223,51 +222,53 @@ for k in 1:ntind end """ # default inputs for tests -test_input_gauss_legendre = Dict("run_name" => "gausslegendre_pseudospectral", - "base_directory" => test_output_directory, - "composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 0, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0), - "ion_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_ngrid" => 3, - "vpa_L" => 6.0, - "vpa_nelement" => 6, - "vpa_bc" => "zero", - "vpa_discretization" => "gausslegendre_pseudospectral", - "vperp_ngrid" => 3, - "vperp_nelement" => 3, - "vperp_L" => 3.0, - "vperp_discretization" => "gausslegendre_pseudospectral", - "ionization_frequency" => 0.0, - "charge_exchange_frequency" => 0.0, - "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "nuii" => 1.0, "frequency_option" => "manual"), - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, - "evolve_moments_parallel_flow" => false, - "z_discretization" => "chebyshev_pseudospectral", - "evolve_moments_density" => false, - "z_ngrid" => 1, - "z_nelement_local" => 1, - "z_nelement" => 1, - "z_bc" => "wall", - "r_discretization" => "chebyshev_pseudospectral", - "r_ngrid" => 1, - "r_nelement" => 1, - "r_nelement_local" => 1, - "r_bc" => "periodic", - "timestepping" => OptionsDict("dt" => 0.01, - "nstep" => 5000, - "nwrite" => 5000, - "nwrite_dfns" => 5000 )) +test_input_gauss_legendre = OptionsDict("output" => OptionsDict("run_name" => "gausslegendre_pseudospectral", + "base_directory" => test_output_directory), + "composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 0, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + + "vpa" => OptionsDict("ngrid" => 3, + "L" => 6.0, + "nelement" => 6, + "bc" => "zero", + "discretization" => "gausslegendre_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 3, + "nelement" => 3, + "L" => 3.0, + "discretization" => "gausslegendre_pseudospectral"), + "reactions" => OptionsDict("ionization_frequency" => 0.0, + "charge_exchange_frequency" => 0.0), + "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "nuii" => 1.0, "frequency_option" => "manual"), + "evolve_moments" => OptionsDict("parallel_pressure" => false, + "moments_conservation" => false, + "parallel_flow" => false, + "density" => false), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 1, + "nelement_local" => 1, + "nelement" => 1, + "bc" => "wall"), + "r" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 1, + "nelement" => 1, + "nelement_local" => 1, + "bc" => "periodic"), + "timestepping" => OptionsDict("dt" => 0.01, + "nstep" => 5000, + "nwrite" => 5000, + "nwrite_dfns" => 5000), + ) """ @@ -287,12 +288,16 @@ function run_test(test_input, expected, rtol, atol, upar_rtol=nothing; args...) end # Convert keyword arguments to a unique name - name = input["run_name"] + function stringify_arg(key, value) + if isa(value, AbstractDict) + return string(string(key)[1], (stringify_arg(k, v) for (k, v) in value)...) + else + return string(string(key)[1], value) + end + end + name = input["output"]["run_name"] if length(args) > 0 - name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) - - # Remove trailing "_" - name = chop(name) + name = string(name, "_", (stringify_arg(k, v) for (k, v) in args)...) end # Provide some progress info @@ -300,7 +305,7 @@ function run_test(test_input, expected, rtol, atol, upar_rtol=nothing; args...) # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running quietoutput() do # run simulation @@ -326,7 +331,7 @@ function run_test(test_input, expected, rtol, atol, upar_rtol=nothing; args...) # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name, name) + path = joinpath(realpath(input["output"]["base_directory"]), name, name) # open the netcdf file containing moments data and give it the handle 'fid' fid = open_readonly_output_file(path, "moments") @@ -422,22 +427,21 @@ function runtests() vperp_bc = "zero-impose-regularity" run_test(test_input_gauss_legendre, expected_zero_impose_regularity, 1.0e-14, 1.0e-14; - vperp_bc=vperp_bc) + vperp=OptionsDict("bc" => vperp_bc)) end @testset "Gauss Legendre no enforced regularity condition at vperp = 0" begin run_name = "gausslegendre_pseudospectral_no_regularity" vperp_bc = "zero" run_test(test_input_gauss_legendre, expected_zero, - 1.0e-14, 1.0e-14; vperp_bc=vperp_bc) + 1.0e-14, 1.0e-14; vperp=OptionsDict("bc" => vperp_bc)) end @testset "Gauss Legendre no (explicitly) enforced boundary conditions" begin run_name = "gausslegendre_pseudospectral_none_bc" vperp_bc = "none" vpa_bc = "none" - run_test(test_input_gauss_legendre, - expected_none_bc, - 1.0e-14, 1.0e-14; vperp_bc=vperp_bc, vpa_bc=vpa_bc) + run_test(test_input_gauss_legendre, expected_none_bc, 1.0e-14, 1.0e-14; + vperp=OptionsDict("bc" => vperp_bc), vpa=OptionsDict("bc" => vpa_bc)) end end end diff --git a/moment_kinetics/test/gyroaverage_tests.jl b/moment_kinetics/test/gyroaverage_tests.jl index f134a4bf5..b42564709 100644 --- a/moment_kinetics/test/gyroaverage_tests.jl +++ b/moment_kinetics/test/gyroaverage_tests.jl @@ -16,7 +16,7 @@ using moment_kinetics.looping using moment_kinetics.array_allocation: allocate_float, allocate_shared_float using moment_kinetics.gyroaverages: gyroaverage_pdf! using moment_kinetics.gyroaverages: gyroaverage_field!, init_gyro_operators -using moment_kinetics.type_definitions: mk_float, mk_int, OptionsDict +using moment_kinetics.type_definitions: mk_float, mk_int using moment_kinetics.species_input: get_species_input print_test_results = false @@ -107,14 +107,9 @@ function gyroaverage_test(absolute_error; rhostar=0.1, pitch=0.5, ngrid=5, kr=2, gyrophase_nelement_global = gyrophase_nelement_local # total number of elements gyrophase_discretization = "finite_difference" gyrophase_L = 2.0*pi + gyrophase_bc = "periodic" - # fd_option and adv_input not actually used so given values unimportant - fd_option = "fourth_order_centered" cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0#1 - comm = MPI.COMM_NULL element_spacing_option = "uniform" # create the 'input' struct containing input info needed to create a # coordinate @@ -124,27 +119,54 @@ function gyroaverage_test(absolute_error; rhostar=0.1, pitch=0.5, ngrid=5, kr=2, setup_distributed_memory_MPI(1,1,1,1) irank_z, nrank_z, comm_sub_z, irank_r, nrank_r, comm_sub_r = setup_distributed_memory_MPI(z_nelement_global,z_nelement_local,r_nelement_global,r_nelement_local) - r_input = grid_input("r", r_ngrid, r_nelement_global, r_nelement_local, - nrank_r, irank_r, r_L, discretization, fd_option, cheb_option, r_bc, adv_input,comm_sub_r,element_spacing_option) - z_input = grid_input("z", z_ngrid, z_nelement_global, z_nelement_local, - nrank_z, irank_z, z_L, discretization, fd_option, cheb_option, z_bc, adv_input,comm_sub_z,element_spacing_option) - vperp_input = grid_input("vperp", vperp_ngrid, vperp_nelement_global, vperp_nelement_local, - nrank, irank, vperp_L, discretization, fd_option, cheb_option, vperp_bc, adv_input,comm,element_spacing_option) - vpa_input = grid_input("vpa", vpa_ngrid, vpa_nelement_global, vpa_nelement_local, - nrank, irank, vpa_L, discretization, fd_option, cheb_option, vpa_bc, adv_input,comm,element_spacing_option) - gyrophase_input = grid_input("gyrophase", gyrophase_ngrid, gyrophase_nelement_global, gyrophase_nelement_local, - nrank, irank, gyrophase_L, gyrophase_discretization, fd_option, cheb_option, "periodic", adv_input,comm,element_spacing_option) + coords_input = OptionsDict( + "r"=>OptionsDict("ngrid"=>r_ngrid, "nelement"=>r_nelement_global, + "nelement_local"=>r_nelement_local, "L"=>r_L, + "discretization"=>discretization, "cheb_option"=>cheb_option, + "bc"=>r_bc, + "element_spacing_option"=>element_spacing_option), + "z"=>OptionsDict("ngrid"=>z_ngrid, "nelement"=>z_nelement_global, + "nelement_local"=>z_nelement_local, "L"=>z_L, + "discretization"=>discretization, "cheb_option"=>cheb_option, + "bc"=>z_bc, "element_spacing_option"=>element_spacing_option), + "vperp"=>OptionsDict("ngrid"=>vperp_ngrid, "nelement"=>vperp_nelement_global, + "nelement_local"=>vperp_nelement_local, "L"=>vperp_L, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>vperp_bc, + "element_spacing_option"=>element_spacing_option), + "vpa"=>OptionsDict("ngrid"=>vpa_ngrid, "nelement"=>vpa_nelement_global, + "nelement_local"=>vpa_nelement_local, "L"=>vpa_L, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>vpa_bc, + "element_spacing_option"=>element_spacing_option), + "gyrophase"=>OptionsDict("ngrid"=>gyrophase_ngrid, + "nelement"=>gyrophase_nelement_global, + "nelement_local"=>gyrophase_nelement_local, + "L"=>gyrophase_L, "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>gyrophase_bc, + "element_spacing_option"=>element_spacing_option), + ) # create the coordinate structs - r, r_spectral = define_coordinate(r_input, nothing; collision_operator_dim=false, run_directory=test_output_directory) - z, z_spectral = define_coordinate(z_input, nothing; collision_operator_dim=false, run_directory=test_output_directory) - vperp, vperp_spectral = define_coordinate(vperp_input, nothing; collision_operator_dim=false, run_directory=test_output_directory) - vpa, vpa_spectral = define_coordinate(vpa_input, nothing; collision_operator_dim=false, run_directory=test_output_directory) - gyrophase, gyrophase_spectral = define_coordinate(gyrophase_input, nothing; collision_operator_dim=false, run_directory=test_output_directory) + r, r_spectral = define_coordinate(coords_input, "r"; collision_operator_dim=false, + run_directory=test_output_directory, + irank=irank_r, nrank=nrank_r, comm=comm_sub_r) + z, z_spectral = define_coordinate(coords_input, "z"; collision_operator_dim=false, + run_directory=test_output_directory, + irank=irank_z, nrank=nrank_z, comm=comm_sub_z) + vperp, vperp_spectral = define_coordinate(coords_input, "vperp"; + collision_operator_dim=false, + run_directory=test_output_directory) + vpa, vpa_spectral = define_coordinate(coords_input, "vpa"; + collision_operator_dim=false, + run_directory=test_output_directory) + gyrophase, gyrophase_spectral = define_coordinate(coords_input, "gyrophase"; + collision_operator_dim=false, + run_directory=test_output_directory) # create test geometry option = "constant-helical" - inputdict = Dict("geometry" => Dict("option" => option, "rhostar" => rhostar, "pitch" => pitch)) + inputdict = OptionsDict("geometry" => OptionsDict("option" => option, "rhostar" => rhostar, "pitch" => pitch)) geometry_in = setup_geometry_input(inputdict) geometry = init_magnetic_geometry(geometry_in,z,r) diff --git a/moment_kinetics/test/harrisonthompson.jl b/moment_kinetics/test/harrisonthompson.jl index 0945f72e2..990db4c9d 100644 --- a/moment_kinetics/test/harrisonthompson.jl +++ b/moment_kinetics/test/harrisonthompson.jl @@ -11,8 +11,7 @@ using SpecialFunctions: dawson using moment_kinetics.load_data: open_readonly_output_file using moment_kinetics.load_data: load_fields_data, load_time_data using moment_kinetics.load_data: load_species_data, load_coordinate_data -using moment_kinetics.input_structs: merge_dict_with_kwargs! -using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: merge_dict_with_kwargs! ionization_frequency = 0.688 @@ -84,68 +83,71 @@ test_input_finite_difference = Dict("composition" => OptionsDict("n_ion_species" "upar_phase" => 0.0, "temperature_amplitude" => 0.0, "temperature_phase" => 0.0), - "run_name" => "finite_difference", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, - "charge_exchange_frequency" => 0.0, - "ionization_frequency" => 0.0, - "constant_ionization_rate" => true, + "output" => OptionsDict("run_name" => "finite_difference"), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.0, + "ionization_frequency" => 0.0), "timestepping" => OptionsDict("nstep" => 9000, "dt" => 0.0005, "nwrite" => 9000, "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "finite_difference", - "z_ngrid" => 100, - "z_nelement" => 1, - "z_bc" => "wall", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 200, - "vpa_nelement" => 1, - "vpa_L" => 8.0, - "vpa_bc" => "zero", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 200, - "vz_nelement" => 1, - "vz_L" => 8.0, - "vz_bc" => "zero", - "vz_discretization" => "finite_difference", - "ion_source" => Dict("active" => true, - "source_strength" => ionization_frequency, - "source_T" => 0.25, - "z_profile" => "constant", - "r_profile" => "constant"), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "z" => OptionsDict("ngrid" => 100, + "nelement" => 1, + "bc" => "wall", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 200, + "nelement" => 1, + "L" => 8.0, + "bc" => "zero", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 200, + "nelement" => 1, + "L" => 8.0, + "bc" => "zero", + "discretization" => "finite_difference"), + "ion_source_1" => OptionsDict("active" => true, + "source_strength" => ionization_frequency, + "source_T" => 0.25, + "z_profile" => "constant", + "r_profile" => "constant"), ) -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 2, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 10, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 10)) - -test_input_chebyshev_split1 = merge(test_input_chebyshev, - Dict("run_name" => "chebyshev_pseudospectral_split1", - "evolve_moments_density" => true, - "evolve_moments_conservation" => true)) - -test_input_chebyshev_split2 = merge(test_input_chebyshev_split1, - Dict("run_name" => "chebyshev_pseudospectral_split2", - "evolve_moments_parallel_flow" => true, - "ion_numerical_dissipation" => Dict("force_minimum_pdf_value" => 0.0))) - -test_input_chebyshev_split3 = merge(test_input_chebyshev_split2, - Dict("run_name" => "chebyshev_pseudospectral_split3", - "evolve_moments_parallel_pressure" => true)) +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 2), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + )) + +test_input_chebyshev_split1 = recursive_merge(test_input_chebyshev, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split1"), + "evolve_moments" => OptionsDict("density" => true, + "moments_conservation" => true), + )) + +test_input_chebyshev_split2 = recursive_merge(test_input_chebyshev_split1, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split2"), + "evolve_moments" => OptionsDict("parallel_flow" => true), + "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0), + )) + +test_input_chebyshev_split3 = recursive_merge(test_input_chebyshev_split2, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split3"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + )) """ Run a test for a single set of parameters @@ -161,7 +163,7 @@ function run_test(test_input, analytic_rtol, analytic_atol, expected_phi, input = deepcopy(test_input) # Convert keyword arguments to a unique name - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -174,7 +176,7 @@ function run_test(test_input, analytic_rtol, analytic_atol, expected_phi, # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running phi = nothing @@ -191,7 +193,7 @@ function run_test(test_input, analytic_rtol, analytic_atol, expected_phi, # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name, name) + path = joinpath(realpath(input["output"]["base_directory"]), name, name) # open the netcdf file and give it the handle 'fid' fid = open_readonly_output_file(path,"moments") @@ -237,12 +239,12 @@ function runtests() println("Harrison-Thompson wall boundary condition tests") @testset_skip "FD version forms discontinuity in vpa at z=±L/2" "finite difference" begin - test_input_finite_difference["base_directory"] = test_output_directory + test_input_finite_difference["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference, 1.e-3, 1.e-4, zeros(100), 1.e-14, 1.e-15) end @testset "Chebyshev" begin - test_input_chebyshev["base_directory"] = test_output_directory + test_input_chebyshev["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev, 3.e-2, 3.e-3, [-0.8270506736528097, -0.6647482045160528, -0.43595102198197894, -0.2930090302314022, -0.19789542449264944, -0.14560099229503182, @@ -252,7 +254,7 @@ function runtests() -0.6647482045160534, -0.8270506736528144], 5.0e-9, 1.e-15) end @testset "Chebyshev split 1" begin - test_input_chebyshev_split1["base_directory"] = test_output_directory + test_input_chebyshev_split1["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split1, 3.e-2, 3.e-3, [-0.8089566460734486, -0.6619131832543634, -0.43082918688434424, -0.29582033972847016, -0.1934419000612522, -0.14925142084423915, @@ -262,7 +264,7 @@ function runtests() -0.6619131832543697, -0.808956646073445], 5.0e-9, 1.e-15) end @testset "Chebyshev split 2" begin - test_input_chebyshev_split2["base_directory"] = test_output_directory + test_input_chebyshev_split2["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split2, 6.e-2, 3.e-3, [-0.7798736739831602, -0.661568214314525, -0.409872886370737, -0.24444487132869974, -0.17244646306807737, -0.11761557291772232, @@ -274,7 +276,7 @@ function runtests() # The 'split 3' test is pretty badly resolved, but don't want to increase # run-time! @testset "Chebyshev split 3" begin - test_input_chebyshev_split3["base_directory"] = test_output_directory + test_input_chebyshev_split3["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split3, 2.5e-1, 3.e-3, [-0.5012994554414933, -0.4624277373138882, -0.35356695432752266, -0.22371207174875177, -0.14096934539193717, -0.10082423314545275, diff --git a/moment_kinetics/test/interpolation_tests.jl b/moment_kinetics/test/interpolation_tests.jl index 6b185e141..a38506a2f 100644 --- a/moment_kinetics/test/interpolation_tests.jl +++ b/moment_kinetics/test/interpolation_tests.jl @@ -2,8 +2,7 @@ module InterpolationTests include("setup.jl") -using moment_kinetics.input_structs: grid_input, advection_input -using moment_kinetics.coordinates: define_coordinate +using moment_kinetics.coordinates: define_test_coordinate using moment_kinetics.interpolation: interpolate_to_grid_1d, interpolate_to_grid_z, interpolate_to_grid_vpa @@ -20,9 +19,6 @@ println("interpolation tests") ngrid = 33 L = 6.0 bc = "periodic" -# fd_option and adv_input not actually used so given values unimportant -fd_option = "" -adv_input = advection_input("default", 1.0, 0.0, 0.0) function runtests() @testset "interpolation" verbose=use_verbose begin @@ -35,20 +31,17 @@ function runtests() ntest ∈ (3, 14), nelement ∈ (2, 8), zlim ∈ (L/2.0, L/5.0) # create the 'input' struct containing input info needed to create a coordinate - nelement_local = nelement - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value + nelement_local = nelement cheb_option = "FFT" - #element_spacing_option = "uniform" - input = grid_input("coord", ngrid, nelement, - nelement_local, nrank_per_block, irank, L, - discretization, fd_option, cheb_option, bc, adv_input, comm, - element_spacing_option) + input = OptionsDict("name"=>"coord", "ngrid"=>ngrid, "nelement"=>nelement, + "L"=>L, "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>element_spacing_option) # create the coordinate struct 'z' # This test runs effectively in serial, so use `ignore_MPI=true` to avoid # errors due to communicators not being fully set up. - z, spectral = define_coordinate(input, nothing; ignore_MPI=true, collision_operator_dim=false) + z, spectral = define_test_coordinate(input; ignore_MPI=true, + collision_operator_dim=false) test_grid = [z for z in range(-zlim, zlim, length=ntest)] diff --git a/moment_kinetics/test/nonlinear_solver_tests.jl b/moment_kinetics/test/nonlinear_solver_tests.jl index f15b5cf34..29fe633c5 100644 --- a/moment_kinetics/test/nonlinear_solver_tests.jl +++ b/moment_kinetics/test/nonlinear_solver_tests.jl @@ -9,7 +9,7 @@ using moment_kinetics.input_structs: advection_input using moment_kinetics.looping using moment_kinetics.looping: setup_loop_ranges! using moment_kinetics.nonlinear_solvers -using moment_kinetics.type_definitions: mk_float, mk_int, OptionsDict +using moment_kinetics.type_definitions: mk_float, mk_int using MPI @@ -113,11 +113,12 @@ function linear_test() end nl_solver_params = setup_nonlinear_solve( + true, OptionsDict("nonlinear_solver" => - OptionsDict("rtol" => 0.0, - "atol" => atol, - "linear_restart" => restart, - "linear_max_restarts" => max_restarts)), + OptionsDict("rtol" => 0.0, + "atol" => atol, + "linear_restart" => restart, + "linear_max_restarts" => max_restarts)), coords; serial_solve=serial_solve) newton_solve!(x, rhs_func!, residual, delta_x, rhs_delta, v, w, nl_solver_params; @@ -245,12 +246,13 @@ function nonlinear_test() end nl_solver_params = setup_nonlinear_solve( + true, OptionsDict("nonlinear_solver" => - OptionsDict("rtol" => 0.0, - "atol" => atol, - "linear_restart" => restart, - "linear_max_restarts" => max_restarts, - "nonlinear_max_iterations" => 100)), + OptionsDict("rtol" => 0.0, + "atol" => atol, + "linear_restart" => restart, + "linear_max_restarts" => max_restarts, + "nonlinear_max_iterations" => 100)), coords; serial_solve=serial_solve) newton_solve!(x, rhs_func!, residual, delta_x, rhs_delta, v, w, nl_solver_params; diff --git a/moment_kinetics/test/nonlinear_sound_wave_inputs_and_expected_data.jl b/moment_kinetics/test/nonlinear_sound_wave_inputs_and_expected_data.jl index 031591e51..2a5736037 100644 --- a/moment_kinetics/test/nonlinear_sound_wave_inputs_and_expected_data.jl +++ b/moment_kinetics/test/nonlinear_sound_wave_inputs_and_expected_data.jl @@ -82,106 +82,110 @@ const expected = 0.024285034070612672 0.01001177872485688 0.00842420216637052 0.019283695804388705 0.03672486160719087 0.04165072188572364 0.0369234055803037 0.036374533667106045 0.041904838760501203 0.040712367539469434 0.02428503407061266]) # default inputs for tests -test_input_finite_difference = Dict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0), - "ion_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.5, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.5, - "temperature_phase" => mk_float(π)), - "neutral_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.5, - "density_phase" => mk_float(π), - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.5, - "temperature_phase" => 0.0), - "run_name" => "finite_difference", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "charge_exchange_frequency" => 2*π*0.1, - "ionization_frequency" => 0.0, - "timestepping" => OptionsDict("nstep" => 100, - "dt" => 0.001, - "nwrite" => 100, - "nwrite_dfns" => 100, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "finite_difference", - "z_ngrid" => 100, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 400, - "vpa_nelement" => 1, - "vpa_L" => vpa_L, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 400, - "vz_nelement" => 1, - "vz_L" => vpa_L, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference") +test_input_finite_difference = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => mk_float(π)), + "neutral_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => mk_float(π), + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => 0.0), + "output" => OptionsDict("run_name" => "finite_difference"), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*π*0.1, + "ionization_frequency" => 0.0), + "timestepping" => OptionsDict("nstep" => 100, + "dt" => 0.001, + "nwrite" => 100, + "nwrite_dfns" => 100, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "z" => OptionsDict("ngrid" => 100, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 400, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 400, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + ) test_input_finite_difference_split_1_moment = - merge(test_input_finite_difference, - Dict("run_name" => "finite_difference_split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_finite_difference_split_2_moments = - merge(test_input_finite_difference_split_1_moment, - Dict("run_name" => "finite_difference_split_2_moments", - "evolve_moments_parallel_flow" => true)) + recursive_merge(test_input_finite_difference_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_finite_difference_split_3_moments = - merge(test_input_finite_difference_split_2_moments, - Dict("run_name" => "finite_difference_split_3_moments", - "evolve_moments_parallel_pressure" => true, - "vpa_L" => 12.0, "vz_L" => 12.0)) + recursive_merge(test_input_finite_difference_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("L" => 12.0), + "vz" => OptionsDict("L" => 12.0), + )) -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 4, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 8, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 8)) +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 4), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 8), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 8)), + ) if global_size[] > 2 && global_size[] % 2 == 0 # Test using distributed-memory - test_input_chebyshev["z_nelement_local"] = test_input_chebyshev["z_nelement"] ÷ 2 + test_input_chebyshev["z"]["nelement_local"] = test_input_chebyshev["z"]["nelement"] ÷ 2 end test_input_chebyshev_split_1_moment = - merge(test_input_chebyshev, - Dict("run_name" => "chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(test_input_chebyshev, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_split_2_moments = - merge(test_input_chebyshev_split_1_moment, - Dict("run_name" => "chebyshev_pseudospectral_split_2_moments", - "evolve_moments_parallel_flow" => true)) + recursive_merge(test_input_chebyshev_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_split_3_moments = - merge(test_input_chebyshev_split_2_moments, - Dict("run_name" => "chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true, - "vpa_L" => 12.0, "vz_L" => 12.0)) - - + recursive_merge(test_input_chebyshev_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("L" => 12.0), + "vz" => OptionsDict("L" => 12.0), + )) diff --git a/moment_kinetics/test/nonlinear_sound_wave_tests.jl b/moment_kinetics/test/nonlinear_sound_wave_tests.jl index 7da52ab70..6540162f0 100644 --- a/moment_kinetics/test/nonlinear_sound_wave_tests.jl +++ b/moment_kinetics/test/nonlinear_sound_wave_tests.jl @@ -4,12 +4,11 @@ include("setup.jl") using Base.Filesystem: tempname -using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.interpolation: interpolate_to_grid_z, interpolate_to_grid_vpa using moment_kinetics.load_data: get_run_info_no_setup, close_run_info, postproc_load_variable -using moment_kinetics.type_definitions: mk_float, OptionsDict +using moment_kinetics.type_definitions: mk_float +using moment_kinetics.utils: merge_dict_with_kwargs! const analytical_rtol = 3.e-2 const regression_rtol = 2.e-8 @@ -33,7 +32,7 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) end # Convert keyword arguments to a unique name - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -46,7 +45,7 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running quietoutput() do @@ -72,7 +71,7 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name) + path = joinpath(realpath(input["output"]["base_directory"]), name) # open the output file(s) run_info = get_run_info_no_setup(path; dfns=true) @@ -125,7 +124,7 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) f_neutral = f_neutral_vzvrvzetazrst[:,1,1,:,1,:,:] # Unnormalize f - if input["evolve_moments_density"] + if input["evolve_moments"]["density"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] .*= n_ion[iz,is,it] end @@ -133,7 +132,7 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) f_neutral[:,iz,isn,it] .*= n_neutral[iz,isn,it] end end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] ./= v_t_ion[iz,is,it] end @@ -227,10 +226,10 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) size(newgrid_f_ion, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_ion[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_ion[iz,1] end newgrid_f_ion[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vpa, vpa_spectral) @@ -258,10 +257,10 @@ function run_test(test_input, rtol, atol, upar_rtol=nothing; args...) size(newgrid_f_neutral, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_neutral[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_neutral[iz,1] end newgrid_f_neutral[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vpa, vpa_spectral) @@ -288,38 +287,38 @@ function runtests() # finite difference @testset "FD base" begin - test_input_finite_difference["base_directory"] = test_output_directory + test_input_finite_difference["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference, 1.e-3, 1.e-11, 2.e-3) end @testset "FD split 1" begin - test_input_finite_difference_split_1_moment["base_directory"] = test_output_directory + test_input_finite_difference_split_1_moment["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference_split_1_moment, 1.e-3, 1.e-11) end @testset "FD split 2" begin - test_input_finite_difference_split_2_moments["base_directory"] = test_output_directory + test_input_finite_difference_split_2_moments["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference_split_2_moments, 1.e-3, 1.e-11) end @testset "FD split 3" begin - test_input_finite_difference_split_3_moments["base_directory"] = test_output_directory + test_input_finite_difference_split_3_moments["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference_split_3_moments, 1.e-3, 1.e-11) end # Chebyshev pseudospectral # Benchmark data is taken from this run (Chebyshev with no splitting) @testset "Chebyshev base" begin - test_input_chebyshev["base_directory"] = test_output_directory + test_input_chebyshev["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev, 1.e-10, 3.e-16) end @testset "Chebyshev split 1" begin - test_input_chebyshev_split_1_moment["base_directory"] = test_output_directory + test_input_chebyshev_split_1_moment["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split_1_moment, 1.e-3, 1.e-15) end @testset "Chebyshev split 2" begin - test_input_chebyshev_split_2_moments["base_directory"] = test_output_directory + test_input_chebyshev_split_2_moments["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split_2_moments, 1.e-3, 1.e-15) end @testset "Chebyshev split 3" begin - test_input_chebyshev_split_3_moments["base_directory"] = test_output_directory + test_input_chebyshev_split_3_moments["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_split_3_moments, 1.e-3, 1.e-15) end end diff --git a/moment_kinetics/test/recycling_fraction_tests.jl b/moment_kinetics/test/recycling_fraction_tests.jl index deb5a178c..04d289637 100644 --- a/moment_kinetics/test/recycling_fraction_tests.jl +++ b/moment_kinetics/test/recycling_fraction_tests.jl @@ -9,163 +9,165 @@ include("setup.jl") using Base.Filesystem: tempname using MPI -using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.interpolation: interpolate_to_grid_z using moment_kinetics.load_data: get_run_info_no_setup, close_run_info, postproc_load_variable -using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: merge_dict_with_kwargs! # default inputs for tests -test_input = Dict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 0.2, - "T_wall" => 0.1, - "recycling_fraction" => 0.5), - "ion_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.0, - "density_phase" => 0.0, - "upar_amplitude" => 1.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "neutral_species_1" => OptionsDict("initial_density" => 1.0, +test_input = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 0.2, + "T_wall" => 0.1, + "recycling_fraction" => 0.5), + "ion_species_1" => OptionsDict("initial_density" => 1.0, "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.001, + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.0, "density_phase" => 0.0, - "upar_amplitude" => -1.0, + "upar_amplitude" => 1.0, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "run_name" => "full-f", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, - "charge_exchange_frequency" => 0.75, - "ionization_frequency" => 0.5, - "constant_ionization_rate" => false, - "timestepping" => OptionsDict("nstep" => 1000, - "dt" => 1.0e-4, - "nwrite" => 1000, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 9, - "z_nelement" => 8, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "z_element_spacing_option" => "sqrt", - "vpa_ngrid" => 10, - "vpa_nelement" => 15, - "vpa_L" => 18.0, - "vpa_bc" => "zero", - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_element_spacing_option" => "coarse_tails", - "vz_ngrid" => 10, - "vz_nelement" => 15, - "vz_L" => 18.0, - "vz_bc" => "zero", - "vz_discretization" => "chebyshev_pseudospectral", - "vz_element_spacing_option" => "coarse_tails", - "ion_source" => Dict("active" => true, - "z_profile" => "gaussian", - "z_width" => 0.125, - "source_strength" => 2.0, - "source_T" => 2.0)) + "temperature_phase" => 0.0), + "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "neutral_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => -1.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "vz_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "output" => OptionsDict("run_name" => "full-f"), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), + "reactions" => OptionsDict("charge_exchange_frequency" => 0.75, + "ionization_frequency" => 0.5), + "timestepping" => OptionsDict("nstep" => 1000, + "dt" => 1.0e-4, + "nwrite" => 1000, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 9, + "nelement" => 8, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral", + "element_spacing_option" => "sqrt"), + "vpa" => OptionsDict("ngrid" => 10, + "nelement" => 15, + "L" => 18.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral", + "element_spacing_option" => "coarse_tails"), + "vz" => OptionsDict("ngrid" => 10, + "nelement" => 15, + "L" => 18.0, + "bc" => "zero", + "discretization" => "chebyshev_pseudospectral", + "element_spacing_option" => "coarse_tails"), + "ion_source_1" => OptionsDict("active" => true, + "z_profile" => "gaussian", + "z_width" => 0.125, + "source_strength" => 2.0, + "source_T" => 2.0), + ) if global_size[] > 2 && global_size[] % 2 == 0 # Test using distributed-memory - test_input["z_nelement_local"] = test_input["z_nelement"] ÷ 2 + test_input["z"]["nelement_local"] = test_input["z"]["nelement"] ÷ 2 end -test_input_split1 = merge(test_input, - Dict("run_name" => "split1", - "evolve_moments_density" => true, - "evolve_moments_conservation" => true)) -test_input_split2 = merge(test_input_split1, - Dict("run_name" => "split2", - "evolve_moments_parallel_flow" => true)) -test_input_split3 = merge(test_input_split2, - Dict("run_name" => "split3", - "z_nelement" => 16, - "vpa_nelement" => 31, - "vz_nelement" => 31, - "evolve_moments_parallel_pressure" => true, - "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, "vpa_dissipation_coefficient" => 1e-2), - "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, "vz_dissipation_coefficient" => 1e-2))) -test_input_split3["timestepping"] = merge(test_input_split3["timestepping"], - Dict("dt" => 1.0e-5, - "write_error_diagnostics" => true, - "write_steady_state_diagnostics" => true)) +test_input_split1 = recursive_merge(test_input, + OptionsDict("output" => OptionsDict("run_name" => "split1"), + "evolve_moments" => OptionsDict("density" => true, + "moments_conservation" => true))) +test_input_split2 = recursive_merge(test_input_split1, + OptionsDict("output" => OptionsDict("run_name" => "split2"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) +test_input_split3 = recursive_merge(test_input_split2, + OptionsDict("output" => OptionsDict("run_name" => "split3"), + "z" => OptionsDict("nelement" => 16), + "vpa" => OptionsDict("nelement" => 31), + "vz" => OptionsDict("nelement" => 31), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, "vpa_dissipation_coefficient" => 1e-2), + "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, "vz_dissipation_coefficient" => 1e-2))) +test_input_split3["timestepping"] = recursive_merge(test_input_split3["timestepping"], + OptionsDict("dt" => 1.0e-5, + "write_error_diagnostics" => true, + "write_steady_state_diagnostics" => true)) # default inputs for adaptive timestepping tests -test_input_adaptive = merge(test_input, - OptionsDict("run_name" => "adaptive full-f", - "z_ngrid" => 5, - "z_nelement" => 16, - "vpa_ngrid" => 6, - "vpa_nelement" => 31, - "vz_ngrid" => 6, - "vz_nelement" => 31)) +test_input_adaptive = recursive_merge(test_input, + OptionsDict("output" => OptionsDict("run_name" => "adaptive full-f"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 16), + "vpa" => OptionsDict("ngrid" => 6, + "nelement" => 31), + "vz" => OptionsDict("ngrid" => 6, + "nelement" => 31)), + ) # Note, use excessively conservative timestepping settings here, because # we want to avoid any timestep failures in the test. If failures # occur, the number or when exactly they occur could depend on the # round-off error, which could make the results less reproducible (even # though the difference should be negligible compared to the # discretization error of the simulation). -test_input_adaptive["timestepping"] = merge(test_input_adaptive["timestepping"], - OptionsDict("type" => "Fekete4(3)", - "nstep" => 5000, - "dt" => 1.0e-5, - "minimum_dt" => 1.0e-5, - "CFL_prefactor" => 1.0, - "step_update_prefactor" => 0.5, - "nwrite" => 1000, - "split_operators" => false)) - -test_input_adaptive_split1 = merge(test_input_adaptive, - Dict("run_name" => "adaptive split1", - "evolve_moments_density" => true, - "evolve_moments_conservation" => true)) -test_input_adaptive_split2 = merge(test_input_adaptive_split1, - Dict("run_name" => "adaptive split2", - "evolve_moments_parallel_flow" => true)) -test_input_adaptive_split2["timestepping"] = merge(test_input_adaptive_split2["timestepping"], - OptionsDict("step_update_prefactor" => 0.4)) -test_input_adaptive_split3 = merge(test_input_adaptive_split2, - Dict("run_name" => "adaptive split3", - "evolve_moments_parallel_pressure" => true, - "numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, - "vpa_dissipation_coefficient" => 1e-2))) +test_input_adaptive["timestepping"] = recursive_merge(test_input_adaptive["timestepping"], + OptionsDict("type" => "Fekete4(3)", + "nstep" => 5000, + "dt" => 1.0e-5, + "minimum_dt" => 1.0e-5, + "CFL_prefactor" => 1.0, + "step_update_prefactor" => 0.5, + "nwrite" => 1000, + "split_operators" => false), + ) + +test_input_adaptive_split1 = recursive_merge(test_input_adaptive, + OptionsDict("output" => OptionsDict("run_name" => "adaptive split1"), + "evolve_moments" => OptionsDict("density" => true, + "moments_conservation" => true))) +test_input_adaptive_split2 = recursive_merge(test_input_adaptive_split1, + OptionsDict("output" => OptionsDict("run_name" => "adaptive split2"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) +test_input_adaptive_split2["timestepping"] = recursive_merge(test_input_adaptive_split2["timestepping"], + OptionsDict("step_update_prefactor" => 0.4)) +test_input_adaptive_split3 = recursive_merge(test_input_adaptive_split2, + OptionsDict("output" => OptionsDict("run_name" => "adaptive split3"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "ion_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vpa_dissipation_coefficient" => 1e-2), + "neutral_numerical_dissipation" => OptionsDict("force_minimum_pdf_value" => 0.0, + "vz_dissipation_coefficient" => 1e-2))) # The initial conditions seem to make the split3 case hard to advance without any # failures. In a real simulation, would just set the minimum_dt higher to try to get # through this without crashing. For this test, want the timestep to adapt (not just sit # at minimum_dt), so just set a very small timestep. -test_input_adaptive_split3["timestepping"] = merge(test_input_adaptive_split3["timestepping"], - OptionsDict("dt" => 1.0e-7, - "rtol" => 2.0e-4, - "atol" => 2.0e-10, - "minimum_dt" => 1.0e-7, - "step_update_prefactor" => 0.064)) +test_input_adaptive_split3["timestepping"] = recursive_merge(test_input_adaptive_split3["timestepping"], + OptionsDict("dt" => 1.0e-7, + "rtol" => 2.0e-4, + "atol" => 2.0e-10, + "minimum_dt" => 1.0e-7, + "step_update_prefactor" => 0.064)) """ Run a test for a single set of parameters @@ -179,7 +181,7 @@ function run_test(test_input, expected_phi; rtol=4.e-14, atol=1.e-15, args...) input = deepcopy(test_input) # Convert keyword arguments to a unique name - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -192,7 +194,7 @@ function run_test(test_input, expected_phi; rtol=4.e-14, atol=1.e-15, args...) # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running phi = undef @@ -206,7 +208,7 @@ function run_test(test_input, expected_phi; rtol=4.e-14, atol=1.e-15, args...) # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name) + path = joinpath(realpath(input["output"]["base_directory"]), name) # open the output file(s) run_info = get_run_info_no_setup(path) @@ -239,7 +241,7 @@ function runtests() println("Recycling fraction tests") @long @testset "Full-f" begin - test_input["base_directory"] = test_output_directory + test_input["output"]["base_directory"] = test_output_directory run_test(test_input, [-0.0546579889285807, -0.019016549127873168, -0.0014860800466385304, 0.0009959205072609873, 0.0018297472055798175, 0.001071042733974246, @@ -251,7 +253,7 @@ function runtests() -0.04842263416979855]) end @long @testset "Split 1" begin - test_input_split1["base_directory"] = test_output_directory + test_input_split1["output"]["base_directory"] = test_output_directory run_test(test_input_split1, [-0.054564400690150644, -0.01880050885497155, -0.0013804889155909434, 0.0009426267362423344, 0.0018708794999890794, 0.0010048035580616115, @@ -263,7 +265,7 @@ function runtests() -0.04820698953610652]) end @long @testset "Split 2" begin - test_input_split2["base_directory"] = test_output_directory + test_input_split2["output"]["base_directory"] = test_output_directory run_test(test_input_split2, [-0.055351930552923125, -0.0200209368236471, -0.0010274232338285407, 0.0011445828881595096, 0.001990016623266284, 0.0011847791295251302, @@ -275,7 +277,7 @@ function runtests() -0.04714624635817171]) end @long @testset "Split 3" begin - test_input_split3["base_directory"] = test_output_directory + test_input_split3["output"]["base_directory"] = test_output_directory run_test(test_input_split3, [-0.036195418620494954, -0.030489030308458488, -0.028975057418733397, -0.02856021807109163, -0.025513413807863268, -0.0219696963676536, @@ -306,12 +308,12 @@ function runtests() -0.00942148866222427, -0.011607485576226423, -0.020871221194795328, -0.03762871759968933] @testset "Adaptive timestep - full-f" begin - test_input_adaptive["base_directory"] = test_output_directory + test_input_adaptive["output"]["base_directory"] = test_output_directory run_test(test_input_adaptive, fullf_expected_output, rtol=6.0e-4, atol=2.0e-12) end @testset "Adaptive timestep - split 1" begin - test_input_adaptive_split1["base_directory"] = test_output_directory + test_input_adaptive_split1["output"]["base_directory"] = test_output_directory run_test(test_input_adaptive_split1, [-0.04375862714017892, -0.022363510973059945, -0.012739964397542611, -0.010806509398868007, -0.007052551067569563, @@ -324,7 +326,7 @@ function runtests() atol=2.0e-12) end @testset "Adaptive timestep - split 2" begin - test_input_adaptive_split2["base_directory"] = test_output_directory + test_input_adaptive_split2["output"]["base_directory"] = test_output_directory run_test(test_input_adaptive_split2, [-0.0440004026002034, -0.022740771274011903, -0.012908307424861458, -0.010957840207013755, -0.007098397545728348, @@ -337,7 +339,7 @@ function runtests() -0.03785398593006839], rtol=6.0e-4, atol=2.0e-12) end @testset "Adaptive timestep - split 3" begin - test_input_adaptive_split3["base_directory"] = test_output_directory + test_input_adaptive_split3["output"]["base_directory"] = test_output_directory run_test(test_input_adaptive_split3, [-0.034623352735472034, -0.03200541773193755, -0.02714032291656093, -0.020924986472905527, -0.01015057042512689, 0.0027893133203071574, @@ -354,8 +356,8 @@ function runtests() "SSPRK2", "SSPRK1") timestep_check_input = deepcopy(test_input_adaptive) - timestep_check_input["base_directory"] = test_output_directory - timestep_check_input["run_name"] = type + timestep_check_input["output"]["base_directory"] = test_output_directory + timestep_check_input["output"]["run_name"] = type timestep_check_input["timestepping"]["type"] = type run_test(timestep_check_input, fullf_expected_output, rtol=8.e-4, atol=1.e-10) diff --git a/moment_kinetics/test/restart_interpolation_tests.jl b/moment_kinetics/test/restart_interpolation_tests.jl index ca6a166ba..936040e28 100644 --- a/moment_kinetics/test/restart_interpolation_tests.jl +++ b/moment_kinetics/test/restart_interpolation_tests.jl @@ -7,9 +7,8 @@ include("setup.jl") using Base.Filesystem: tempname using moment_kinetics.communication -using moment_kinetics.coordinates: define_coordinate using moment_kinetics.file_io: io_has_parallel -using moment_kinetics.input_structs: grid_input, advection_input, hdf5, merge_dict_with_kwargs! +using moment_kinetics.input_structs: hdf5 using moment_kinetics.load_data: open_readonly_output_file, load_coordinate_data, load_species_data, load_fields_data, load_ion_moments_data, load_pdf_data, @@ -18,7 +17,8 @@ using moment_kinetics.load_data: open_readonly_output_file, load_coordinate_data using moment_kinetics.interpolation: interpolate_to_grid_z, interpolate_to_grid_vpa using moment_kinetics.load_data: get_run_info_no_setup, close_run_info, postproc_load_variable -using moment_kinetics.type_definitions: mk_float, OptionsDict +using moment_kinetics.type_definitions: mk_float +using moment_kinetics.utils: merge_dict_with_kwargs! include("nonlinear_sound_wave_inputs_and_expected_data.jl") @@ -28,39 +28,43 @@ base_input["timestepping"]["nwrite"] = 50 base_input["timestepping"]["nwrite_dfns"] = 50 if global_size[] > 1 && global_size[] % 2 == 0 # Test using distributed-memory - base_input["z_nelement_local"] = base_input["z_nelement"] ÷ 2 + base_input["z"]["nelement_local"] = base_input["z"]["nelement"] ÷ 2 end -base_input["output"] = OptionsDict("parallel_io" => false) +base_input["output"]["parallel_io"] = false restart_test_input_chebyshev = - merge(deepcopy(base_input), - OptionsDict("run_name" => "restart_chebyshev_pseudospectral", - "r_ngrid" => 3, "r_nelement" => 2, - "r_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 17, "z_nelement" => 2, - "vpa_ngrid" => 9, "vpa_nelement" => 32, - "vz_ngrid" => 9, "vz_nelement" => 32)) +recursive_merge(deepcopy(base_input), + OptionsDict("output" => OptionsDict("run_name" => "restart_chebyshev_pseudospectral"), + "r" => OptionsDict("ngrid" => 3, "nelement" => 2, + "discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("ngrid" => 17, "nelement" => 2), + "vpa" => OptionsDict("ngrid" => 9, "nelement" => 32), + "vz" => OptionsDict("ngrid" => 9, "nelement" => 32)), + ) if global_size[] > 1 && global_size[] % 2 == 0 # Test using distributed-memory - restart_test_input_chebyshev["z_nelement_local"] = restart_test_input_chebyshev["z_nelement"] ÷ 2 + restart_test_input_chebyshev["z"]["nelement_local"] = restart_test_input_chebyshev["z"]["nelement"] ÷ 2 end restart_test_input_chebyshev_split_1_moment = - merge(deepcopy(restart_test_input_chebyshev), - OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(deepcopy(restart_test_input_chebyshev), + OptionsDict("output" => OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true)), + ) restart_test_input_chebyshev_split_2_moments = - merge(deepcopy(restart_test_input_chebyshev_split_1_moment), - OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_2_moments", - "r_ngrid" => 1, "r_nelement" => 1, - "evolve_moments_parallel_flow" => true)) + recursive_merge(deepcopy(restart_test_input_chebyshev_split_1_moment), + OptionsDict("output" => OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_2_moments"), + "r" => OptionsDict("ngrid" => 1, "nelement" => 1), + "evolve_moments" => OptionsDict("parallel_flow" => true)), + ) restart_test_input_chebyshev_split_3_moments = - merge(deepcopy(restart_test_input_chebyshev_split_2_moments), - OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true, - "vpa_L" => 1.5*vpa_L, "vz_L" => 1.5*vpa_L)) + recursive_merge(deepcopy(restart_test_input_chebyshev_split_2_moments), + OptionsDict("output" => OptionsDict("run_name" => "restart_chebyshev_pseudospectral_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("L" => 1.5*vpa_L), "vz" => OptionsDict("L" => 1.5*vpa_L)), + ) """ Run a sound-wave test for a single set of parameters @@ -88,15 +92,20 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) if isa(value, AbstractDict) return string(string(key)[1], (stringify_arg(k, v) for (k, v) in value)...) else - return string(string(key)[1], value) + if isa(value, AbstractString) + return string(string(key)[1], value[1]) + else + return string(string(key)[1], value) + end end end - name = input["run_name"] + name = input["output"]["run_name"] if length(args) > 0 name = string(name, "_", (stringify_arg(k, v) for (k, v) in args)...) - - # Remove trailing "_" - name = chop(name) + end + # Make sure name is not too long + if length(name) > 80 + name = name[1:80] end if parallel_io name *= "parallel-io" @@ -106,19 +115,19 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) println(" - testing ", message) merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running quietoutput() do # run simulation if parallel_io - restart_filename = joinpath(base["base_directory"], - base["run_name"], - base["run_name"] * ".dfns.h5") + restart_filename = joinpath(base["output"]["base_directory"], + base["output"]["run_name"], + base["output"]["run_name"] * ".dfns.h5") else - restart_filename = joinpath(base["base_directory"], - base["run_name"], - base["run_name"] * ".dfns.0.h5") + restart_filename = joinpath(base["output"]["base_directory"], + base["output"]["run_name"], + base["output"]["run_name"] * ".dfns.0.h5") end run_moment_kinetics(input; restart=restart_filename) end @@ -143,7 +152,7 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) ######################### # Read the output data - path = joinpath(realpath(input["base_directory"]), name) + path = joinpath(realpath(input["output"]["base_directory"]), name) run_info = get_run_info_no_setup((path, -1); dfns=true) z = run_info.z @@ -182,7 +191,7 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) close_run_info(run_info) # Delete output because output files for 3V tests can be large - rm(joinpath(realpath(input["base_directory"]), name); recursive=true) + rm(joinpath(realpath(input["output"]["base_directory"]), name); recursive=true) phi = phi_zrt[:,1,:] n_ion = n_ion_zrst[:,1,:,:] @@ -199,7 +208,7 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) f_neutral = f_neutral_vzvrvzetazrst[:,:,1,:,:] # Unnormalize f - if input["evolve_moments_density"] + if input["evolve_moments"]["density"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] .*= n_ion[iz,is,it] end @@ -207,7 +216,7 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) f_neutral[:,iz,isn,it] .*= n_neutral[iz,isn,it] end end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] for it ∈ 1:length(time), is ∈ 1:n_ion_species, iz ∈ 1:z.n f_ion[:,iz,is,it] ./= v_t_ion[iz,is,it] end @@ -241,10 +250,10 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) size(newgrid_f_ion, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_ion[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_ion[iz,1] end newgrid_f_ion[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vpa, vpa_spectral) @@ -275,10 +284,10 @@ function run_test(test_input, base, message, rtol, atol; tol_3V, args...) size(newgrid_f_neutral, 4)) for iz ∈ 1:length(expected.z) wpa = copy(expected.vpa) - if input["evolve_moments_parallel_flow"] + if input["evolve_moments"]["parallel_flow"] wpa .-= newgrid_upar_neutral[iz,1] end - if input["evolve_moments_parallel_pressure"] + if input["evolve_moments"]["parallel_pressure"] wpa ./= newgrid_vth_neutral[iz,1] end newgrid_f_neutral[:,iz,1] = interpolate_to_grid_vpa(wpa, temp[:,iz,1], vz, vz_spectral) @@ -297,16 +306,22 @@ function runtests() parallel_io = base_input["output"]["parallel_io"] base_input_full_f = deepcopy(base_input) - base_input_full_f["timestepping"] = merge(base_input["timestepping"], - OptionsDict("nstep" => nstep)) - base_input_evolve_density = merge(base_input_full_f, - OptionsDict("evolve_moments_density" => true)) - base_input_evolve_upar = merge(base_input_evolve_density, - OptionsDict("evolve_moments_parallel_flow" => true, - "vpa_L" => 1.5*vpa_L, "vz_L" => 1.5*vpa_L)) - base_input_evolve_ppar = merge(base_input_evolve_upar, - OptionsDict("evolve_moments_parallel_pressure" => true, - "vpa_L" => 1.5*vpa_L, "vz_L" => 1.5*vpa_L)) + base_input_full_f["timestepping"] = recursive_merge(base_input["timestepping"], + OptionsDict("nstep" => nstep), + ) + base_input_evolve_density = recursive_merge(base_input_full_f, + OptionsDict("evolve_moments" => OptionsDict("density" => true)), + ) + base_input_evolve_upar = recursive_merge(base_input_evolve_density, + OptionsDict("evolve_moments" => OptionsDict("parallel_flow" => true), + "vpa" => OptionsDict("L" => 1.5*vpa_L), + "vz" => OptionsDict("L" => 1.5*vpa_L)), + ) + base_input_evolve_ppar = recursive_merge(base_input_evolve_upar, + OptionsDict("evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("L" => 1.5*vpa_L), + "vz" => OptionsDict("L" => 1.5*vpa_L)), + ) for (base, base_label) ∈ ((base_input_full_f, "full-f"), (base_input_evolve_density, "split 1"), @@ -314,7 +329,7 @@ function runtests() (base_input_evolve_ppar, "split 3")) test_output_directory = get_MPI_tempdir() - base["base_directory"] = test_output_directory + base["output"]["base_directory"] = test_output_directory # Base run, from which tests are restarted # Suppress console output while running @@ -330,7 +345,7 @@ function runtests() # simulation) don't test upar. upar and uz end up with large 'errors' # (~50%), and it is not clear why, but ignore this so test can pass. this_input = deepcopy(restart_test_input_chebyshev) - this_input["base_directory"] = test_output_directory + this_input["output"]["base_directory"] = test_output_directory this_input["output"]["parallel_io"] = parallel_io run_test(this_input, base, message, rtol, 1.e-15; tol_3V=tol_3V, args...) end @@ -338,21 +353,21 @@ function runtests() message = "restart split 1 from $base_label$label" @testset "$message" begin this_input = deepcopy(restart_test_input_chebyshev_split_1_moment) - this_input["base_directory"] = test_output_directory + this_input["output"]["base_directory"] = test_output_directory this_input["output"]["parallel_io"] = parallel_io run_test(this_input, base, message, rtol, 1.e-15; tol_3V=tol_3V, args...) end message = "restart split 2 from $base_label$label" @testset "$message" begin this_input = deepcopy(restart_test_input_chebyshev_split_2_moments) - this_input["base_directory"] = test_output_directory + this_input["output"]["base_directory"] = test_output_directory this_input["output"]["parallel_io"] = parallel_io run_test(this_input, base, message, rtol, 1.e-15; tol_3V=tol_3V, args...) end message = "restart split 3 from $base_label$label" @testset "$message" begin this_input = deepcopy(restart_test_input_chebyshev_split_3_moments) - this_input["base_directory"] = test_output_directory + this_input["output"]["base_directory"] = test_output_directory this_input["output"]["parallel_io"] = parallel_io run_test(this_input, base, message, rtol, 1.e-15; tol_3V=tol_3V, args...) end @@ -374,16 +389,20 @@ function runtests() # interpolation used for ion-neutral coupling in 2V/3V case has low accuracy, so # use looser tolerance for various things. @long do_tests(", 2V/3V", 1.0e-1, 98, false; tol_3V=0.3, - timestepping=OptionsDict("nstep" => 2), r_ngrid=1, r_nelement=1, - vperp_ngrid=17, vperp_nelement=4, vperp_L=vpa_L, vpa_ngrid=17, - vpa_nelement=8, vzeta_ngrid=17, vzeta_nelement=4, vzeta_L=vpa_L, - vr_ngrid=17, vr_nelement=4, vr_L=vpa_L, vz_ngrid=17, vz_nelement=8) + timestepping=OptionsDict("nstep" => 2), + r=OptionsDict("ngrid" => 1, "nelement" => 1), + vperp=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L, "ngrid" => 17), + vpa=OptionsDict("nelement" => 8), + vzeta=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L), + vr=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L), + vz=OptionsDict("ngrid" => 17, "nelement" => 8), + ) if io_has_parallel(Val(hdf5)) orig_base_input = deepcopy(base_input) # Also test not using parallel_io base_input["output"]["parallel_io"] = true - base_input["run_name"] *= "_parallel_io" + base_input["output"]["run_name"] *= "_parallel_io" do_tests(", parallel I/O") @@ -391,11 +410,14 @@ function runtests() # interpolation used for ion-neutral coupling in 2V/3V case has low accuracy, # so use looser tolerance for various things. @long do_tests(", 2V/3V, parallel I/O", 2.0e-1, 98, false; tol_3V=0.3, - timestepping=OptionsDict("nstep" => 2), r_ngrid=1, - r_nelement=1, vperp_ngrid=17, vperp_nelement=4, vperp_L=vpa_L, - vpa_ngrid=17, vpa_nelement=8, vzeta_ngrid=17, vzeta_nelement=4, - vzeta_L=vpa_L, vr_ngrid=17, vr_nelement=4, vr_L=vpa_L, - vz_ngrid=17, vz_nelement=8) + timestepping=OptionsDict("nstep" => 2), + r=OptionsDict("ngrid" => 1, "nelement" => 1), + vperp=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L, "ngrid" => 17), + vpa=OptionsDict("nelement" => 8), + vzeta=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L), + vr=OptionsDict("ngrid" => 17, "nelement" => 4, "L" => vpa_L), + vz=OptionsDict("ngrid" => 17, "nelement" => 8), + ) global base_input = orig_base_input end diff --git a/moment_kinetics/test/setup.jl b/moment_kinetics/test/setup.jl index 555824d00..7e9ec9cc8 100644 --- a/moment_kinetics/test/setup.jl +++ b/moment_kinetics/test/setup.jl @@ -13,10 +13,12 @@ using moment_kinetics module MKTestUtilities export use_verbose, force_optional_dependencies, @long, quietoutput, get_MPI_tempdir, - global_rank, global_size, maxabs_norm, @testset_skip + global_rank, global_size, maxabs_norm, @testset_skip, recursive_merge, OptionsDict using moment_kinetics.communication: comm_world, global_rank, global_size using moment_kinetics.command_line_options: get_options +using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge using MPI diff --git a/moment_kinetics/test/sound_wave_tests.jl b/moment_kinetics/test/sound_wave_tests.jl index 7da2ab497..006b18a69 100644 --- a/moment_kinetics/test/sound_wave_tests.jl +++ b/moment_kinetics/test/sound_wave_tests.jl @@ -6,14 +6,14 @@ using Base.Filesystem: tempname #using Plots: plot, plot!, gui using moment_kinetics.array_allocation: allocate_float -using moment_kinetics.input_structs: netcdf, merge_dict_with_kwargs! +using moment_kinetics.input_structs: netcdf using moment_kinetics.file_io: io_has_implementation using moment_kinetics.load_data: open_readonly_output_file using moment_kinetics.load_data: load_fields_data, load_time_data using moment_kinetics.load_data: load_species_data, load_coordinate_data using moment_kinetics.analysis: analyze_fields_data using moment_kinetics.analysis: fit_delta_phi_mode -using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: merge_dict_with_kwargs! const analytical_rtol = 3.e-2 const regression_rtol = 1.e-14 @@ -25,107 +25,113 @@ const binary_format = (force_optional_dependencies || io_has_implementation(netc "netcdf" : "hdf5" # default inputs for tests -test_input_finite_difference = Dict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0), - "ion_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "neutral_species_1" => OptionsDict("initial_density" => 0.5, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", - "density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "run_name" => "finite_difference", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "charge_exchange_frequency" => 2*π*0.1, - "ionization_frequency" => 0.0, - "timestepping" => OptionsDict("nstep" => 1500, - "dt" => 0.002, - "nwrite" => 20, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "finite_difference", - "z_ngrid" => 100, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vperp_L" => 1.0, - "vperp_discretization" => "finite_difference", - "vpa_ngrid" => 180, - "vpa_nelement" => 1, - "vpa_L" => 8.0, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 180, - "vz_nelement" => 1, - "vz_L" => 8.0, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference", - "output" => OptionsDict("binary_format" => binary_format) - ) +test_input_finite_difference = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "neutral_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "output" => OptionsDict("run_name" => "finite_difference", + "binary_format" => binary_format), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*π*0.1, + "ionization_frequency" => 0.0), + "timestepping" => OptionsDict("nstep" => 1500, + "dt" => 0.002, + "nwrite" => 20, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "z" => OptionsDict("ngrid" => 100, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "L" => 1.0, + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 180, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 180, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + ) test_input_finite_difference_split_1_moment = - merge(test_input_finite_difference, - Dict("run_name" => "finite_difference_split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true)) + ) test_input_finite_difference_split_2_moments = - merge(test_input_finite_difference_split_1_moment, - Dict("run_name" => "finite_difference_split_2_moments", - "evolve_moments_parallel_flow" => true, "vpa_ngrid" => 270, "vpa_L" => - 12.0, "vz_ngrid" => 270, "vz_L" => 12.0)) + recursive_merge(test_input_finite_difference_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true), + "vpa" => OptionsDict("ngrid" => 270, "L" => 12.0), + "vz" => OptionsDict("ngrid" => 270, "L" => 12.0)) + ) test_input_finite_difference_split_3_moments = - merge(test_input_finite_difference_split_2_moments, - Dict("run_name" => "finite_difference_split_3_moments", - "evolve_moments_parallel_pressure" => true, "vpa_ngrid" => 270, "vpa_L" => - 12.0, "vz_ngrid" => 270, "vz_L" => 12.0)) - -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 2, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 8, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 8)) + recursive_merge(test_input_finite_difference_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true), + "vpa" => OptionsDict("ngrid" => 270, "L" => 12.0), + "vz" => OptionsDict("ngrid" => 270, "L" => 12.0)) + ) + +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 2), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 8), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 8), + )) test_input_chebyshev_split_1_moment = - merge(test_input_chebyshev, - Dict("run_name" => "chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) + recursive_merge(test_input_chebyshev, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment"), + "evolve_moments" => OptionsDict("density" => true))) test_input_chebyshev_split_2_moments = - merge(test_input_chebyshev_split_1_moment, - Dict("run_name" => "chebyshev_pseudospectral_split_2_moments", - "evolve_moments_parallel_flow" => true)) + recursive_merge(test_input_chebyshev_split_1_moment, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments"), + "evolve_moments" => OptionsDict("parallel_flow" => true))) test_input_chebyshev_split_3_moments = - merge(test_input_chebyshev_split_2_moments, - Dict("run_name" => "chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true)) + recursive_merge(test_input_chebyshev_split_2_moments, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments"), + "evolve_moments" => OptionsDict("parallel_pressure" => true))) """ @@ -149,7 +155,7 @@ function run_test(test_input, analytic_frequency, analytic_growth_rate, return string(string(key)[1], value) end end - name = input["run_name"] + name = input["output"]["run_name"] shortname = name if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -164,7 +170,7 @@ function run_test(test_input, analytic_frequency, analytic_growth_rate, # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = shortname + input["output"]["run_name"] = shortname # Suppress console output while running phi_fit = undef @@ -180,7 +186,7 @@ function run_test(test_input, analytic_frequency, analytic_growth_rate, # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), shortname, shortname) + path = joinpath(realpath(input["output"]["base_directory"]), shortname, shortname) # open the netcdf file and give it the handle 'fid' fid = open_readonly_output_file(path,"moments") @@ -250,18 +256,18 @@ function run_test_set_finite_difference() @long run_test(test_input_finite_difference, 2*π*1.4467, -2*π*0.6020, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference, 2*π*1.4240, -2*π*0.6379, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]) @long run_test(test_input_finite_difference, 2*π*0.0, -2*π*0.3235, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_finite_difference, 2*π*0.0, -2*π*0.2963, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_finite_difference, 2*π*1.4467, -2*π*0.6020, @@ -276,7 +282,7 @@ function run_test_set_finite_difference() -0.000941612585497573]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_finite_difference, 2*π*1.2671, -2*π*0.8033, @@ -297,12 +303,12 @@ function run_test_set_finite_difference() -0.3470252574909716, -0.3470107059829777, -0.3469943940725544], 30; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_finite_difference, 2*π*0.0, -2*π*0.2727, [-0.34705779901310196, -0.34704885164065513, -0.3470379898466833, -0.3470252574909716, -0.3470107059829777, -0.3469943940725544]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_finite_difference, 2*π*1.9919, -2*π*0.2491, @@ -317,18 +323,18 @@ function run_test_set_finite_difference_split_1_moment() run_test(test_input_finite_difference_split_1_moment, 2*π*1.4467, -2*π*0.6020, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference_split_1_moment, 2*π*1.4240, -2*π*0.6379, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]) run_test(test_input_finite_difference_split_1_moment, 2*π*0.0, -2*π*0.3235, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) run_test(test_input_finite_difference_split_1_moment, 2*π*0.0, -2*π*0.2963, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 run_test(test_input_finite_difference_split_1_moment, 2*π*1.4467, -2*π*0.6020, @@ -341,7 +347,7 @@ function run_test_set_finite_difference_split_1_moment() -0.0010033394223312585, -0.0009742364063434105, -0.0009416125854969064]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 run_test(test_input_finite_difference_split_1_moment, 2*π*1.2671, -2*π*0.8033, @@ -362,12 +368,12 @@ function run_test_set_finite_difference_split_1_moment() -0.3470252574909716, -0.3470107059829777, -0.3469943940725544], 30; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference_split_1_moment, 2*π*0.0, -2*π*0.2727, [-0.34705779901310196, -0.34704885164065513, -0.3470379898466833, -0.3470252574909716, -0.3470107059829777, -0.3469943940725544]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 run_test(test_input_finite_difference_split_1_moment, 2*π*1.9919, -2*π*0.2491, @@ -382,18 +388,18 @@ function run_test_set_finite_difference_split_2_moments() run_test(test_input_finite_difference_split_2_moments, 2*π*1.4467, -2*π*0.6020, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference_split_2_moments, 2*π*1.4240, -2*π*0.6379, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]) run_test(test_input_finite_difference_split_2_moments, 2*π*0.0, -2*π*0.3235, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) run_test(test_input_finite_difference_split_2_moments, 2*π*0.0, -2*π*0.2963, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 run_test(test_input_finite_difference_split_2_moments, 2*π*1.4467, -2*π*0.6020, @@ -406,7 +412,7 @@ function run_test_set_finite_difference_split_2_moments() -0.0010033394223312585, -0.0009742364063434105, -0.0009416125854969064]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 run_test(test_input_finite_difference_split_2_moments, 2*π*1.2671, -2*π*0.8033, [-0.34706673733456106, -0.3470627566790802, -0.3470579059173919, -0.347052193699157, -0.34704563020982493, -0.3470382271523149], 30; composition = OptionsDict("T_e" => 0.5), - timestepping = OptionsDict("nstep" => 1300), z_ngrid=150, - charge_exchange_frequency=2*π*0.0) + timestepping = OptionsDict("nstep" => 1300), z = OptionsDict("ngrid" => 150), + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference_split_2_moments, 2*π*0.0, -2*π*0.2727, [-0.34705779901310196, -0.34704885164065513, -0.3470379898466833, -0.3470252574909716, -0.3470107059829777, -0.3469943940725544]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 run_test(test_input_finite_difference_split_2_moments, 2*π*1.9919, -2*π*0.2491, @@ -448,18 +454,18 @@ function run_test_set_finite_difference_split_3_moments() -2*π*0.6020, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_finite_difference_split_3_moments, 2*π*1.4240, -2*π*0.6379, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]) @long run_test(test_input_finite_difference_split_3_moments, 2*π*0.0, -2*π*0.3235, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_finite_difference_split_3_moments, 2*π*0.0, -2*π*0.2963, [-0.6941155980262039, -0.6940977032813103, -0.6940759796933667, -0.6940505149819431, -0.6940214119659553, -0.6939887881451088]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_finite_difference_split_3_moments, 2*π*1.4467, @@ -474,7 +480,7 @@ function run_test_set_finite_difference_split_3_moments() -0.0009742364063434105, -0.0009416125854969064]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_finite_difference_split_3_moments, 2*π*1.2671, @@ -497,12 +503,12 @@ function run_test_set_finite_difference_split_3_moments() -0.3470107059829777, -0.3469943940725544], 30; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_finite_difference_split_3_moments, 2*π*0.0, -2*π*0.2727, [-0.34705779901310196, -0.34704885164065513, -0.3470379898466833, -0.3470252574909716, -0.3470107059829777, -0.3469943940725544]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_finite_difference_split_3_moments, 2*π*1.9919, @@ -518,18 +524,18 @@ function run_test_set_chebyshev() @long run_test(test_input_chebyshev, 2*π*1.4467, -2*π*0.6020, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_chebyshev, 2*π*1.4240, -2*π*0.6379, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]) @long run_test(test_input_chebyshev, 2*π*0.0, -2*π*0.3235, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_chebyshev, 2*π*0.0, -2*π*0.2963, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_chebyshev, 2*π*1.4467, -2*π*0.6020, @@ -542,7 +548,7 @@ function run_test_set_chebyshev() 0.0008923624901804128, 0.0008994953327500175, 0.0008923624901804128]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_chebyshev, 2*π*1.2671, -2*π*0.8033, @@ -563,12 +569,12 @@ function run_test_set_chebyshev() -0.34607740653471614, -0.34607384011343095, -0.34607740653471614], 30; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_chebyshev, 2*π*0.0, -2*π*0.2727, [-0.34657359027997264, -0.34629088790428314, -0.34612578140467837, -0.34607740653471614, -0.34607384011343095, -0.34607740653471614]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_chebyshev, 2*π*1.9919, -2*π*0.2491, @@ -583,18 +589,18 @@ function run_test_set_chebyshev_split_1_moment() @long run_test(test_input_chebyshev_split_1_moment, 2*π*1.4467, -2*π*0.6020, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_chebyshev_split_1_moment, 2*π*1.4240, -2*π*0.6379, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]) @long run_test(test_input_chebyshev_split_1_moment, 2*π*0.0, -2*π*0.3235, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_chebyshev_split_1_moment, 2*π*0.0, -2*π*0.2963, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_chebyshev_split_1_moment, 2*π*1.4467, -2*π*0.6020, @@ -609,7 +615,7 @@ function run_test_set_chebyshev_split_1_moment() 0.0008923624901797472]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_chebyshev_split_1_moment, 2*π*1.2671, -2*π*0.8033, @@ -630,12 +636,12 @@ function run_test_set_chebyshev_split_1_moment() -0.34607740653471614, -0.34607384011343095, -0.34607740653471614], 30; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_chebyshev_split_1_moment, 2*π*0.0, -2*π*0.2727, [-0.34657359027997264, -0.34629088790428314, -0.34612578140467837, -0.34607740653471614, -0.34607384011343095, -0.34607740653471614]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_chebyshev_split_1_moment, 2*π*1.9919, -2*π*0.2491, @@ -650,18 +656,18 @@ function run_test_set_chebyshev_split_2_moments() @long run_test(test_input_chebyshev_split_2_moments, 2*π*1.4467, -2*π*0.6020, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_chebyshev_split_2_moments, 2*π*1.4240, -2*π*0.6379, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]) @long run_test(test_input_chebyshev_split_2_moments, 2*π*0.0, -2*π*0.3235, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_chebyshev_split_2_moments, 2*π*0.0, -2*π*0.2963, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_chebyshev_split_2_moments, 2*π*1.4467, -2*π*0.6020, @@ -676,7 +682,7 @@ function run_test_set_chebyshev_split_2_moments() 0.0008923624901797472]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_chebyshev_split_2_moments, 2*π*1.2671, -2*π*0.8033, @@ -697,12 +703,12 @@ function run_test_set_chebyshev_split_2_moments() -0.34607740653471614, -0.34607384011343095, -0.34607740653471614], 40; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300, "nwrite" => 10), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_chebyshev_split_2_moments, 2*π*0.0, -2*π*0.2727, [-0.34657359027997264, -0.34629088790428314, -0.34612578140467837, -0.34607740653471614, -0.34607384011343095, -0.34607740653471614]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_chebyshev_split_2_moments, 2*π*1.9919, -2*π*0.2491, @@ -717,18 +723,18 @@ function run_test_set_chebyshev_split_3_moments() @long run_test(test_input_chebyshev_split_3_moments, 2*π*1.4467, -2*π*0.6020, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) run_test(test_input_chebyshev_split_3_moments, 2*π*1.4240, -2*π*0.6379, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]) @long run_test(test_input_chebyshev_split_3_moments, 2*π*0.0, -2*π*0.3235, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*1.8) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*1.8)) @long run_test(test_input_chebyshev_split_3_moments, 2*π*0.0, -2*π*0.2963, [-0.6931471805599453, -0.6925817758085663, -0.6922515628093567, -0.6921548130694323, -0.6921476802268619, -0.6921548130694323]; - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i>>n_n T_e=1 @long run_test(test_input_chebyshev_split_3_moments, 2*π*1.4467, -2*π*0.6020, @@ -743,7 +749,7 @@ function run_test_set_chebyshev_split_3_moments() 0.0008923624901797472]; ion_species_1 = OptionsDict("initial_density" => 0.9999), neutral_species_1 = OptionsDict("initial_density" => 0.0001), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i< 0.0001), neutral_species_1 = OptionsDict("initial_density" => 0.9999), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=0.5 @long run_test(test_input_chebyshev_split_3_moments, 2*π*1.2671, -2*π*0.8033, @@ -764,12 +770,12 @@ function run_test_set_chebyshev_split_3_moments() -0.34607740653471614, -0.34607384011343095, -0.34607740653471614], 80; composition = OptionsDict("T_e" => 0.5), timestepping = OptionsDict("nstep" => 1300, "nwrite" => 5), - charge_exchange_frequency=2*π*0.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*0.0)) @long run_test(test_input_chebyshev_split_3_moments, 2*π*0.0, -2*π*0.2727, [-0.34657359027997264, -0.34629088790428314, -0.34612578140467837, -0.34607740653471614, -0.34607384011343095, -0.34607740653471614]; composition = OptionsDict("T_e" => 0.5), - charge_exchange_frequency=2*π*2.0) + reactions=OptionsDict("charge_exchange_frequency"=>2*π*2.0)) # n_i=n_n T_e=4 @long run_test(test_input_chebyshev_split_3_moments, 2*π*1.9919, -2*π*0.2491, @@ -787,30 +793,30 @@ function runtests() println("sound wave tests") @testset "finite difference" begin - test_input_finite_difference["base_directory"] = test_output_directory + test_input_finite_difference["output"]["base_directory"] = test_output_directory run_test_set_finite_difference() - test_input_finite_difference_split_1_moment["base_directory"] = test_output_directory + test_input_finite_difference_split_1_moment["output"]["base_directory"] = test_output_directory @long run_test_set_finite_difference_split_1_moment() - test_input_finite_difference_split_2_moments["base_directory"] = test_output_directory + test_input_finite_difference_split_2_moments["output"]["base_directory"] = test_output_directory @long run_test_set_finite_difference_split_2_moments() - test_input_finite_difference_split_3_moments["base_directory"] = test_output_directory + test_input_finite_difference_split_3_moments["output"]["base_directory"] = test_output_directory run_test_set_finite_difference_split_3_moments() end @testset "Chebyshev" begin - test_input_chebyshev["base_directory"] = test_output_directory + test_input_chebyshev["output"]["base_directory"] = test_output_directory run_test_set_chebyshev() - test_input_chebyshev_split_1_moment["base_directory"] = test_output_directory + test_input_chebyshev_split_1_moment["output"]["base_directory"] = test_output_directory run_test_set_chebyshev_split_1_moment() - test_input_chebyshev_split_2_moments["base_directory"] = test_output_directory + test_input_chebyshev_split_2_moments["output"]["base_directory"] = test_output_directory run_test_set_chebyshev_split_2_moments() - test_input_chebyshev_split_3_moments["base_directory"] = test_output_directory + test_input_chebyshev_split_3_moments["output"]["base_directory"] = test_output_directory run_test_set_chebyshev_split_3_moments() end end diff --git a/moment_kinetics/test/velocity_integral_tests.jl b/moment_kinetics/test/velocity_integral_tests.jl index 5c1506389..4cddf0537 100644 --- a/moment_kinetics/test/velocity_integral_tests.jl +++ b/moment_kinetics/test/velocity_integral_tests.jl @@ -2,7 +2,6 @@ module VelocityIntegralTests include("setup.jl") -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.velocity_moments: get_density, get_upar, get_ppar, get_pperp, get_pressure using moment_kinetics.array_allocation: allocate_float @@ -23,34 +22,36 @@ function runtests() Lvpa = 18.0 #physical box size in reference units Lvperp = 9.0 #physical box size in reference units bc = "" #not required to take a particular value, not used - # fd_option and adv_input not actually used so given values unimportant discretization = "chebyshev_pseudospectral" - fd_option = "fourth_order_centered" cheb_option = "FFT" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = MPI.COMM_NULL - # create the 'input' struct containing input info needed to create a - # coordinate - vr_input = grid_input("vperp", 1, 1, 1, nrank, irank, 1.0, discretization, - fd_option, cheb_option, bc, adv_input, comm, "uniform") - vz_input = grid_input("vpa", ngrid, nelement_global, nelement_local, nrank, irank, - Lvpa, discretization, fd_option, cheb_option, bc, adv_input, comm, - "uniform") - vpa_input = grid_input("vpa", ngrid, nelement_global, nelement_local, nrank, - irank, Lvpa, discretization, fd_option, cheb_option, bc, adv_input, - comm, "uniform") - vperp_input = grid_input("vperp", ngrid, nelement_global, nelement_local, nrank, - irank, Lvperp, discretization, fd_option, cheb_option, bc, adv_input, - comm, "uniform") - # create the coordinate struct 'x' - # This test runs effectively in serial, so use `ignore_MPI=true` to avoid - # errors due to communicators not being fully set up. - vpa, vpa_spectral = define_coordinate(vpa_input, nothing; ignore_MPI=true) - vperp, vperp_spectral = define_coordinate(vperp_input, nothing; ignore_MPI=true) - vz, vz_spectral = define_coordinate(vz_input, nothing; ignore_MPI=true) - vr, vr_spectral = define_coordinate(vr_input, nothing; ignore_MPI=true) + # create the 'input' struct containing input info needed to create + # coordinates + coords_input = OptionsDict("vperp1d"=>OptionsDict("ngrid"=>1, "nelement"=>1, "nelement_local"=>1, "L"=>1.0, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>"uniform"), + "vpa1d"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>Lvpa, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>"uniform"), + "vperp"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>Lvperp, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>"uniform"), + "vpa"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>Lvpa, + "discretization"=>discretization, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>"uniform"), + ) + + # create the coordinate structs + vpa, vpa_spectral = define_coordinate(coords_input, "vpa"; ignore_MPI=true) + vperp, vperp_spectral = define_coordinate(coords_input, "vperp"; ignore_MPI=true) + vz, vz_spectral = define_coordinate(coords_input, "vpa1d"; ignore_MPI=true) + vr, vr_spectral = define_coordinate(coords_input, "vperp1d"; ignore_MPI=true) dfn = allocate_float(vpa.n,vperp.n) dfn1D = allocate_float(vz.n, vr.n) diff --git a/moment_kinetics/test/wall_bc_tests.jl b/moment_kinetics/test/wall_bc_tests.jl index bdafab307..91cd2fa2d 100644 --- a/moment_kinetics/test/wall_bc_tests.jl +++ b/moment_kinetics/test/wall_bc_tests.jl @@ -9,121 +9,123 @@ using Base.Filesystem: tempname using MPI using moment_kinetics.coordinates: define_coordinate -using moment_kinetics.input_structs: grid_input, advection_input, merge_dict_with_kwargs! using moment_kinetics.interpolation: interpolate_to_grid_z using moment_kinetics.load_data: open_readonly_output_file using moment_kinetics.load_data: load_fields_data, load_pdf_data, load_time_data, load_species_data -using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: merge_dict_with_kwargs! # default inputs for tests -test_input_finite_difference = Dict("composition" => OptionsDict("n_ion_species" => 1, - "n_neutral_species" => 1, - "electron_physics" => "boltzmann_electron_response", - "T_e" => 1.0, - "T_wall" => 1.0), - "ion_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 1.0, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "neutral_species_1" => OptionsDict("initial_density" => 1.0, - "initial_temperature" => 1.0), - "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", - "density_amplitude" => 0.001, - "density_phase" => 0.0, - "upar_amplitude" => 0.0, - "upar_phase" => 0.0, - "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "vpa_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", +test_input_finite_difference = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "electron_physics" => "boltzmann_electron_response", + "T_e" => 1.0, + "T_wall" => 1.0), + "ion_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "vpa_IC_ion_species_1" => OptionsDict("initialization_option" => "gaussian", "density_amplitude" => 1.0, "density_phase" => 0.0, "upar_amplitude" => 0.0, "upar_phase" => 0.0, "temperature_amplitude" => 0.0, - "temperature_phase" => 0.0), - "run_name" => "finite_difference", - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => false, - "charge_exchange_frequency" => 2.0, - "ionization_frequency" => 2.0, - "constant_ionization_rate" => false, - "timestepping" => OptionsDict("nstep" => 10000, - "dt" => 1.0e-5, - "nwrite" => 100, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "finite_difference", - "z_ngrid" => 200, - "z_nelement" => 1, - "z_bc" => "wall", - "z_discretization" => "finite_difference", - "z_element_spacing_option" => "uniform", - "vpa_ngrid" => 400, - "vpa_nelement" => 1, - "vpa_L" => 8.0, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 400, - "vz_nelement" => 1, - "vz_L" => 8.0, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference") + "temperature_phase" => 0.0), + "neutral_species_1" => OptionsDict("initial_density" => 1.0, + "initial_temperature" => 1.0), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 0.001, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "vz_IC_neutral_species_1" => OptionsDict("initialization_option" => "gaussian", + "density_amplitude" => 1.0, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.0, + "temperature_phase" => 0.0), + "output" => OptionsDict("run_name" => "finite_difference"), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => false), + "reactions" => OptionsDict("charge_exchange_frequency" => 2.0, + "ionization_frequency" => 2.0), + "timestepping" => OptionsDict("nstep" => 10000, + "dt" => 1.0e-5, + "nwrite" => 100, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "z" => OptionsDict("ngrid" => 200, + "nelement" => 1, + "bc" => "wall", + "discretization" => "finite_difference", + "element_spacing_option" => "uniform"), + "vpa" => OptionsDict("ngrid" => 400, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 400, + "nelement" => 1, + "L" => 8.0, + "bc" => "periodic", + "discretization" => "finite_difference"), + ) -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 2, - "z_element_spacing_option" => "uniform", - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 10, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 10)) +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 2, + "element_spacing_option" => "uniform"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + )) -test_input_chebyshev_sqrt_grid_odd = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 5, # minimum nontrival nelement (odd) - "z_element_spacing_option" => "sqrt", - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 10, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 10)) -test_input_chebyshev_sqrt_grid_even = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 6, # minimum nontrival nelement (even) - "z_element_spacing_option" => "sqrt", - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 10, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 10)) +test_input_chebyshev_sqrt_grid_odd = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 5, # minimum nontrival nelement (odd) + "element_spacing_option" => "sqrt"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + )) +test_input_chebyshev_sqrt_grid_even = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 6, # minimum nontrival nelement (even) + "element_spacing_option" => "sqrt"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 10), + )) # Reference output interpolated onto a common set of points for comparing # different discretizations, taken from a Chebyshev run with z_grid=9, @@ -146,7 +148,7 @@ function run_test(test_input, expected_phi, tolerance; args...) input = deepcopy(test_input) # Convert keyword arguments to a unique name - name = input["run_name"] * ", with element spacing: " * input["z_element_spacing_option"] + name = input["output"]["run_name"] * ", with element spacing: " * input["z"]["element_spacing_option"] if length(args) > 0 name = string(name, "_", (string(k, "-", v, "_") for (k, v) in args)...) @@ -159,7 +161,7 @@ function run_test(test_input, expected_phi, tolerance; args...) # Update default inputs with values to be changed merge_dict_with_kwargs!(input; args...) - input["run_name"] = name + input["output"]["run_name"] = name # Suppress console output while running phi = undef @@ -173,7 +175,7 @@ function run_test(test_input, expected_phi, tolerance; args...) # Load and analyse output ######################### - path = joinpath(realpath(input["base_directory"]), name, name) + path = joinpath(realpath(input["output"]["base_directory"]), name, name) # open the netcdf file and give it the handle 'fid' fid = open_readonly_output_file(path,"moments") @@ -202,23 +204,10 @@ function run_test(test_input, expected_phi, tolerance; args...) end # Create coordinates - # - # create the 'input' struct containing input info needed to create a coordinate - # adv_input not actually used in this test so given values unimportant - adv_input = advection_input("default", 1.0, 0.0, 0.0) - cheb_option = "FFT" - nrank_per_block = 0 # dummy value - irank = 0 # dummy value - comm = MPI.COMM_NULL # dummy value - element_spacing_option = "uniform" - input = grid_input("coord", test_input["z_ngrid"], test_input["z_nelement"], - test_input["z_nelement"], nrank_per_block, irank, 1.0, - test_input["z_discretization"], "", cheb_option, test_input["z_bc"], - adv_input, comm, test_input["z_element_spacing_option"]) - z, z_spectral = define_coordinate(input, nothing; ignore_MPI=true) + z, z_spectral = define_coordinate(test_input, "z"; ignore_MPI=true) # Cross comparison of all discretizations to same benchmark - if test_input["z_element_spacing_option"] == "uniform" + if test_input["z"]["element_spacing_option"] == "uniform" # Only support this test for uniform element spacing. # phi is better resolved by "sqrt" spacing grid, so disagrees with benchmark data from # simulation with uniform element spacing. @@ -236,12 +225,12 @@ function runtests() println("Wall boundary condition tests") @testset_skip "FD test case does not conserve density" "finite difference" begin - test_input_finite_difference["base_directory"] = test_output_directory + test_input_finite_difference["output"]["base_directory"] = test_output_directory run_test(test_input_finite_difference, nothing, 2.e-3) end @testset "Chebyshev uniform" begin - test_input_chebyshev["base_directory"] = test_output_directory + test_input_chebyshev["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev, [-1.168944495073113, -0.747950464799219, -0.6947560093910274, -0.6917252594440765, -0.7180152693147238, -0.9980114030684668], @@ -249,7 +238,7 @@ function runtests() end @testset "Chebyshev sqrt grid odd" begin - test_input_chebyshev_sqrt_grid_odd["base_directory"] = test_output_directory + test_input_chebyshev_sqrt_grid_odd["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_sqrt_grid_odd, [-1.2047298844053338, -0.9431378244038217, -0.8084332486925859, -0.7812620574297168, -0.7233303715713063, -0.700387877851292, @@ -259,7 +248,7 @@ function runtests() 2.e-3) end @testset "Chebyshev sqrt grid even" begin - test_input_chebyshev_sqrt_grid_even["base_directory"] = test_output_directory + test_input_chebyshev_sqrt_grid_even["output"]["base_directory"] = test_output_directory run_test(test_input_chebyshev_sqrt_grid_even, [-1.213617044609117, -1.0054529856551995, -0.8714447622540997, -0.836017704148175, -0.7552111126205924, -0.7264644278204795, diff --git a/performance-tests/plot_performance.jl b/performance-tests/plot_performance.jl index 0328fa60c..44d0aa6e8 100644 --- a/performance-tests/plot_performance.jl +++ b/performance-tests/plot_performance.jl @@ -287,13 +287,13 @@ function get_grid_sizes(prefix) inputs_list = SoundWavePerformance.inputs_list # Use nz as the 'grid size' because that is the outer-loop in most of the 1D1V # code (basically everything apart from z_advection!()). - grid_sizes = [input["z_nelement"] * (input["z_ngrid"] - 1) + 1 + grid_sizes = [input["z"]["nelement"] * (input["z"]["ngrid"] - 1) + 1 for input in inputs_list] elseif prefix == "sound_wave-2xres" inputs_list = SoundWave2xResPerformance.inputs_list # Use nz as the 'grid size' because that is the outer-loop in most of the 1D1V # code (basically everything apart from z_advection!()). - grid_sizes = [input["z_nelement"] * (input["z_ngrid"] - 1) + 1 + grid_sizes = [input["z"]["nelement"] * (input["z"]["ngrid"] - 1) + 1 for input in inputs_list] else error("Unrecognized prefix $prefix") diff --git a/performance-tests/sound_wave-2xres.jl b/performance-tests/sound_wave-2xres.jl index 9622c0c12..5c8f01e41 100644 --- a/performance-tests/sound_wave-2xres.jl +++ b/performance-tests/sound_wave-2xres.jl @@ -2,6 +2,7 @@ module SoundWave2xResPerformance include("utils.jl") using .PerformanceTestUtils +using moment_kinetics.utils: recursive_merge const test_name = "sound_wave-2xres" @@ -14,100 +15,102 @@ const z_L = 1.0 # always 1 in normalized units? const vpa_L = 8.0 # default inputs for tests -test_input_finite_difference = Dict("n_ion_species" => 1, - "n_neutral_species" => 1, - "boltzmann_electron_response" => true, - "run_name" => "finite_difference", - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "T_e" => 1.0, - "initial_density1" => 0.5, - "initial_temperature1" => 1.0, - "initial_density2" => 0.5, - "initial_temperature2" => 1.0, - "z_IC_option1" => "sinusoid", - "z_IC_density_amplitude1" => 0.5, - "z_IC_density_phase1" => 0.0, - "z_IC_upar_amplitude1" => 0.0, - "z_IC_upar_phase1" => 0.0, - "z_IC_temperature_amplitude1" => 0.5, - "z_IC_temperature_phase1" => Float64(π), - "z_IC_option2" => "sinusoid", - "z_IC_density_amplitude2" => 0.5, - "z_IC_density_phase2" => Float64(π), - "z_IC_upar_amplitude2" => 0.0, - "z_IC_upar_phase2" => 0.0, - "z_IC_temperature_amplitude2" => 0.5, - "z_IC_temperature_phase2" => 0.0, - "charge_exchange_frequency" => 2*Float64(π)*0.1, - "ionization_frequency" => 0.0, - "timestepping" => Dict("nstep" => 100, - "dt" => 0.0002, - "nwrite" => 200, - "use_semi_lagrange" => false, - "n_rk_stages" => 4, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 161, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 481, - "vpa_nelement" => 1, - "vpa_L" => vpa_L, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 481, - "vz_nelement" => 1, - "vz_L" => vpa_L, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference") +test_input_finite_difference = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "boltzmann_electron_response" => true, + "T_e" => 1.0), + "output" => OptionsDict("run_name" => "finite_difference", + "base_directory" => test_output_directory), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "neutral_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => 0.0, + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => Float64(π)), + "z_IC_neutral_species_1" => OptionsDict("initialization_option2" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => Float64(π), + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => 0.0), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*Float64(π)*0.1, + "ionization_frequency" => 0.0), + "timestepping" => Dict("nstep" => 100, + "dt" => 0.0002, + "nwrite" => 200, + "use_semi_lagrange" => false, + "n_rk_stages" => 4, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 161, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 481, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 481, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + ) test_input_finite_difference_split_1_moment = merge(test_input_finite_difference, - Dict("run_name" => "finite_difference_split_1_moment", - "evolve_moments_density" => true)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_1_moment"), + "evolve_moments_density" => true)) test_input_finite_difference_split_2_moments = merge(test_input_finite_difference_split_1_moment, - Dict("run_name" => "finite_difference_split_2_moments", - "evolve_moments_parallel_flow" => true)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_2_moments"), + "evolve_moments_parallel_flow" => true)) test_input_finite_difference_split_3_moments = merge(test_input_finite_difference_split_2_moments, - Dict("run_name" => "finite_difference_split_3_moments", - "evolve_moments_parallel_pressure" => true)) - -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 20, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 34, - "vpa_nelement" => 15, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 34, - "vz_nelement" => 15)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_3_moments"), + "evolve_moments_parallel_pressure" => true)) + +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 20), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 34, + "nelement" => 15), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 34, + "nelement" => 15), + )) test_input_chebyshev_split_1_moment = merge(test_input_chebyshev, - Dict("run_name" => "chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment"), + "evolve_moments_density" => true)) test_input_chebyshev_split_2_moments = merge(test_input_chebyshev_split_1_moment, - Dict("run_name" => "chebyshev_pseudospectral_split_2_moments", - "evolve_moments_parallel_flow" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments"), + "evolve_moments_parallel_flow" => true)) test_input_chebyshev_split_3_moments = merge(test_input_chebyshev_split_2_moments, - Dict("run_name" => "chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments"), + "evolve_moments_parallel_pressure" => true)) inputs_list = (test_input_finite_difference, test_input_finite_difference_split_1_moment, diff --git a/performance-tests/sound_wave.jl b/performance-tests/sound_wave.jl index 787c77189..f2f7526be 100644 --- a/performance-tests/sound_wave.jl +++ b/performance-tests/sound_wave.jl @@ -2,6 +2,7 @@ module SoundWavePerformance include("utils.jl") using .PerformanceTestUtils +using moment_kinetics.utils: recursive_merge const test_name = "sound_wave" @@ -14,100 +15,102 @@ const z_L = 1.0 # always 1 in normalized units? const vpa_L = 8.0 # default inputs for tests -test_input_finite_difference = Dict("n_ion_species" => 1, - "n_neutral_species" => 1, - "boltzmann_electron_response" => true, - "run_name" => "finite_difference", - "base_directory" => test_output_directory, - "evolve_moments_density" => false, - "evolve_moments_parallel_flow" => false, - "evolve_moments_parallel_pressure" => false, - "evolve_moments_conservation" => true, - "T_e" => 1.0, - "initial_density1" => 0.5, - "initial_temperature1" => 1.0, - "initial_density2" => 0.5, - "initial_temperature2" => 1.0, - "z_IC_option1" => "sinusoid", - "z_IC_density_amplitude1" => 0.5, - "z_IC_density_phase1" => 0.0, - "z_IC_upar_amplitude1" => 0.0, - "z_IC_upar_phase1" => 0.0, - "z_IC_temperature_amplitude1" => 0.5, - "z_IC_temperature_phase1" => Float64(π), - "z_IC_option2" => "sinusoid", - "z_IC_density_amplitude2" => 0.5, - "z_IC_density_phase2" => Float64(π), - "z_IC_upar_amplitude2" => 0.0, - "z_IC_upar_phase2" => 0.0, - "z_IC_temperature_amplitude2" => 0.5, - "z_IC_temperature_phase2" => 0.0, - "charge_exchange_frequency" => 2*Float64(π)*0.1, - "ionization_frequency" => 0.0, - "timestepping" => Dict( "nstep" => 100, - "dt" => 0.0005, - "nwrite" => 200, - "use_semi_lagrange" => false, - "n_rk_stages" => 4, - "split_operators" => false), - "r_ngrid" => 1, - "r_nelement" => 1, - "z_ngrid" => 81, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 241, - "vpa_nelement" => 1, - "vpa_L" => vpa_L, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "vz_ngrid" => 241, - "vz_nelement" => 1, - "vz_L" => vpa_L, - "vz_bc" => "periodic", - "vz_discretization" => "finite_difference") +test_input_finite_difference = OptionsDict("composition" => OptionsDict("n_ion_species" => 1, + "n_neutral_species" => 1, + "boltzmann_electron_response" => true, + "T_e" => 1.0), + "output" => OptionsDict("run_name" => "finite_difference", + "base_directory" => test_output_directory), + "evolve_moments" => OptionsDict("density" => false, + "parallel_flow" => false, + "parallel_pressure" => false, + "moments_conservation" => true), + "ion_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "neutral_species_1" => OptionsDict("initial_density" => 0.5, + "initial_temperature" => 1.0), + "z_IC_ion_species_1" => OptionsDict("initialization_option" => "sinusoid", + "z_IC_density_amplitude" => 0.5, + "z_IC_density_phase" => 0.0, + "z_IC_upar_amplitude" => 0.0, + "z_IC_upar_phase" => 0.0, + "z_IC_temperature_amplitude" => 0.5, + "z_IC_temperature_phase" => Float64(π)), + "z_IC_neutral_species_1" => OptionsDict("initialization_option" => "sinusoid", + "density_amplitude" => 0.5, + "density_phase" => Float64(π), + "upar_amplitude" => 0.0, + "upar_phase" => 0.0, + "temperature_amplitude" => 0.5, + "temperature_phase" => 0.0), + "reactions" => OptionsDict("charge_exchange_frequency" => 2*Float64(π)*0.1, + "ionization_frequency" => 0.0), + "timestepping" => OptionsDict( "nstep" => 100, + "dt" => 0.0005, + "nwrite" => 200, + "use_semi_lagrange" => false, + "n_rk_stages" => 4, + "split_operators" => false), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "z" => OptionsDict("ngrid" => 81, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 241, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 241, + "nelement" => 1, + "L" => vpa_L, + "bc" => "periodic", + "discretization" => "finite_difference"), + ) test_input_finite_difference_split_1_moment = merge(test_input_finite_difference, - Dict("run_name" => "finite_difference_split_1_moment", - "evolve_moments_density" => true)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_1_moment"), + "evolve_moments_density" => true)) test_input_finite_difference_split_2_moments = merge(test_input_finite_difference_split_1_moment, - Dict("run_name" => "finite_difference_split_2_moments", - "evolve_moments_parallel_flow" => true)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_2_moments"), + "evolve_moments_parallel_flow" => true)) test_input_finite_difference_split_3_moments = merge(test_input_finite_difference_split_2_moments, - Dict("run_name" => "finite_difference_split_3_moments", - "evolve_moments_parallel_pressure" => true)) - -test_input_chebyshev = merge(test_input_finite_difference, - Dict("run_name" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 9, - "z_nelement" => 10, - "vpa_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 17, - "vpa_nelement" => 15, - "vz_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 17, - "vz_nelement" => 15)) + OptionsDict("output" => OptionsDict("run_name" => "finite_difference_split_3_moments"), + "evolve_moments_parallel_pressure" => true)) + +test_input_chebyshev = recursive_merge(test_input_finite_difference, + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 9, + "nelement" => 10), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 15), + "vz" => OptionsDict("discretization" => "chebyshev_pseudospectral", + "ngrid" => 17, + "nelement" => 15), + )) test_input_chebyshev_split_1_moment = merge(test_input_chebyshev, - Dict("run_name" => "chebyshev_pseudospectral_split_1_moment", - "evolve_moments_density" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_1_moment"), + "evolve_moments_density" => true)) test_input_chebyshev_split_2_moments = merge(test_input_chebyshev_split_1_moment, - Dict("run_name" => "chebyshev_pseudospectral_split_2_moments", - "evolve_moments_parallel_flow" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_2_moments"), + "evolve_moments_parallel_flow" => true)) test_input_chebyshev_split_3_moments = merge(test_input_chebyshev_split_2_moments, - Dict("run_name" => "chebyshev_pseudospectral_split_3_moments", - "evolve_moments_parallel_pressure" => true)) + OptionsDict("output" => OptionsDict("run_name" => "chebyshev_pseudospectral_split_3_moments"), + "evolve_moments_parallel_pressure" => true)) inputs_list = (test_input_finite_difference, test_input_finite_difference_split_1_moment, diff --git a/performance-tests/utils.jl b/performance-tests/utils.jl index 89f634179..09a4cbcfd 100644 --- a/performance-tests/utils.jl +++ b/performance-tests/utils.jl @@ -246,7 +246,7 @@ Returns [minimum time, median time, maximum time] """ function run_test(input) - message = input["run_name"] * " ($(block_size[]) procs)" + message = input["output"]["run_name"] * " ($(block_size[]) procs)" _println0(message) _println0("=" ^ length(message)) _println0() diff --git a/plots_post_processing/plots_post_processing/src/plot_MMS_sequence.jl b/plots_post_processing/plots_post_processing/src/plot_MMS_sequence.jl index 17ba9c02b..1be774f68 100644 --- a/plots_post_processing/plots_post_processing/src/plot_MMS_sequence.jl +++ b/plots_post_processing/plots_post_processing/src/plot_MMS_sequence.jl @@ -33,6 +33,7 @@ using moment_kinetics.moment_kinetics_input: mk_input, read_input_file using moment_kinetics.input_structs: geometry_input using moment_kinetics.reference_parameters using moment_kinetics.species_input: get_species_input +using moment_kinetics.type_definitions: OptionsDict import Base: get @@ -233,8 +234,8 @@ function get_MMS_error_data(path_list,scan_type,scan_name) end - r_bc = get(scan_input, "r_bc", "periodic") - z_bc = get(scan_input, "z_bc", "periodic") + r_bc = get(get(scan_input, "r", OptionsDict()), "bc", "periodic") + z_bc = get(get(scan_input, "z", OptionsDict()), "bc", "periodic") # avoid passing Lr = 0 into manufactured_solns functions if r.n > 1 Lr_in = r.L diff --git a/plots_post_processing/plots_post_processing/src/plots_post_processing.jl b/plots_post_processing/plots_post_processing/src/plots_post_processing.jl index 82c6726db..caa9d1f6f 100644 --- a/plots_post_processing/plots_post_processing/src/plots_post_processing.jl +++ b/plots_post_processing/plots_post_processing/src/plots_post_processing.jl @@ -36,9 +36,8 @@ using moment_kinetics: check_so_newer_than_code using moment_kinetics.communication using moment_kinetics.quadrature: composite_simpson_weights using moment_kinetics.array_allocation: allocate_float -using moment_kinetics.coordinates: define_coordinate using moment_kinetics.file_io: open_ascii_output_file -using moment_kinetics.type_definitions: mk_float, mk_int +using moment_kinetics.type_definitions: mk_float, mk_int, OptionsDict using moment_kinetics.load_data: open_readonly_output_file, get_group, load_input, load_time_data, construct_global_zr_coords using moment_kinetics.load_data: get_nranks @@ -60,7 +59,7 @@ using moment_kinetics.manufactured_solns: manufactured_solutions, manufactured_electric_fields, manufactured_geometry using moment_kinetics.moment_kinetics_input: mk_input, get -using moment_kinetics.input_structs: geometry_input, grid_input, species_composition +using moment_kinetics.input_structs: geometry_input, species_composition using moment_kinetics.input_structs: boltzmann_electron_response, #electron_physics_type, boltzmann_electron_response_with_simple_sheath using moment_kinetics.species_input: get_species_input @@ -239,27 +238,34 @@ function allocate_global_zr_neutral_moments(nz_global,nr_global,n_neutral_specie return neutral_density, neutral_uz, neutral_pz, neutral_qz, neutral_thermal_speed end +function _get_nested(scan_input, section, option, default) + if section ∉ keys(scan_input) + return default + end + return get(scan_input[section], option, default) +end + function get_coords_nelement(scan_input) # use 1 as default because these values should be set in input .toml - z_nelement = get(scan_input, "z_nelement", 1) - r_nelement = get(scan_input, "r_nelement", 1) - vpa_nelement = get(scan_input, "vpa_nelement", 1) - vperp_nelement = get(scan_input, "vperp_nelement", 1) - vz_nelement = get(scan_input, "vz_nelement", 1) - vr_nelement = get(scan_input, "vr_nelement", 1) - vzeta_nelement = get(scan_input, "vzeta_nelement", 1) + z_nelement = _get_nested(scan_input, "z", "nelement", 1) + r_nelement = _get_nested(scan_input, "r", "nelement", 1) + vpa_nelement = _get_nested(scan_input, "vpa", "nelement", 1) + vperp_nelement = _get_nested(scan_input, "vperp", "nelement", 1) + vz_nelement = _get_nested(scan_input, "vz", "nelement", 1) + vr_nelement = _get_nested(scan_input, "vr", "nelement", 1) + vzeta_nelement = _get_nested(scan_input, "vzeta", "nelement", 1) return z_nelement, r_nelement, vpa_nelement, vperp_nelement, vz_nelement, vr_nelement, vzeta_nelement end function get_coords_ngrid(scan_input) # use 1 as default because these values should be set in input .toml - z_ngrid = get(scan_input, "z_ngrid", 1) - r_ngrid = get(scan_input, "r_ngrid", 1) - vpa_ngrid = get(scan_input, "vpa_ngrid", 1) - vperp_ngrid = get(scan_input, "vperp_ngrid", 1) - vz_ngrid = get(scan_input, "vz_ngrid", 1) - vr_ngrid = get(scan_input, "vr_ngrid", 1) - vzeta_ngrid = get(scan_input, "vzeta_ngrid", 1) + z_ngrid = _get_nested(scan_input, "z", "ngrid", 1) + r_ngrid = _get_nested(scan_input, "r", "ngrid", 1) + vpa_ngrid = _get_nested(scan_input, "vpa", "ngrid", 1) + vperp_ngrid = _get_nested(scan_input, "vperp", "ngrid", 1) + vz_ngrid = _get_nested(scan_input, "vz", "ngrid", 1) + vr_ngrid = _get_nested(scan_input, "vr", "ngrid", 1) + vzeta_ngrid = _get_nested(scan_input, "vzeta", "ngrid", 1) return z_ngrid, r_ngrid, vpa_ngrid, vperp_ngrid, vz_ngrid, vr_ngrid, vzeta_ngrid end @@ -3243,7 +3249,7 @@ function plot_fields_2D(phi, Ez, Er, time, z, r, iz0, ir0, trygif(anim, outfile, fps=5) elseif pp.animate_phi_vs_r_z && nr == 1 && nz > 1 # make a gif animation of ϕ(z) at different times anim = @animate for i ∈ itime_min:nwrite_movie:itime_max - @views plot(z, phi[:,1,i], xlabel="z", ylabel=L"\widetilde{\phi}", ylims = (phimin,phimax)) + @views plot(z, phi[:,1,i], xlabel="z", ylabel=L"\widetilde{\phi}", ylims = (phimin,phimax),label ="") end outfile = string(run_name, "_phi_vs_z.gif") trygif(anim, outfile, fps=5) @@ -3268,13 +3274,13 @@ function plot_fields_2D(phi, Ez, Er, time, z, r, iz0, ir0, outfile = string(run_name, "_Ez"*description*"_vs_r_z.gif") trygif(anim, outfile, fps=5) anim = @animate for i ∈ itime_min:nwrite_movie:itime_max - @views plot(r, Ez[1,:,i], xlabel="r", ylabel=L"\widetilde{E}_z", ylims = (Ezmin,Ezmax)) + @views plot(r, Ez[1,:,i], xlabel="r", ylabel=L"\widetilde{E}_z", ylims = (Ezmin,Ezmax), label="") end outfile = string(run_name, "_Ez(zwall-)_vs_r.gif") trygif(anim, outfile, fps=5) elseif pp.animate_Ez_vs_r_z && nr == 1 && nz > 1 anim = @animate for i ∈ itime_min:nwrite_movie:itime_max - @views plot(z, Ez[:,1,i], xlabel="z", ylabel=L"\widetilde{E}_z", ylims = (Ezmin,Ezmax)) + @views plot(z, Ez[:,1,i], xlabel="z", ylabel=L"\widetilde{E}_z", ylims = (Ezmin,Ezmax), label="") end outfile = string(run_name, "_Ez_vs_z.gif") trygif(anim, outfile, fps=5) @@ -3291,7 +3297,7 @@ function plot_fields_2D(phi, Ez, Er, time, z, r, iz0, ir0, outfile = string(run_name, "_Er"*description*"(r,z_wall-)_vs_r.pdf") trysavefig(outfile) anim = @animate for i ∈ itime_min:nwrite_movie:itime_max - @views plot(r, Er[1,:,i], xlabel="r", ylabel=L"\widetilde{E}_r", ylims = (Ermin,Ermax)) + @views plot(r, Er[1,:,i], xlabel="r", ylabel=L"\widetilde{E}_r", ylims = (Ermin,Ermax), label="") end outfile = string(run_name, "_Er(zwall-)_vs_r.gif") trygif(anim, outfile, fps=5) @@ -3320,7 +3326,7 @@ function plot_ion_moments_2D(density, parallel_flow, parallel_pressure, description = "_ion_spec"*string(is)*"_" # the density densitymin = minimum(density[:,:,is,:]) - densitymax = maximum(density) + densitymax = maximum(density[:,:,is,:]) if pp.plot_density_vs_r0_z && nz > 1 # plot last timestep density[z,ir0] @views plot(z, density[:,ir0,is,end], xlabel=L"z/L_z", ylabel=L"n_i") outfile = string(run_name, "_density"*description*"(r0,z)_vs_z.pdf") @@ -3338,7 +3344,13 @@ function plot_ion_moments_2D(density, parallel_flow, parallel_pressure, end outfile = string(run_name, "_density"*description*"_vs_r_z.gif") trygif(anim, outfile, fps=5) - end + elseif pp.animate_density_vs_r_z && nr == 1 && nz > 1 + anim = @animate for i ∈ itime_min:nwrite_movie:itime_max + @views plot(z, density[:,1,is,i], xlabel="z", ylabel=L"n_i", ylims = (densitymin,densitymax),label ="") + end + outfile = string(run_name, "_density"*description*"_vs_z.gif") + trygif(anim, outfile, fps=5) + end if pp.plot_density_vs_r_z && nr > 1 && nz > 1 @views heatmap(r, z, density[:,:,is,end], xlabel=L"r", ylabel=L"z", c = :deep, interpolation = :cubic, windowsize = (360,240), margin = 15pt) @@ -3355,7 +3367,7 @@ function plot_ion_moments_2D(density, parallel_flow, parallel_pressure, end # the parallel flow parallel_flowmin = minimum(parallel_flow[:,:,is,:]) - parallel_flowmax = maximum(parallel_flow) + parallel_flowmax = maximum(parallel_flow[:,:,is,:]) if pp.plot_parallel_flow_vs_r0_z && nz > 1 # plot last timestep parallel_flow[z,ir0] @views plot(z, parallel_flow[:,ir0,is,end], xlabel=L"z/L_z", ylabel=L"u_{i\|\|}") outfile = string(run_name, "_parallel_flow"*description*"(r0,z)_vs_z.pdf") @@ -3373,6 +3385,12 @@ function plot_ion_moments_2D(density, parallel_flow, parallel_pressure, end outfile = string(run_name, "_parallel_flow"*description*"_vs_r_z.gif") trygif(anim, outfile, fps=5) + elseif pp.animate_parallel_flow_vs_r_z && nr == 1 && nz > 1 + anim = @animate for i ∈ itime_min:nwrite_movie:itime_max + @views plot(z, parallel_flow[:,1,is,i], xlabel="z", ylabel=L"u_{i\|\|}", ylims = (parallel_flowmin,parallel_flowmax),label ="") + end + outfile = string(run_name, "_parallel_flow"*description*"_vs_z.gif") + trygif(anim, outfile, fps=5) end if pp.plot_parallel_flow_vs_r_z && nr > 1 && nz > 1 @views heatmap(r, z, parallel_flow[:,:,is,end], xlabel=L"r", ylabel=L"z", c = :deep, interpolation = :cubic, @@ -3500,6 +3518,14 @@ function plot_ion_moments_2D(density, parallel_flow, parallel_pressure, label = [L"p_{i\|\|}" L"p_{i\perp}" L"p_{i}"], foreground_color_legend = nothing, background_color_legend = nothing) outfile = string(run_name, "_all_pressures"*description*"(r0,z)_vs_z.pdf") trysavefig(outfile) + pmin = min(minimum(parallel_pressure[:,ir0,is,:]),minimum(perpendicular_pressure[:,ir0,is,:]),minimum(total_pressure[:,ir0,is,:])) + pmax = max(maximum(parallel_pressure[:,ir0,is,:]),maximum(perpendicular_pressure[:,ir0,is,:]),maximum(total_pressure[:,ir0,is,:])) + anim = @animate for i ∈ itime_min:nwrite_movie:itime_max + @views plot([z,z,z], [parallel_pressure[:,ir0,is,i],perpendicular_pressure[:,ir0,is,i],total_pressure[:,ir0,is,i]], xlabel=L"z/L_z", ylabel="", + label = [L"p_{i\|\|}" L"p_{i\perp}" L"p_{i}"], foreground_color_legend = nothing, background_color_legend = nothing, ylims = (pmin,pmax)) + end + outfile = string(run_name, "_all_pressures"*description*"(r0,z)_vs_z.gif") + trygif(anim, outfile, fps=5) end # the thermal speed if pp.plot_vth0_vs_t diff --git a/profiling/sound_wave_chebyshev.toml b/profiling/sound_wave_chebyshev.toml index 7f61d5c13..c5f070b49 100644 --- a/profiling/sound_wave_chebyshev.toml +++ b/profiling/sound_wave_chebyshev.toml @@ -24,15 +24,19 @@ z_IC_upar_phase2 = 0.0 z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 -z_ngrid = 9 -z_nelement = 10 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 15 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[z] +ngrid = 9 +nelement = 10 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 15 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_chebyshev_split_1_moment.toml b/profiling/sound_wave_chebyshev_split_1_moment.toml index aa1f7fda2..5e01dbe80 100644 --- a/profiling/sound_wave_chebyshev_split_1_moment.toml +++ b/profiling/sound_wave_chebyshev_split_1_moment.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 9 -z_nelement = 10 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 15 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[z] +ngrid = 9 +nelement = 10 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 15 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_chebyshev_split_2_moments.toml b/profiling/sound_wave_chebyshev_split_2_moments.toml index f669c5e87..b7f2bd713 100644 --- a/profiling/sound_wave_chebyshev_split_2_moments.toml +++ b/profiling/sound_wave_chebyshev_split_2_moments.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 9 -z_nelement = 10 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 15 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[z] +ngrid = 9 +nelement = 10 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 15 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_chebyshev_split_3_moments.toml b/profiling/sound_wave_chebyshev_split_3_moments.toml index d7d85d963..0f8a71f5d 100644 --- a/profiling/sound_wave_chebyshev_split_3_moments.toml +++ b/profiling/sound_wave_chebyshev_split_3_moments.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 9 -z_nelement = 10 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 15 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" + +[z] +ngrid = 9 +nelement = 10 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 15 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_finite_difference.toml b/profiling/sound_wave_finite_difference.toml index bd7b657ff..2f4aeb181 100644 --- a/profiling/sound_wave_finite_difference.toml +++ b/profiling/sound_wave_finite_difference.toml @@ -24,17 +24,23 @@ z_IC_upar_phase2 = 0.0 z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 81 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 241 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 81 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 241 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_finite_difference_split_1_moment.toml b/profiling/sound_wave_finite_difference_split_1_moment.toml index 1da0de40c..326b9927c 100644 --- a/profiling/sound_wave_finite_difference_split_1_moment.toml +++ b/profiling/sound_wave_finite_difference_split_1_moment.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 81 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 241 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[z] +ngrid = 81 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 241 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_finite_difference_split_2_moments.toml b/profiling/sound_wave_finite_difference_split_2_moments.toml index 103855ee7..9d82d9257 100644 --- a/profiling/sound_wave_finite_difference_split_2_moments.toml +++ b/profiling/sound_wave_finite_difference_split_2_moments.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 81 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 241 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[z] +ngrid = 81 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 241 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [timestepping] nstep = 100 diff --git a/profiling/sound_wave_finite_difference_split_3_moments.toml b/profiling/sound_wave_finite_difference_split_3_moments.toml index 6813dc3b6..24530c809 100644 --- a/profiling/sound_wave_finite_difference_split_3_moments.toml +++ b/profiling/sound_wave_finite_difference_split_3_moments.toml @@ -25,15 +25,19 @@ z_IC_temperature_amplitude2 = 0.5 z_IC_temperature_phase2 = 0.0 charge_exchange_frequency = 0.6283185307179586 ionization_frequency = 0.0 -z_ngrid = 81 -z_nelement = 1 -z_bc = "periodic" -z_discretization = "finite_difference" -vpa_ngrid = 241 -vpa_nelement = 1 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "finite_difference" + +[z] +ngrid = 81 +nelement = 1 +bc = "periodic" +discretization = "finite_difference" + +[vpa] +ngrid = 241 +nelement = 1 +L = 8.0 +bc = "periodic" +discretization = "finite_difference" [timestepping] nstep = 100 diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/plot_dispersion_relation.jl b/publication_inputs/2023_EFTC_jto-poster/sound-wave/plot_dispersion_relation.jl index 81b4e7fc9..110844dc9 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/plot_dispersion_relation.jl +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/plot_dispersion_relation.jl @@ -293,7 +293,7 @@ end function get_sim_omega_gamma(sim) try s = nothing - open(joinpath("..", "..", sim["base_directory"], sim["run_name"], basename(sim["run_name"]) * ".frequency_fit.txt"), + open(joinpath("..", "..", sim["output"]["base_directory"], sim["output"]["run_name"], basename(sim["output"]["run_name"]) * ".frequency_fit.txt"), "r") do io s = split(readline(io)) end @@ -310,7 +310,7 @@ function get_sim_omega_gamma(sim) return omega, gamma catch e - println("Error for ", sim["run_name"], " ", e) + println("Error for ", sim["output"]["run_name"], " ", e) return NaN, NaN end end @@ -322,7 +322,7 @@ function plot_sim_output!(ax_omega, ax_gamma, sims, ni, nn, Th, Te; kwargs...) omega = zeros(length(sims)) gamma = zeros(length(sims)) for (i, s) ∈ enumerate(sims) - Ri[i] = s["charge_exchange_frequency"] + Ri[i] = s["reactions"]["charge_exchange_frequency"] omega[i], gamma[i] = get_sim_omega_gamma(s) end diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25.toml index 1326c87f1..ef16d2b89 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.25 -initial_density2 = 1.0 -initial_temperature2 = 0.25 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 4.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 4.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.004 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split1.toml index 504d09589..5ac6820c9 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split1.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.25 -initial_density2 = 1.0 -initial_temperature2 = 0.25 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 4.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 4.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.004 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split2.toml index 1ab1b753d..8a75ac738 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split2.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.25 -initial_density2 = 1.0 -initial_temperature2 = 0.25 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 4.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 4.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 4.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.004 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split3.toml index fb6e88def..c111cc009 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.25_split3.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.25 -initial_density2 = 1.0 -initial_temperature2 = 0.25 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.25 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.004 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5.toml index 782281348..77717feea 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.5 -initial_density2 = 1.0 -initial_temperature2 = 0.5 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 5.65685424949238 # 8/sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 5.65685424949238 # 8/sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.00282842712474619 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split1.toml index b1c49ec79..783b9071b 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split1.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.5 -initial_density2 = 1.0 -initial_temperature2 = 0.5 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 5.65685424949238 # 8/sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 5.65685424949238 # 8/sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.00282842712474619 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split2.toml index 71927242e..afb97b3e2 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split2.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.5 -initial_density2 = 1.0 -initial_temperature2 = 0.5 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 5.65685424949238 # 8/sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 5.65685424949238 # 8/sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 5.65685424949238 # 8/sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.00282842712474619 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split3.toml index bfc24253b..7306f9af0 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T0.5_split3.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 0.5 -initial_density2 = 1.0 -initial_temperature2 = 0.5 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 0.5 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1500 dt = 0.00282842712474619 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1.toml index 6a520568f..7cfd8c368 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 0.002 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split1.toml index 37bbb8379..e76b33bfb 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split1.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 0.002 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split2.toml index acb8fae9a..1290a8c0a 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split2.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 0.002 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split3.toml index 6d6ee0b12..669bcda72 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T1_split3.toml @@ -1,52 +1,71 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 0.002 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2.toml index b3821d3d0..93444128c 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2.toml @@ -1,54 +1,73 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 2.0 -initial_density2 = 1.0 -initial_temperature2 = 2.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[z_IC_ion_species_1] +initialization_option1 = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0, 6.3, 6.6, 6.9, 7.2, 7.5, 7.8, 8.1, 8.4, 8.7] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 11.313708498984761 # = 8*sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 11.313708498984761 # = 8*sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1800 dt = 0.001414213562373095 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split1.toml index 45637d5c2..1a74238dd 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split1.toml @@ -1,54 +1,73 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 2.0 -initial_density2 = 1.0 -initial_temperature2 = 2.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0, 6.3, 6.6, 6.9, 7.2, 7.5, 7.8, 8.1, 8.4, 8.7] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 11.313708498984761 # = 8*sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 11.313708498984761 # = 8*sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1800 dt = 0.001414213562373095 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split2.toml index be029379d..4cc7cff2f 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split2.toml @@ -1,54 +1,73 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 2.0 -initial_density2 = 1.0 -initial_temperature2 = 2.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0, 6.3, 6.6, 6.9, 7.2, 7.5, 7.8, 8.1, 8.4, 8.7] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 11.313708498984761 # = 8*sqrt(2) -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 11.313708498984761 # = 8*sqrt(2) -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 11.313708498984761 # = 8*sqrt(2) +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1800 dt = 0.001414213562373095 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split3.toml index ea349b6f9..cb3acd490 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T2_split3.toml @@ -1,54 +1,73 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 2.0 -initial_density2 = 1.0 -initial_temperature2 = 2.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 2.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0, 6.3, 6.6, 6.9, 7.2, 7.5, 7.8, 8.1, 8.4, 8.7] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 1800 dt = 0.001414213562373095 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4.toml index acb50aee4..658527119 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4.toml @@ -1,55 +1,74 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 4.0 -initial_density2 = 1.0 -initial_temperature2 = 4.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0, 6.4, 6.8, 7.2, 7.6, 8.0, 8.4, 8.8, 9.2, 9.6, 10.0, 10.4, 10.8, 11.2, 11.6, 12.0, 12.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 16.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 16.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 3000 dt = 1.0e-3 nwrite = 20 #nwrite_dfns = 20 #80 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split1.toml index 8d593b0c5..9f2f411bf 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split1.toml @@ -1,55 +1,74 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 4.0 -initial_density2 = 1.0 -initial_temperature2 = 4.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0, 6.4, 6.8, 7.2, 7.6, 8.0, 8.4, 8.8, 9.2, 9.6, 10.0, 10.4, 10.8, 11.2, 11.6, 12.0, 12.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 16.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 16.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 3000 dt = 1.0e-3 nwrite = 20 #nwrite_dfns = 20 #80 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split2.toml index 50351e929..aba4c978c 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split2.toml @@ -1,55 +1,74 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 4.0 -initial_density2 = 1.0 -initial_temperature2 = 4.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0, 6.4, 6.8, 7.2, 7.6, 8.0, 8.4, 8.8, 9.2, 9.6, 10.0, 10.4, 10.8, 11.2, 11.6, 12.0, 12.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 16.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 16.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 16.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 3000 dt = 1.0e-3 nwrite = 20 #nwrite_dfns = 20 #80 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split3.toml index 45420535f..8e6719274 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_T4_split3.toml @@ -1,55 +1,74 @@ -#combine_outer = ["charge_exchange_frequency"] +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = 1.0 -initial_temperature1 = 4.0 -initial_density2 = 1.0 -initial_temperature2 = 4.0 -z_IC_option1 = "sinusoid" -#z_IC_density_amplitude1 = 0.001 -z_IC_density_amplitude1 = 0.01 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -#z_IC_density_amplitude2 = 0.001 -z_IC_density_amplitude2 = 0.01 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 4.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +#density_amplitude = 0.001 +density_amplitude = 0.01 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0, 6.4, 6.8, 7.2, 7.6, 8.0, 8.4, 8.8, 9.2, 9.6, 10.0, 10.4, 10.8, 11.2, 11.6, 12.0, 12.4] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 3000 dt = 1.0e-3 nwrite = 20 #nwrite_dfns = 20 #80 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio.toml index 4ea96b399..eae8fde3f 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio.toml @@ -1,52 +1,73 @@ combine_outer = ["charge_exchange_frequency"] + +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] -initial_temperature1 = 1.0 -initial_density2 = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 2.0e-3 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split1.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split1.toml index 56130d08c..7159cd582 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split1.toml @@ -1,52 +1,73 @@ combine_outer = ["charge_exchange_frequency"] + +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] -initial_temperature1 = 1.0 -initial_density2 = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 2.0e-3 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split2.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split2.toml index 894acd85b..72ad80657 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split2.toml @@ -1,52 +1,73 @@ combine_outer = ["charge_exchange_frequency"] + +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] -initial_temperature1 = 1.0 -initial_density2 = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[z_IC_ion_species_1] +initial_density = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +pa_ngrid = 17 +pa_nelement = 8 +pa_L = 8.0 +pa_bc = "periodic" +pa_discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 dt = 2.0e-3 nwrite = 20 -n_rk_stages = 4 split_operators = false diff --git a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split3.toml b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split3.toml index 4550dd608..057498646 100644 --- a/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/sound-wave/scan_sound-wave_nratio_split3.toml @@ -1,48 +1,70 @@ combine_outer = ["charge_exchange_frequency"] + +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true T_e = 1.0 -initial_density1 = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] -initial_temperature1 = 1.0 -initial_density2 = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] -initial_temperature2 = 1.0 -z_IC_option1 = "sinusoid" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 0.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -z_IC_option2 = "sinusoid" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = 0.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 + +[ion_species_1] +initial_density = [1.0e-5, 0.5, 1.0, 1.5, 1.99999] +initial_temperature = 1.0 + +[neutral_species_1] +initial_density = [1.99999, 1.5, 1.0, 0.5, 1.0e-5] +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[z_IC_neutral_species_1] +initialization_option = "sinusoid" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6.0, 6.2] ionization_frequency = 0.0 -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 17 -z_nelement = 2 -z_bc = "periodic" -z_discretization = "chebyshev_pseudospectral" -vpa_ngrid = 17 -vpa_nelement = 8 -vpa_L = 8.0 -vpa_bc = "periodic" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 17 -vz_nelement = 8 -vz_L = 8.0 -vz_bc = "periodic" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 17 +nelement = 2 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vpa] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 17 +nelement = 8 +L = 8.0 +bc = "periodic" +discretization = "chebyshev_pseudospectral" [timestepping] nstep = 2500 diff --git a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5.toml b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5.toml index 8943ac402..c0170bc2f 100644 --- a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5.toml +++ b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5.toml @@ -1,70 +1,94 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = false -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true recycling_fraction = 0.5 -krook_collisions_option = "reference_parameters" T_e = 0.2 # 1.0 T_wall = 0.1 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -z_IC_option1 = "gaussian" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 1.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -vpa_IC_option1 = "gaussian" -vpa_IC_density_amplitude1 = 1.0 -vpa_IC_density_phase1 = 0.0 -vpa_IC_upar_amplitude1 = 0.0 -vpa_IC_upar_phase1 = 0.0 -vpa_IC_temperature_amplitude1 = 0.0 -vpa_IC_temperature_phase1 = 0.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option2 = "gaussian" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = -1.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 -vpa_IC_option2 = "gaussian" -vpa_IC_density_amplitude2 = 1.0 -vpa_IC_density_phase2 = 0.0 -vpa_IC_upar_amplitude2 = 0.0 -vpa_IC_upar_phase2 = 0.0 -vpa_IC_temperature_amplitude2 = 0.0 -vpa_IC_temperature_phase2 = 0.0 + +[krook_collisions] +use_krook = true +frequency_option = "reference_parameters" + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vpa_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = -1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vz_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = false +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [timestepping] #nstep = 50000 @@ -72,10 +96,11 @@ nstep = 1000000 dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 -n_rk_stages = 4 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split1.toml b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split1.toml index f7a1484d7..7aaa02aa8 100644 --- a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split1.toml +++ b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split1.toml @@ -1,70 +1,94 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = false -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true recycling_fraction = 0.5 -krook_collisions_option = "reference_parameters" T_e = 0.2 # 1.0 T_wall = 0.1 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -z_IC_option1 = "gaussian" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 1.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -vpa_IC_option1 = "gaussian" -vpa_IC_density_amplitude1 = 1.0 -vpa_IC_density_phase1 = 0.0 -vpa_IC_upar_amplitude1 = 0.0 -vpa_IC_upar_phase1 = 0.0 -vpa_IC_temperature_amplitude1 = 0.0 -vpa_IC_temperature_phase1 = 0.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option2 = "gaussian" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = -1.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 -vpa_IC_option2 = "gaussian" -vpa_IC_density_amplitude2 = 1.0 -vpa_IC_density_phase2 = 0.0 -vpa_IC_upar_amplitude2 = 0.0 -vpa_IC_upar_phase2 = 0.0 -vpa_IC_temperature_amplitude2 = 0.0 -vpa_IC_temperature_phase2 = 0.0 + +[krook_collisions] +use_krook = true +frequency_option = "reference_parameters" + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vpa_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = -1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vz_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = false +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [timestepping] #nstep = 50000 @@ -72,10 +96,11 @@ nstep = 1000000 dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 -n_rk_stages = 4 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split2.toml b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split2.toml index ef1a221cb..ddd5151b2 100644 --- a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split2.toml +++ b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split2.toml @@ -1,70 +1,94 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = false -evolve_moments_conservation = true recycling_fraction = 0.5 -krook_collisions_option = "reference_parameters" T_e = 0.2 # 1.0 T_wall = 0.1 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -z_IC_option1 = "gaussian" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 1.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -vpa_IC_option1 = "gaussian" -vpa_IC_density_amplitude1 = 1.0 -vpa_IC_density_phase1 = 0.0 -vpa_IC_upar_amplitude1 = 0.0 -vpa_IC_upar_phase1 = 0.0 -vpa_IC_temperature_amplitude1 = 0.0 -vpa_IC_temperature_phase1 = 0.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option2 = "gaussian" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = -1.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 -vpa_IC_option2 = "gaussian" -vpa_IC_density_amplitude2 = 1.0 -vpa_IC_density_phase2 = 0.0 -vpa_IC_upar_amplitude2 = 0.0 -vpa_IC_upar_phase2 = 0.0 -vpa_IC_temperature_amplitude2 = 0.0 -vpa_IC_temperature_phase2 = 0.0 + +[krook_collisions] +use_krook = true +frequency_option = "reference_parameters" + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vpa_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = -1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vz_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 18.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 18.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = false +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 18.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [timestepping] #nstep = 50000 @@ -72,10 +96,11 @@ nstep = 1000000 dt = 3.0e-5 nwrite = 10000 nwrite_dfns = 10000 -n_rk_stages = 4 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split3.toml b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split3.toml index 79c01a3be..2b1fed262 100644 --- a/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split3.toml +++ b/publication_inputs/2023_EFTC_jto-poster/wall-bc/wall-bc_recyclefraction0.5_split3.toml @@ -1,70 +1,94 @@ -steady_state_residual = true -converged_residual_value = 1.0e-3 -#runtime_plots = true +[composition] n_ion_species = 1 n_neutral_species = 1 boltzmann_electron_response = true -evolve_moments_density = true -evolve_moments_parallel_flow = true -evolve_moments_parallel_pressure = true -evolve_moments_conservation = true recycling_fraction = 0.5 -krook_collisions_option = "reference_parameters" T_e = 0.2 # 1.0 T_wall = 0.1 -initial_density1 = 1.0 -initial_temperature1 = 1.0 -z_IC_option1 = "gaussian" -z_IC_density_amplitude1 = 0.001 -z_IC_density_phase1 = 0.0 -z_IC_upar_amplitude1 = 1.0 -z_IC_upar_phase1 = 0.0 -z_IC_temperature_amplitude1 = 0.0 -z_IC_temperature_phase1 = 0.0 -vpa_IC_option1 = "gaussian" -vpa_IC_density_amplitude1 = 1.0 -vpa_IC_density_phase1 = 0.0 -vpa_IC_upar_amplitude1 = 0.0 -vpa_IC_upar_phase1 = 0.0 -vpa_IC_temperature_amplitude1 = 0.0 -vpa_IC_temperature_phase1 = 0.0 -initial_density2 = 1.0 -initial_temperature2 = 1.0 -z_IC_option2 = "gaussian" -z_IC_density_amplitude2 = 0.001 -z_IC_density_phase2 = 0.0 -z_IC_upar_amplitude2 = -1.0 -z_IC_upar_phase2 = 0.0 -z_IC_temperature_amplitude2 = 0.0 -z_IC_temperature_phase2 = 0.0 -vpa_IC_option2 = "gaussian" -vpa_IC_density_amplitude2 = 1.0 -vpa_IC_density_phase2 = 0.0 -vpa_IC_upar_amplitude2 = 0.0 -vpa_IC_upar_phase2 = 0.0 -vpa_IC_temperature_amplitude2 = 0.0 -vpa_IC_temperature_phase2 = 0.0 + +[krook_collisions] +use_krook = true +frequency_option = "reference_parameters" + +[ion_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = 1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vpa_IC_ion_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[neutral_species_1] +initial_density = 1.0 +initial_temperature = 1.0 + +[z_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 0.001 +density_phase = 0.0 +upar_amplitude = -1.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[vz_IC_neutral_species_1] +initialization_option = "gaussian" +density_amplitude = 1.0 +density_phase = 0.0 +upar_amplitude = 0.0 +upar_phase = 0.0 +temperature_amplitude = 0.0 +temperature_phase = 0.0 + +[reactions] charge_exchange_frequency = 0.75 ionization_frequency = 0.5 -constant_ionization_rate = false -r_ngrid = 1 -r_nelement = 1 -z_ngrid = 9 -z_nelement = 32 -z_nelement_local = 4 -z_bc = "wall" -z_discretization = "chebyshev_pseudospectral" -z_element_spacing_option = "sqrt" -vpa_ngrid = 10 -vpa_nelement = 63 -vpa_L = 36.0 -vpa_bc = "zero" -vpa_discretization = "chebyshev_pseudospectral" -vz_ngrid = 10 -vz_nelement = 63 -vz_L = 36.0 -vz_bc = "zero" -vz_discretization = "chebyshev_pseudospectral" + +[evolve_moments] +density = true +parallel_flow = true +parallel_pressure = true +moments_conservation = true + +[r] +ngrid = 1 +nelement = 1 + +[z] +ngrid = 9 +nelement = 32 +nelement_local = 4 +bc = "wall" +discretization = "chebyshev_pseudospectral" +element_spacing_option = "sqrt" + +[vpa] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" + +[vz] +ngrid = 10 +nelement = 63 +L = 36.0 +bc = "zero" +discretization = "chebyshev_pseudospectral" [timestepping] #nstep = 50000 @@ -72,10 +96,11 @@ nstep = 1000000 dt = 1.0e-5 nwrite = 10000 nwrite_dfns = 10000 -n_rk_stages = 4 split_operators = false +steady_state_residual = true +converged_residual_value = 1.0e-3 -[ion_source] +[ion_source_1] active = true z_profile = "gaussian" z_width = 0.125 diff --git a/test_scripts/2D_FEM_assembly_test.jl b/test_scripts/2D_FEM_assembly_test.jl index 6dcfec726..bdb499490 100644 --- a/test_scripts/2D_FEM_assembly_test.jl +++ b/test_scripts/2D_FEM_assembly_test.jl @@ -7,11 +7,10 @@ using Measures using Dates import moment_kinetics using moment_kinetics.array_allocation: allocate_float, allocate_shared_float -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.chebyshev: setup_chebyshev_pseudospectral using moment_kinetics.gauss_legendre: setup_gausslegendre_pseudospectral, get_QQ_local! -using moment_kinetics.type_definitions: mk_float, mk_int +using moment_kinetics.type_definitions: mk_float, mk_int, OptionsDict using moment_kinetics.fokker_planck: init_fokker_planck_collisions_weak_form using moment_kinetics.fokker_planck: fokker_planck_collision_operator_weak_form! using moment_kinetics.fokker_planck: conserving_corrections! @@ -96,31 +95,29 @@ end # fd_option and adv_input not actually used so given values unimportant #discretization = "chebyshev_pseudospectral" discretization = "gausslegendre_pseudospectral" - fd_option = "fourth_order_centered" - cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = MPI.COMM_NULL - # create the 'input' struct containing input info needed to create a - # coordinate element_spacing_option = "uniform" - vpa_input = grid_input("vpa", ngrid, nelement_global_vpa, nelement_local_vpa, - nrank, irank, Lvpa, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - vperp_input = grid_input("vperp", ngrid, nelement_global_vperp, nelement_local_vperp, - nrank, irank, Lvperp, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - # create the coordinate struct 'x' - println("made inputs") - println("vpa: ngrid: ",ngrid," nelement: ",nelement_local_vpa, " Lvpa: ",Lvpa) - println("vperp: ngrid: ",ngrid," nelement: ",nelement_local_vperp, " Lvperp: ",Lvperp) # Set up MPI if standalone initialize_comms!() end setup_distributed_memory_MPI(1,1,1,1) - vpa, vpa_spectral = define_coordinate(vpa_input) - vperp, vperp_spectral = define_coordinate(vperp_input) + coords_input = OptionsDict( + "vperp"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global_vperp, + "nelement_local"=>nelement_local_vperp, "L"=>Lvperp, + "discretization"=>discretization, + "element_spacing_option"=>element_spacing_option), + "vpa"=>OptionsDict("ngrid"=>ngrid, "nelement"=>nelement_global_vpa, + "nelement_local"=>nelement_local_vpa, "L"=>Lvpa, + "discretization"=>discretization, + "element_spacing_option"=>element_spacing_option), + ) + println("made inputs") + println("vpa: ngrid: ",ngrid," nelement: ",nelement_local_vpa, " Lvpa: ",Lvpa) + println("vperp: ngrid: ",ngrid," nelement: ",nelement_local_vperp, " Lvperp: ",Lvperp) + # create the coordinate structs + vperp, vperp_spectral = define_coordinate(coords_input, "vperp") + vpa, vpa_spectral = define_coordinate(coords_input, "vpa") looping.setup_loop_ranges!(block_rank[], block_size[]; s=1, sn=1, r=1, z=1, vperp=vperp.n, vpa=vpa.n, diff --git a/test_scripts/GaussLobattoLegendre_test.jl b/test_scripts/GaussLobattoLegendre_test.jl index 80b865716..74292aa1e 100644 --- a/test_scripts/GaussLobattoLegendre_test.jl +++ b/test_scripts/GaussLobattoLegendre_test.jl @@ -1,8 +1,6 @@ export gausslegendre_test -using FastGaussQuadrature -using LegendrePolynomials: Pl -using LinearAlgebra: mul!, lu, inv, cond +using LinearAlgebra: mul!, cond, ldiv! using Printf using Plots using LaTeXStrings @@ -11,10 +9,10 @@ using Measures import moment_kinetics using moment_kinetics.gauss_legendre -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.calculus: derivative!, second_derivative!, laplacian_derivative! using moment_kinetics.calculus: mass_matrix_solve! +using moment_kinetics.type_definitions: OptionsDict function print_matrix(matrix,name,n,m) @@ -44,33 +42,35 @@ using moment_kinetics.calculus: mass_matrix_solve! #nelement = 4 y_ngrid = ngrid #number of points per element y_nelement_local = nelement # number of elements per rank - y_nelement_global = y_nelement_local # total number of elements - bc = "zero" + y_nelement_global = y_nelement_local # total number of elements discretization = "gausslegendre_pseudospectral" # fd_option and adv_input not actually used so given values unimportant - fd_option = "fourth_order_centered" - cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0#1 - comm = MPI.COMM_NULL element_spacing_option = "uniform" # create the 'input' struct containing input info needed to create a # coordinate - for y_name in ["vpa","vperp"] + for y_name in ["vpa","vperp","z"] println("") println("$y_name test") println("") if y_name == "vperp" - y_L = L_in #physical box size in reference units - else + y_L = L_in #physical box size in reference units + bc = "zero" + elseif y_name =="vpa" y_L = 2*L_in + bc = "zero" + elseif y_name == "z" + y_L = L_in + bc = "periodic" end - y_input = grid_input(y_name, y_ngrid, y_nelement_global, y_nelement_local, - nrank, irank, y_L, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - - # create the coordinate structs - y, y_spectral = define_coordinate(y_input,init_YY=false) + input = OptionsDict(y_name => OptionsDict("ngrid"=>y_ngrid, "nelement"=>y_nelement_global, + "nelement_local"=>y_nelement_local, "L"=>y_L, + "discretization"=>discretization, + "element_spacing_option"=>element_spacing_option, + "bc"=>bc)) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + y, y_spectral = define_coordinate(input, y_name; collision_operator_dim=true, ignore_MPI=true) #print_matrix(Mmat,"Mmat",y.n,y.n) #print_matrix(y_spectral.radau.M0,"local radau mass matrix M0",y.ngrid,y.ngrid) #print_matrix(y_spectral.radau.M1,"local radau mass matrix M1",y.ngrid,y.ngrid) @@ -96,11 +96,15 @@ using moment_kinetics.calculus: mass_matrix_solve! #print_vector(y_spectral.lobatto.D0,"local lobatto D matrix D0",y.ngrid) f_exact = Array{Float64,1}(undef,y.n) + f_num = Array{Float64,1}(undef,y.n) + f_err = Array{Float64,1}(undef,y.n) df_exact = Array{Float64,1}(undef,y.n) df_num = Array{Float64,1}(undef,y.n) df_err = Array{Float64,1}(undef,y.n) g_exact = Array{Float64,1}(undef,y.n) h_exact = Array{Float64,1}(undef,y.n) + h_num = Array{Float64,1}(undef,y.n) + h_err = Array{Float64,1}(undef,y.n) divg_exact = Array{Float64,1}(undef,y.n) divg_num = Array{Float64,1}(undef,y.n) divg_err = Array{Float64,1}(undef,y.n) @@ -110,6 +114,12 @@ using moment_kinetics.calculus: mass_matrix_solve! d2f_exact = Array{Float64,1}(undef,y.n) d2f_num = Array{Float64,1}(undef,y.n) d2f_err = Array{Float64,1}(undef,y.n) + fperiodic_err = Array{Float64,1}(undef,y.n) + fperiodic_num = Array{Float64,1}(undef,y.n) + fperiodic_exact = Array{Float64,1}(undef,y.n) + d2fperiodic_exact = Array{Float64,1}(undef,y.n) + d2fperiodic_num = Array{Float64,1}(undef,y.n) + d2fperiodic_err = Array{Float64,1}(undef,y.n) b = Array{Float64,1}(undef,y.n) for iy in 1:y.n f_exact[iy] = exp(-y.grid[iy]^2) @@ -124,28 +134,32 @@ using moment_kinetics.calculus: mass_matrix_solve! #h_exact[iy] = exp(-y.grid[iy]^3) #laph_exact[iy] = 9.0*y.grid[iy]*(y.grid[iy]^3 - 1.0)*exp(-y.grid[iy]^3) #f_exact[iy] = -2.0*y.grid[iy]*exp(-y.grid[iy]^2) - - end - if y.name == "vpa" - F_exact = sqrt(pi) - elseif y.name == "vperp" - F_exact = 1.0 + fperiodic_exact[iy] = sin(2.0*pi*y.grid[iy]/y.L) + d2fperiodic_exact[iy] = -((2.0*pi/y.L)^2)*sin(2.0*pi*y.grid[iy]/y.L) end - # do a test integration - #println(f_exact) - F_num = sum(y.wgts.*f_exact) - F_err = abs(F_num - F_exact) - #for ix in 1:ngrid - # F_num += w[ix]*df_exact[ix] - #end - println("F_err: ", F_err, " F_exact: ",F_exact, " F_num: ", F_num) - derivative!(df_num, f_exact, y, y_spectral) - @. df_err = df_num - df_exact - println("max(df_err) (interpolation): ",maximum(df_err)) - derivative!(d2f_num, df_num, y, y_spectral) - @. d2f_err = d2f_num - d2f_exact - println("max(d2f_err) (double first derivative by interpolation): ",maximum(d2f_err)) + if y.name in ["vpa","vperp"] + if y.name == "vpa" + F_exact = sqrt(pi) + elseif y.name == "vperp" + F_exact = 1.0 + end + # do a test integration + #println(f_exact) + F_num = sum(y.wgts.*f_exact) + F_err = abs(F_num - F_exact) + #for ix in 1:ngrid + # F_num += w[ix]*df_exact[ix] + #end + println("F_err: ", F_err, " F_exact: ",F_exact, " F_num: ", F_num) + + derivative!(df_num, f_exact, y, y_spectral) + @. df_err = df_num - df_exact + println("max(df_err) (interpolation): ",maximum(df_err)) + derivative!(d2f_num, df_num, y, y_spectral) + @. d2f_err = d2f_num - d2f_exact + println("max(d2f_err) (double first derivative by interpolation): ",maximum(d2f_err)) + end if y.name == "vpa" mul!(b,y_spectral.S_matrix,f_exact) mass_matrix_solve!(df_num,b,y_spectral) @@ -164,6 +178,20 @@ using moment_kinetics.calculus: mass_matrix_solve! outfile = "vpa_test.pdf" savefig(outfile) + # test 1D ODE solve + # form RHS vector + mul!(b,y_spectral.mass_matrix,d2f_exact) + # Dirichlet zero BCs + b[1] = 0.0 + b[end] = 0.0 + # solve ODE + ldiv!(f_num,y_spectral.L_matrix_lu,b) + @. f_err = abs(f_num - f_exact) + println("max(f_err) (weak form): ",maximum(f_err)) + plot([y.grid, y.grid], [f_num, f_exact], xlabel="vpa", label=["num" "exact"], ylabel="") + outfile = "vpa_test_ode.pdf" + savefig(outfile) + elseif y.name == "vperp" #println("condition: ",cond(y_spectral.mass_matrix)) mul!(b,y_spectral.S_matrix,g_exact) @@ -212,6 +240,40 @@ using moment_kinetics.calculus: mass_matrix_solve! @. laph_err = abs(laph_num - laph_exact) println("max(laph_err) (interpolation): ",maximum(laph_err)) + # test 1D ODE solve + # form RHS vector + mul!(b,y_spectral.mass_matrix,laph_exact) + # Dirichlet zero BC at upper endpoint + b[end] = 0.0 + # solve ODE + ldiv!(h_num,y_spectral.L_matrix_lu,b) + @. h_err = abs(h_num - h_exact) + println("max(h_err) (weak form): ",maximum(h_err)) + plot([y.grid, y.grid], [h_num, h_exact], xlabel="vperp", label=["num" "exact"], ylabel="") + outfile = "vperp_test_ode.pdf" + savefig(outfile) + elseif y.name == "z" + # test 1D differentiation + second_derivative!(d2fperiodic_num, fperiodic_exact, y, y_spectral) + @. d2fperiodic_err = abs(d2fperiodic_num - d2fperiodic_exact) + println("max(d2fperiodic_err) (weak form): ",maximum(d2fperiodic_err)) + + # test 1D ODE solve + # form RHS vector + mul!(b,y_spectral.mass_matrix,d2fperiodic_exact) + b[1] = 0.0 # fixes constant piece of solution + b[end] = 0.0 # makes sure periodicity is enforced + # solve ODE + ldiv!(fperiodic_num,y_spectral.L_matrix_lu,b) + ## subtract constant piece (constant offset is allowed solution) + #F_num = sum(y.wgts.*fperiodic_num)/sum(y.wgts) + #@. fperiodic_num -= F_num + @. fperiodic_err = abs(fperiodic_num - fperiodic_exact) + println("max(fperiodic_err) (weak form): ",maximum(fperiodic_err)) + plot([y.grid, y.grid], [fperiodic_num, fperiodic_exact], xlabel="z", label=["num" "exact"], ylabel="") + outfile = "periodic_test_ode.pdf" + savefig(outfile) + end end end diff --git a/test_scripts/cheb_matrix_test.jl b/test_scripts/cheb_matrix_test.jl index 9c6324ecd..311611c1d 100644 --- a/test_scripts/cheb_matrix_test.jl +++ b/test_scripts/cheb_matrix_test.jl @@ -4,676 +4,648 @@ using LaTeXStrings using MPI using Measures -if abspath(PROGRAM_FILE) == @__FILE__ - using Pkg - Pkg.activate(".") +using Pkg +Pkg.activate(".") - import moment_kinetics - using moment_kinetics.input_structs: grid_input, advection_input - using moment_kinetics.coordinates: define_coordinate - using moment_kinetics.chebyshev: setup_chebyshev_pseudospectral, chebyshev_radau_derivative_single_element! - using moment_kinetics.calculus: derivative!, integral - #import LinearAlgebra - #using IterativeSolvers: jacobi!, gauss_seidel!, idrs! - using LinearAlgebra: mul!, lu, cond, det - using SparseArrays: sparse - using SpecialFunctions: erf - zero = 1.0e-10 - - function print_matrix(matrix,name,n,m) - println("\n ",name," \n") - for i in 1:n - for j in 1:m - @printf("%.1f ", matrix[i,j]) - end - println("") - end - println("\n") - end - - function print_vector(vector,name,m) - println("\n ",name," \n") +import moment_kinetics + using moment_kinetics.coordinates: define_coordinate + using moment_kinetics.chebyshev: setup_chebyshev_pseudospectral, chebyshev_radau_derivative_single_element! + using moment_kinetics.calculus: derivative!, integral +using moment_kinetics.type_definitions: OptionsDict +#import LinearAlgebra +#using IterativeSolvers: jacobi!, gauss_seidel!, idrs! +using LinearAlgebra: mul!, lu, cond, det +using SparseArrays: sparse +using SpecialFunctions: erf +zero = 1.0e-10 + +function print_matrix(matrix,name,n,m) + println("\n ",name," \n") + for i in 1:n for j in 1:m - @printf("%.3f ", vector[j]) + @printf("%.1f ", matrix[i,j]) end println("") - println("\n") - end - - function Djj(x::Array{Float64,1},j::Int64) - return -0.5*x[j]/( 1.0 - x[j]^2) end - function Djk(x::Array{Float64,1},j::Int64,k::Int64,c_j::Float64,c_k::Float64) - return (c_j/c_k)*((-1)^(k+j))/(x[j] - x[k]) + println("\n") +end + +function print_vector(vector,name,m) + println("\n ",name," \n") + for j in 1:m + @printf("%.3f ", vector[j]) end + println("") + println("\n") +end + +function Djj(x::Array{Float64,1},j::Int64) + return -0.5*x[j]/( 1.0 - x[j]^2) +end +function Djk(x::Array{Float64,1},j::Int64,k::Int64,c_j::Float64,c_k::Float64) + return (c_j/c_k)*((-1)^(k+j))/(x[j] - x[k]) +end + +""" +The function below is based on the numerical method outlined in +Chapter 8.2 from Trefethen 1994 +https://people.maths.ox.ac.uk/trefethen/8all.pdf +full list of Chapters may be obtained here +https://people.maths.ox.ac.uk/trefethen/pdetext.html +""" + +function cheb_derivative_matrix!(D::Array{Float64,2},x::Array{Float64,1},n) + D[:,:] .= 0.0 - """ - The function below is based on the numerical method outlined in - Chapter 8.2 from Trefethen 1994 - https://people.maths.ox.ac.uk/trefethen/8all.pdf - full list of Chapters may be obtained here - https://people.maths.ox.ac.uk/trefethen/pdetext.html - """ + # top left, bottom right + D[1,1] = (2.0*(n - 1.0)^2 + 1.0)/6.0 + D[n,n] = -(2.0*(n - 1.0)^2 + 1.0)/6.0 - function cheb_derivative_matrix!(D::Array{Float64,2},x::Array{Float64,1},n) - D[:,:] .= 0.0 - - # top left, bottom right - D[1,1] = (2.0*(n - 1.0)^2 + 1.0)/6.0 - D[n,n] = -(2.0*(n - 1.0)^2 + 1.0)/6.0 - - # top row - j = 1 - c_j = 2.0 - c_k = 1.0 - for k in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - k = n - c_k = 2.0 - D[j,k] = Djk(x,j,k,c_j,c_k) - - # bottom row - j = n - c_j = 2.0 - c_k = 1.0 - for k in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - k = 1 - c_k = 2.0 + # top row + j = 1 + c_j = 2.0 + c_k = 1.0 + for k in 2:n-1 D[j,k] = Djk(x,j,k,c_j,c_k) - - #left column - k = 1 - c_j = 1.0 - c_k = 2.0 - for j in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - - #right column - k = n - c_j = 1.0 - c_k = 2.0 - for j in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - - # interior rows and columns - for j in 2:n-1 - D[j,j] = Djj(x,j) - #D[j,j] = -0.5*x[j]/( 1.0 - x[j]^2) - for k in 2:n-1 - if j == k - continue - end - c_k = 1.0 - c_j = 1.0 - #D[j,k] = (c_j/c_k)*((-1)^(k+j))/(x[j] - x[k]) - D[j,k] = Djk(x,j,k,c_j,c_k) - end - end - end - - function cheb_derivative_matrix_reversed!(D::Array{Float64,2},x) - D_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - cheb_derivative_matrix_elementwise_reversed!(D_elementwise,x.ngrid,x.L,x.nelement_global) - if x.ngrid < 8 - println("\n D_elementwise \n") - for i in 1:x.ngrid - for j in 1:x.ngrid - @printf("%.1f ", D_elementwise[i,j]) - end - println("") - end - end - assign_cheb_derivative_matrix!(D,D_elementwise,x) end + k = n + c_k = 2.0 + D[j,k] = Djk(x,j,k,c_j,c_k) - function cheb_second_derivative_matrix_reversed!(D::Array{Float64,2},x) - D_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - cheb_derivative_matrix_elementwise_reversed!(D_elementwise,x.ngrid,x.L,x.nelement_global) - D2_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - mul!(D2_elementwise,D_elementwise,D_elementwise) - if x.ngrid < 8 - print_matrix(D2_elementwise,"D2_elementwise",x.ngrid,x.ngrid) - end - assign_cheb_derivative_matrix!(D,D2_elementwise,x) + # bottom row + j = n + c_j = 2.0 + c_k = 1.0 + for k in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) end + k = 1 + c_k = 2.0 + D[j,k] = Djk(x,j,k,c_j,c_k) - function assign_cheb_derivative_matrix!(D::Array{Float64,2},D_elementwise::Array{Float64,2},x) - - # zero output matrix before assignment - D[:,:] .= 0.0 - imin = x.imin - imax = x.imax - - zero_bc_upper_boundary = x.bc == "zero" || x.bc == "zero_upper" - zero_bc_lower_boundary = x.bc == "zero" || x.bc == "zero_lower" - - # fill in first element - j = 1 - if zero_bc_lower_boundary #x.bc == "zero" - D[imin[j],imin[j]:imax[j]] .+= D_elementwise[1,:]./2.0 #contributions from this element/2 - D[imin[j],imin[j]] += D_elementwise[x.ngrid,x.ngrid]/2.0 #contribution from missing `zero' element/2 - else - D[imin[j],imin[j]:imax[j]] .+= D_elementwise[1,:] - end - for k in 2:imax[j]-imin[j] - D[k,imin[j]:imax[j]] .+= D_elementwise[k,:] - end - if zero_bc_upper_boundary && x.nelement_local == 1 - D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 - D[imax[j],imax[j]] += D_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 - elseif x.nelement_local > 1 #x.bc == "zero" - D[imax[j],imin[j]:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 - else - D[imax[j],imin[j]:imax[j]] .+= D_elementwise[x.ngrid,:] - end - # remaining elements recalling definitions of imax and imin - for j in 2:x.nelement_local - #lower boundary condition on element - D[imin[j]-1,imin[j]-1:imax[j]] .+= D_elementwise[1,:]./2.0 - for k in 2:imax[j]-imin[j]+1 - D[k+imin[j]-2,imin[j]-1:imax[j]] .+= D_elementwise[k,:] - end - # upper boundary condition on element - if j == x.nelement_local && !(zero_bc_upper_boundary) - D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:] - elseif j == x.nelement_local && zero_bc_upper_boundary - D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 - D[imax[j],imax[j]] += D_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 - else - D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 - end - end - + #left column + k = 1 + c_j = 1.0 + c_k = 2.0 + for j in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) end - function cheb_derivative_matrix_elementwise_reversed!(D::Array{Float64,2},n::Int64,L::Float64,nelement::Int64) - - #define Chebyshev points in reversed order x_j = { -1, ... , 1} - x = Array{Float64,1}(undef,n) - for j in 1:n - x[j] = cospi((n-j)/(n-1)) - end - - # zero matrix before allocating values - D[:,:] .= 0.0 - - # top row - j = 1 - c_j = 2.0 - c_k = 1.0 - for k in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - k = n - c_k = 2.0 + #right column + k = n + c_j = 1.0 + c_k = 2.0 + for j in 2:n-1 D[j,k] = Djk(x,j,k,c_j,c_k) - - # bottom row - j = n - c_j = 2.0 - c_k = 1.0 + end + + # interior rows and columns + for j in 2:n-1 + D[j,j] = Djj(x,j) + #D[j,j] = -0.5*x[j]/( 1.0 - x[j]^2) for k in 2:n-1 + if j == k + continue + end + c_k = 1.0 + c_j = 1.0 + #D[j,k] = (c_j/c_k)*((-1)^(k+j))/(x[j] - x[k]) D[j,k] = Djk(x,j,k,c_j,c_k) end - k = 1 - c_k = 2.0 - D[j,k] = Djk(x,j,k,c_j,c_k) - - #left column - k = 1 - c_j = 1.0 - c_k = 2.0 - for j in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - - #right column - k = n - c_j = 1.0 - c_k = 2.0 - for j in 2:n-1 - D[j,k] = Djk(x,j,k,c_j,c_k) - end - - - # top left, bottom right - #D[n,n] = (2.0*(n - 1.0)^2 + 1.0)/6.0 - #D[1,1] = -(2.0*(n - 1.0)^2 + 1.0)/6.0 - # interior rows and columns - for j in 2:n-1 - #D[j,j] = Djj(x,j) - for k in 2:n-1 - if j == k - continue - end - c_k = 1.0 - c_j = 1.0 - D[j,k] = Djk(x,j,k,c_j,c_k) + end +end + +function cheb_derivative_matrix_reversed!(D::Array{Float64,2},x) + D_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + cheb_derivative_matrix_elementwise_reversed!(D_elementwise,x.ngrid,x.L,x.nelement_global) + if x.ngrid < 8 + println("\n D_elementwise \n") + for i in 1:x.ngrid + for j in 1:x.ngrid + @printf("%.1f ", D_elementwise[i,j]) end + println("") end - - # calculate diagonal entries to guarantee that - # D * (1, 1, ..., 1, 1) = (0, 0, ..., 0, 0) - for j in 1:n - D[j,j] = -sum(D[j,:]) - end - - #multiply by scale factor for element length - D .= (2.0*float(nelement)/L).*D end + assign_cheb_derivative_matrix!(D,D_elementwise,x) +end + +function cheb_second_derivative_matrix_reversed!(D::Array{Float64,2},x) + D_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + cheb_derivative_matrix_elementwise_reversed!(D_elementwise,x.ngrid,x.L,x.nelement_global) + D2_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + mul!(D2_elementwise,D_elementwise,D_elementwise) + if x.ngrid < 8 + print_matrix(D2_elementwise,"D2_elementwise",x.ngrid,x.ngrid) + end + assign_cheb_derivative_matrix!(D,D2_elementwise,x) +end + +function assign_cheb_derivative_matrix!(D::Array{Float64,2},D_elementwise::Array{Float64,2},x) + + # zero output matrix before assignment + D[:,:] .= 0.0 + imin = x.imin + imax = x.imax - """ - derivative matrix for radau grid - """ - function calculate_chebyshev_radau_D_matrix_via_FFT!(D::Array{Float64,2}, coord, spectral) - ff_buffer = Array{Float64,1}(undef,coord.ngrid) - df_buffer = Array{Float64,1}(undef,coord.ngrid) - # use response matrix approach to calculate derivative matrix D - for j in 1:coord.ngrid - ff_buffer .= 0.0 - ff_buffer[j] = 1.0 - @views chebyshev_radau_derivative_single_element!(df_buffer[:], ff_buffer[:], - spectral.radau.f[:,1], spectral.radau.df, spectral.radau.fext, spectral.radau.forward, coord) - @. D[:,j] = df_buffer[:] # assign appropriate column of derivative matrix + zero_bc_upper_boundary = x.bc == "zero" || x.bc == "zero_upper" + zero_bc_lower_boundary = x.bc == "zero" || x.bc == "zero_lower" + + # fill in first element + j = 1 + if zero_bc_lower_boundary #x.bc == "zero" + D[imin[j],imin[j]:imax[j]] .+= D_elementwise[1,:]./2.0 #contributions from this element/2 + D[imin[j],imin[j]] += D_elementwise[x.ngrid,x.ngrid]/2.0 #contribution from missing `zero' element/2 + else + D[imin[j],imin[j]:imax[j]] .+= D_elementwise[1,:] + end + for k in 2:imax[j]-imin[j] + D[k,imin[j]:imax[j]] .+= D_elementwise[k,:] + end + if zero_bc_upper_boundary && x.nelement_local == 1 + D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 + D[imax[j],imax[j]] += D_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 + elseif x.nelement_local > 1 #x.bc == "zero" + D[imax[j],imin[j]:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 + else + D[imax[j],imin[j]:imax[j]] .+= D_elementwise[x.ngrid,:] + end + # remaining elements recalling definitions of imax and imin + for j in 2:x.nelement_local + #lower boundary condition on element + D[imin[j]-1,imin[j]-1:imax[j]] .+= D_elementwise[1,:]./2.0 + for k in 2:imax[j]-imin[j]+1 + D[k+imin[j]-2,imin[j]-1:imax[j]] .+= D_elementwise[k,:] end - # correct diagonal elements to gurantee numerical stability - # gives D*[1.0, 1.0, ... 1.0] = [0.0, 0.0, ... 0.0] - for j in 1:coord.ngrid - D[j,j] = 0.0 - D[j,j] = -sum(D[j,:]) + # upper boundary condition on element + if j == x.nelement_local && !(zero_bc_upper_boundary) + D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:] + elseif j == x.nelement_local && zero_bc_upper_boundary + D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 + D[imax[j],imax[j]] += D_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 + else + D[imax[j],imin[j]-1:imax[j]] .+= D_elementwise[x.ngrid,:]./2.0 end - - #multiply by scale factor for element length - D .= (2.0*float(coord.nelement_global)/coord.L).*D end - function cheb_radau_derivative_matrix_reversed!(D::Array{Float64,2},x,x_spectral) - D_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - cheb_derivative_matrix_elementwise_reversed!(D_lobotto_elementwise,x.ngrid,x.L,x.nelement_global) +end - D_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - calculate_chebyshev_radau_D_matrix_via_FFT!(D_radau_elementwise,x,x_spectral) - if x.ngrid < 8 - print_matrix(D_lobotto_elementwise,"D_lobotto_elementwise",x.ngrid,x.ngrid) - print_matrix(D_radau_elementwise,"D_radau_elementwise",x.ngrid,x.ngrid) - end - assign_cheb_derivative_matrix!(D,D_lobotto_elementwise,D_radau_elementwise,x) +function cheb_derivative_matrix_elementwise_reversed!(D::Array{Float64,2},n::Int64,L::Float64,nelement::Int64) + + #define Chebyshev points in reversed order x_j = { -1, ... , 1} + x = Array{Float64,1}(undef,n) + for j in 1:n + x[j] = cospi((n-j)/(n-1)) end - - function cheb_radau_second_derivative_matrix_reversed!(D::Array{Float64,2},x,x_spectral) - D_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - cheb_derivative_matrix_elementwise_reversed!(D_lobotto_elementwise,x.ngrid,x.L,x.nelement_global) - D2_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - mul!(D2_lobotto_elementwise,D_lobotto_elementwise,D_lobotto_elementwise) - - D_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - calculate_chebyshev_radau_D_matrix_via_FFT!(D_radau_elementwise,x,x_spectral) - D2_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) - mul!(D2_radau_elementwise,D_radau_elementwise,D_radau_elementwise) - - if x.ngrid < 8 - #print_matrix(D_lobotto_elementwise,"D_lobotto_elementwise",x.ngrid,x.ngrid) - print_matrix(D2_lobotto_elementwise,"D2_lobotto_elementwise",x.ngrid,x.ngrid) - #print_matrix(D_radau_elementwise,"D_radau_elementwise",x.ngrid,x.ngrid) - print_matrix(D2_radau_elementwise,"D2_radau_elementwise",x.ngrid,x.ngrid) - end - assign_cheb_derivative_matrix!(D,D2_lobotto_elementwise,D2_radau_elementwise,x) + + # zero matrix before allocating values + D[:,:] .= 0.0 + + # top row + j = 1 + c_j = 2.0 + c_k = 1.0 + for k in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) end + k = n + c_k = 2.0 + D[j,k] = Djk(x,j,k,c_j,c_k) + # bottom row + j = n + c_j = 2.0 + c_k = 1.0 + for k in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) + end + k = 1 + c_k = 2.0 + D[j,k] = Djk(x,j,k,c_j,c_k) - function assign_cheb_derivative_matrix!(D::Array{Float64,2},D_lobotto_elementwise::Array{Float64,2},D_radau_elementwise::Array{Float64,2},x) - - # zero output matrix before assignment - D[:,:] .= 0.0 - imin = x.imin - imax = x.imax - - zero_bc_upper_boundary = x.bc == "zero" || x.bc == "zero_upper" - zero_bc_lower_boundary = x.bc == "zero" || x.bc == "zero_lower" - - # fill in first element - j = 1 - if zero_bc_lower_boundary #x.bc == "zero" - D[imin[j],imin[j]:imax[j]] .+= D_radau_elementwise[1,:]./2.0 #contributions from this element/2 - D[imin[j],imin[j]] += D_radau_elementwise[x.ngrid,x.ngrid]/2.0 #contribution from missing `zero' element/2 - else - D[imin[j],imin[j]:imax[j]] .+= D_radau_elementwise[1,:] - end - for k in 2:imax[j]-imin[j] - D[k,imin[j]:imax[j]] .+= D_radau_elementwise[k,:] - end - if zero_bc_upper_boundary && x.nelement_local == 1 - D[imax[j],imin[j]-1:imax[j]] .+= D_radau_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 - D[imax[j],imax[j]] += D_lobotto_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 - elseif x.nelement_local > 1 #x.bc == "zero" - D[imax[j],imin[j]:imax[j]] .+= D_radau_elementwise[x.ngrid,:]./2.0 - else - D[imax[j],imin[j]:imax[j]] .+= D_radau_elementwise[x.ngrid,:] - end - # remaining elements recalling definitions of imax and imin - for j in 2:x.nelement_local - #lower boundary condition on element - D[imin[j]-1,imin[j]-1:imax[j]] .+= D_lobotto_elementwise[1,:]./2.0 - for k in 2:imax[j]-imin[j]+1 - D[k+imin[j]-2,imin[j]-1:imax[j]] .+= D_lobotto_elementwise[k,:] - end - # upper boundary condition on element - if j == x.nelement_local && !(zero_bc_upper_boundary) - D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:] - elseif j == x.nelement_local && zero_bc_upper_boundary - D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 - D[imax[j],imax[j]] += D_lobotto_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 - else - D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:]./2.0 - end - end - + #left column + k = 1 + c_j = 1.0 + c_k = 2.0 + for j in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) end - """ - function integrating d y / d t = f(t) - """ - function forward_euler_step!(ynew,yold,f,dt,n) - for i in 1:n - ynew[i] = yold[i] + dt*f[i] - end + #right column + k = n + c_j = 1.0 + c_k = 2.0 + for j in 2:n-1 + D[j,k] = Djk(x,j,k,c_j,c_k) end - """ - function creating lu object for A = I - dt*nu*D2 - """ - function diffusion_matrix(D2,n,dt,nu;return_A=false) - A = Array{Float64,2}(undef,n,n) - for i in 1:n - for j in 1:n - A[i,j] = - dt*nu*D2[i,j] + + + # top left, bottom right + #D[n,n] = (2.0*(n - 1.0)^2 + 1.0)/6.0 + #D[1,1] = -(2.0*(n - 1.0)^2 + 1.0)/6.0 + # interior rows and columns + for j in 2:n-1 + #D[j,j] = Djj(x,j) + for k in 2:n-1 + if j == k + continue end - A[i,i] += 1.0 - end - lu_obj = lu(A) - if return_A - return lu_obj, A - else - return lu_obj + c_k = 1.0 + c_j = 1.0 + D[j,k] = Djk(x,j,k,c_j,c_k) end end - """ - functions for Rosenbluth potential tests - """ - function dH_Maxwellian_dvpa(vpa,vperp,ivpa,ivperp) - # speed variable - eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) - zero = 1.0e-10 - if eta < zero - dHdvpa = -(4.0*vpa.grid[ivpa])/(3.0*sqrt(pi)) - else - dHdvpa = (vpa.grid[ivpa]/eta)*((2.0/sqrt(pi))*(exp(-eta^2)/eta) - (erf(eta)/(eta^2))) - end - return dHdvpa + # calculate diagonal entries to guarantee that + # D * (1, 1, ..., 1, 1) = (0, 0, ..., 0, 0) + for j in 1:n + D[j,j] = -sum(D[j,:]) end - function d2H_Maxwellian_dvpa2(vpa,vperp,ivpa,ivperp) - # speed variable - eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) - zero = 1.0e-10 - if eta < zero - dHdeta_over_eta = -4.0/(3.0*sqrt(pi)) - d2Hdeta2 = -4.0/(3.0*sqrt(pi)) - else - dHdeta_over_eta = (2.0/sqrt(pi))*(exp(-eta^2)/eta^2) - (erf(eta)/(eta^3)) - d2Hdeta2 = 2.0*(erf(eta)/(eta^3)) - (4.0/sqrt(pi))*(1.0 + (1.0/eta^2))*exp(-eta^2) - end - d2Hdvpa2 = ((vperp.grid[ivperp]^2)/(eta^2))*dHdeta_over_eta + ((vpa.grid[ivpa]^2)/(eta^2))*d2Hdeta2 - return d2Hdvpa2 + + #multiply by scale factor for element length + D .= (2.0*float(nelement)/L).*D +end + +""" +derivative matrix for radau grid +""" +function calculate_chebyshev_radau_D_matrix_via_FFT!(D::Array{Float64,2}, coord, spectral) + ff_buffer = Array{Float64,1}(undef,coord.ngrid) + df_buffer = Array{Float64,1}(undef,coord.ngrid) + # use response matrix approach to calculate derivative matrix D + for j in 1:coord.ngrid + ff_buffer .= 0.0 + ff_buffer[j] = 1.0 + @views chebyshev_radau_derivative_single_element!(df_buffer[:], ff_buffer[:], + spectral.radau.f[:,1], spectral.radau.df, spectral.radau.fext, spectral.radau.forward, coord) + @. D[:,j] = df_buffer[:] # assign appropriate column of derivative matrix end - function d2G_Maxwellian_dvpa2(vpa,vperp,ivpa,ivperp) - # speed variable - eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) - zero = 1.0e-10 - if eta < zero - dGdeta_over_eta = 4.0/(3.0*sqrt(pi)) - d2Gdeta2 = 4.0/(3.0*sqrt(pi)) - else - dGdeta_over_eta = (1.0/sqrt(pi))*(exp(-eta^2)/(eta^2)) + (1.0 - (0.5/eta^2))*erf(eta)/eta - d2Gdeta2 = (erf(eta)/(eta^3)) - (2.0/sqrt(pi))*exp(-eta^2)/eta^2 - end - d2Gdvpa2 = ((vperp.grid[ivperp]^2)/(eta^2))*dGdeta_over_eta + ((vpa.grid[ivpa]^2)/(eta^2))*d2Gdeta2 - return d2Gdvpa2 + # correct diagonal elements to gurantee numerical stability + # gives D*[1.0, 1.0, ... 1.0] = [0.0, 0.0, ... 0.0] + for j in 1:coord.ngrid + D[j,j] = 0.0 + D[j,j] = -sum(D[j,:]) end - function dHdvpa_inf(vpa,vperp,ivpa,ivperp) - eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) - dHdvpa_inf = -vpa.grid[ivpa]/eta^3 - return dHdvpa_inf - end - function d2Gdvpa2_inf(vpa,vperp,ivpa,ivperp) - eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) - d2Gdvpa2_inf = ((vpa.grid[ivpa]^2)/eta^5) + ((vperp.grid[ivperp]^2)/eta^3)*( 1.0 - (0.5/eta^2)) - return d2Gdvpa2_inf + #multiply by scale factor for element length + D .= (2.0*float(coord.nelement_global)/coord.L).*D +end + +function cheb_radau_derivative_matrix_reversed!(D::Array{Float64,2},x,x_spectral) + D_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + cheb_derivative_matrix_elementwise_reversed!(D_lobotto_elementwise,x.ngrid,x.L,x.nelement_global) + + D_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + calculate_chebyshev_radau_D_matrix_via_FFT!(D_radau_elementwise,x,x_spectral) + if x.ngrid < 8 + print_matrix(D_lobotto_elementwise,"D_lobotto_elementwise",x.ngrid,x.ngrid) + print_matrix(D_radau_elementwise,"D_radau_elementwise",x.ngrid,x.ngrid) + end + assign_cheb_derivative_matrix!(D,D_lobotto_elementwise,D_radau_elementwise,x) +end + +function cheb_radau_second_derivative_matrix_reversed!(D::Array{Float64,2},x,x_spectral) + D_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + cheb_derivative_matrix_elementwise_reversed!(D_lobotto_elementwise,x.ngrid,x.L,x.nelement_global) + D2_lobotto_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + mul!(D2_lobotto_elementwise,D_lobotto_elementwise,D_lobotto_elementwise) + + D_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + calculate_chebyshev_radau_D_matrix_via_FFT!(D_radau_elementwise,x,x_spectral) + D2_radau_elementwise = Array{Float64,2}(undef,x.ngrid,x.ngrid) + mul!(D2_radau_elementwise,D_radau_elementwise,D_radau_elementwise) + + if x.ngrid < 8 + #print_matrix(D_lobotto_elementwise,"D_lobotto_elementwise",x.ngrid,x.ngrid) + print_matrix(D2_lobotto_elementwise,"D2_lobotto_elementwise",x.ngrid,x.ngrid) + #print_matrix(D_radau_elementwise,"D_radau_elementwise",x.ngrid,x.ngrid) + print_matrix(D2_radau_elementwise,"D2_radau_elementwise",x.ngrid,x.ngrid) end + assign_cheb_derivative_matrix!(D,D2_lobotto_elementwise,D2_radau_elementwise,x) +end + + +function assign_cheb_derivative_matrix!(D::Array{Float64,2},D_lobotto_elementwise::Array{Float64,2},D_radau_elementwise::Array{Float64,2},x) + # zero output matrix before assignment + D[:,:] .= 0.0 + imin = x.imin + imax = x.imax - #using LinearAlgebra.mul - discretization = "chebyshev_pseudospectral" - #discretization = "finite_difference" - etol = 1.0e-15 - outprefix = "derivative_test" - ################### - ## df/dx Nonperiodic (No) BC test - ################### - - # define inputs needed for the test - ngrid = 17 #number of points per element - nelement_local = 20 # number of elements per rank - nelement_global = nelement_local # total number of elements - L = 1.0 #physical box size in reference units - bc = "" #not required to take a particular value, not used - # fd_option and adv_input not actually used so given values unimportant - fd_option = "fourth_order_centered" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = MPI.COMM_NULL - # create the 'input' struct containing input info needed to create a - # coordinate - input = grid_input("coord", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, bc, adv_input,comm) - # create the coordinate struct 'x' - println("made inputs") - x = define_coordinate(input) - println("made x") - Dx = Array{Float64,2}(undef, x.n, x.n) - xchebgrid = Array{Float64,1}(undef, x.n) - for i in 1:x.n - xchebgrid[i] = cos(pi*(i - 1)/(x.n - 1)) + zero_bc_upper_boundary = x.bc == "zero" || x.bc == "zero_upper" + zero_bc_lower_boundary = x.bc == "zero" || x.bc == "zero_lower" + + # fill in first element + j = 1 + if zero_bc_lower_boundary #x.bc == "zero" + D[imin[j],imin[j]:imax[j]] .+= D_radau_elementwise[1,:]./2.0 #contributions from this element/2 + D[imin[j],imin[j]] += D_radau_elementwise[x.ngrid,x.ngrid]/2.0 #contribution from missing `zero' element/2 + else + D[imin[j],imin[j]:imax[j]] .+= D_radau_elementwise[1,:] + end + for k in 2:imax[j]-imin[j] + D[k,imin[j]:imax[j]] .+= D_radau_elementwise[k,:] + end + if zero_bc_upper_boundary && x.nelement_local == 1 + D[imax[j],imin[j]-1:imax[j]] .+= D_radau_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 + D[imax[j],imax[j]] += D_lobotto_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 + elseif x.nelement_local > 1 #x.bc == "zero" + D[imax[j],imin[j]:imax[j]] .+= D_radau_elementwise[x.ngrid,:]./2.0 + else + D[imax[j],imin[j]:imax[j]] .+= D_radau_elementwise[x.ngrid,:] + end + # remaining elements recalling definitions of imax and imin + for j in 2:x.nelement_local + #lower boundary condition on element + D[imin[j]-1,imin[j]-1:imax[j]] .+= D_lobotto_elementwise[1,:]./2.0 + for k in 2:imax[j]-imin[j]+1 + D[k+imin[j]-2,imin[j]-1:imax[j]] .+= D_lobotto_elementwise[k,:] + end + # upper boundary condition on element + if j == x.nelement_local && !(zero_bc_upper_boundary) + D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:] + elseif j == x.nelement_local && zero_bc_upper_boundary + D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:]./2.0 #contributions from this element/2 + D[imax[j],imax[j]] += D_lobotto_elementwise[1,1]/2.0 #contribution from missing `zero' element/2 + else + D[imax[j],imin[j]-1:imax[j]] .+= D_lobotto_elementwise[x.ngrid,:]./2.0 + end end - #println("x",xchebgrid[:]) - cheb_derivative_matrix!(Dx,xchebgrid,x.n) - #println("") - #println("Dx \n") - #for i in 1:x.n - # println(Dx[i,:]) - #end - # create array for the function f(x) to be differentiated/integrated - f = Array{Float64,1}(undef, x.n) - # create array for the derivative df/dx - df = Array{Float64,1}(undef, x.n) - df2 = Array{Float64,1}(undef, x.n) - df2cheb = Array{Float64,1}(undef, x.n) - df_exact = Array{Float64,1}(undef, x.n) - df2_exact = Array{Float64,1}(undef, x.n) - df_err = Array{Float64,1}(undef, x.n) - df2_err = Array{Float64,1}(undef, x.n) - df2cheb_err = Array{Float64,1}(undef, x.n) +end - for ix in 1:x.n - f[ix] = sin(pi*xchebgrid[ix]) - df_exact[ix] = (pi)*cos(pi*xchebgrid[ix]) +""" +function integrating d y / d t = f(t) +""" +function forward_euler_step!(ynew,yold,f,dt,n) + for i in 1:n + ynew[i] = yold[i] + dt*f[i] end - mul!(df,Dx,f) - for ix in 1:x.n - df_err[ix] = df[ix]-df_exact[ix] +end +""" +function creating lu object for A = I - dt*nu*D2 +""" +function diffusion_matrix(D2,n,dt,nu;return_A=false) + A = Array{Float64,2}(undef,n,n) + for i in 1:n + for j in 1:n + A[i,j] = - dt*nu*D2[i,j] + end + A[i,i] += 1.0 end - # test standard cheb D f = df - #println("df \n",df) - #println("df_exact \n",df_exact) - #println("df_err \n",df_err) - input = grid_input("coord", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "zero", adv_input,comm) - # create the coordinate struct 'x' - x = define_coordinate(input) - - Dxreverse = Array{Float64,2}(undef, x.n, x.n) - cheb_derivative_matrix_reversed!(Dxreverse,x) - Dxreverse2 = Array{Float64,2}(undef, x.n, x.n) - mul!(Dxreverse2,Dxreverse,Dxreverse) - D2xreverse = Array{Float64,2}(undef, x.n, x.n) - cheb_second_derivative_matrix_reversed!(D2xreverse,x) - - Dxreverse2[1,1] = 2.0*Dxreverse2[1,1] - Dxreverse2[end,end] = 2.0*Dxreverse2[end,end] - #println("x.grid \n",x.grid) - if x.n < 20 - print_matrix(Dxreverse,"\n Dxreverse \n",x.n,x.n) - print_matrix(Dxreverse2,"\n Dxreverse*Dxreverse \n",x.n,x.n) - print_matrix(D2xreverse,"\n D2xreverse \n",x.n,x.n) - println("\n") + lu_obj = lu(A) + if return_A + return lu_obj, A + else + return lu_obj end +end - alpha = 512.0 - for ix in 1:x.n -# f[ix] = sin(2.0*pi*x.grid[ix]/x.L) -# df_exact[ix] = (2.0*pi/x.L)*cos(2.0*pi*x.grid[ix]/x.L) -# df2_exact[ix] = -(2.0*pi/x.L)*(2.0*pi/x.L)*sin(2.0*pi*x.grid[ix]/x.L) - - f[ix] = exp(-alpha*(x.grid[ix])^2) - df_exact[ix] = -2.0*alpha*x.grid[ix]*exp(-alpha*(x.grid[ix])^2) - df2_exact[ix] = ((2.0*alpha*x.grid[ix])^2 - 2.0*alpha)*exp(-alpha*(x.grid[ix])^2) - end - #println("test f: \n",f) - # calculate d f / d x from matrix - mul!(df,Dxreverse,f) - # calculate d^2 f / d x from second application of Dx matrix - mul!(df2,Dxreverse2,f) - # calculate d^2 f / d x from applition of D2x matrix - mul!(df2cheb,D2xreverse,f) - for ix in 1:x.n - df_err[ix] = df[ix]-df_exact[ix] - df2_err[ix] = df2[ix]-df2_exact[ix] - df2cheb_err[ix] = df2cheb[ix]-df2_exact[ix] +""" +functions for Rosenbluth potential tests +""" +function dH_Maxwellian_dvpa(vpa,vperp,ivpa,ivperp) + # speed variable + eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) + zero = 1.0e-10 + if eta < zero + dHdvpa = -(4.0*vpa.grid[ivpa])/(3.0*sqrt(pi)) + else + dHdvpa = (vpa.grid[ivpa]/eta)*((2.0/sqrt(pi))*(exp(-eta^2)/eta) - (erf(eta)/(eta^2))) end - println("Reversed - multiple elements") - #println("df \n",df) - #println("df_exact \n",df_exact) - #println("df_err \n",df_err) - #println("df2 \n",df2) - #println("df2_exact \n",df2_exact) - #println("df2_err \n",df2_err) - #println("df2cheb_err \n",df2cheb_err) - - println("max(df_err) \n",maximum(abs.(df_err))) - println("max(df2_err) \n",maximum(abs.(df2_err))) - println("max(df2cheb_err) \n",maximum(abs.(df2cheb_err))) - - ### attempt at matrix inversion via LU decomposition - Dt = 0.1 - Nu = 1.0 - lu_obj, AA = diffusion_matrix(Dxreverse2,x.n,Dt,Nu,return_A=true) - #AA = Array{Float64,2}(undef,x.n,x.n) - #for i in 1:x.n - # for j in 1:x.n - # AA[i,j] = - Dt*Nu*Dxreverse2[i,j] - # end - # AA[i,i] += 1.0 - #end - #lu_obj = lu(AA) - if x.n < 20 - println("L : \n",lu_obj.L) - println("U : \n",lu_obj.U) - println("p vector : \n",lu_obj.p) + return dHdvpa +end +function d2H_Maxwellian_dvpa2(vpa,vperp,ivpa,ivperp) + # speed variable + eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) + zero = 1.0e-10 + if eta < zero + dHdeta_over_eta = -4.0/(3.0*sqrt(pi)) + d2Hdeta2 = -4.0/(3.0*sqrt(pi)) + else + dHdeta_over_eta = (2.0/sqrt(pi))*(exp(-eta^2)/eta^2) - (erf(eta)/(eta^3)) + d2Hdeta2 = 2.0*(erf(eta)/(eta^3)) - (4.0/sqrt(pi))*(1.0 + (1.0/eta^2))*exp(-eta^2) end - LUtest = true - AA_test_lhs = lu_obj.L*lu_obj.U - AA_test_rhs = AA[lu_obj.p,:] - for i in 1:x.n - for j in 1:x.n - if abs.(AA_test_lhs[i,j]-AA_test_rhs[i,j]) > zero - global LUtest = false - end - end + d2Hdvpa2 = ((vperp.grid[ivperp]^2)/(eta^2))*dHdeta_over_eta + ((vpa.grid[ivpa]^2)/(eta^2))*d2Hdeta2 + return d2Hdvpa2 +end +function d2G_Maxwellian_dvpa2(vpa,vperp,ivpa,ivperp) + # speed variable + eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) + zero = 1.0e-10 + if eta < zero + dGdeta_over_eta = 4.0/(3.0*sqrt(pi)) + d2Gdeta2 = 4.0/(3.0*sqrt(pi)) + else + dGdeta_over_eta = (1.0/sqrt(pi))*(exp(-eta^2)/(eta^2)) + (1.0 - (0.5/eta^2))*erf(eta)/eta + d2Gdeta2 = (erf(eta)/(eta^3)) - (2.0/sqrt(pi))*exp(-eta^2)/eta^2 end - println("LU == AA : \n",LUtest) + d2Gdvpa2 = ((vperp.grid[ivperp]^2)/(eta^2))*dGdeta_over_eta + ((vpa.grid[ivpa]^2)/(eta^2))*d2Gdeta2 + return d2Gdvpa2 +end + +function dHdvpa_inf(vpa,vperp,ivpa,ivperp) + eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) + dHdvpa_inf = -vpa.grid[ivpa]/eta^3 + return dHdvpa_inf +end +function d2Gdvpa2_inf(vpa,vperp,ivpa,ivperp) + eta = sqrt(vpa.grid[ivpa]^2 + vperp.grid[ivperp]^2) + d2Gdvpa2_inf = ((vpa.grid[ivpa]^2)/eta^5) + ((vperp.grid[ivperp]^2)/eta^3)*( 1.0 - (0.5/eta^2)) + return d2Gdvpa2_inf +end + + +#using LinearAlgebra.mul +discretization = "chebyshev_pseudospectral" +#discretization = "finite_difference" + etol = 1.0e-15 +outprefix = "derivative_test" + ################### + ## df/dx Nonperiodic (No) BC test + ################### - #bb = ones(x.n) try this for bc = "" rather than bc = "zero" - bb = Array{Float64,1}(undef,x.n) - yy = Array{Float64,1}(undef,x.n) - #for i in 1:x.n - # bb[i] = f[i]#exp(-(4.0*x.grid[i]/x.L)^2) - #end - #yy = lu_obj \ bb # solution to AA yy = bb - #println("result", yy) - #println("check result", AA*yy, bb) - MMS_test = false - evolution_test = false#true - elliptic_solve_test = false#true - elliptic_solve_1D_infinite_domain_test = false#true - elliptic_2Dsolve_test = true - if MMS_test - ntest = 5 - MMS_errors = Array{Float64,1}(undef,ntest) - Dt_list = Array{Float64,1}(undef,ntest) - fac_list = Array{Int64,1}(undef,ntest) - fac_list .= [1, 10, 100, 1000, 10000] - #for itest in [1, 10, 100, 1000, 10000] - for itest in 1:ntest - fac = fac_list[itest] - #println(fac) - ntime = 1000*fac - nwrite = 100*fac - dt = 0.001/fac - #println(ntime," ",dt) - nu = 1.0 - LU_obj = diffusion_matrix(Dxreverse2,x.n,dt,nu) - - time = Array{Float64,1}(undef,ntime) - ff = Array{Float64,2}(undef,x.n,ntime) - ss = Array{Float64,1}(undef,x.n) #source + # define inputs needed for the test + ngrid = 17 #number of points per element + nelement_local = 20 # number of elements per rank + nelement_global = nelement_local # total number of elements + L = 1.0 #physical box size in reference units + bc = "" #not required to take a particular value, not used + # fd_option and adv_input not actually used so given values unimportant + fd_option = "fourth_order_centered" + nrank = 1 +irank = 0 +comm = MPI.COMM_NULL +# create the 'input' struct containing input info needed to create a +# coordinate +input = OptionsDict("coord" => OptionsDict("ngrid"=>ngrid, + "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>bc)) +# create the coordinate struct 'x' +# This test runs effectively in serial, so use `ignore_MPI=true` to avoid +# errors due to communicators not being fully set up. +x, spectral = define_coordinate(input, "coord"; ignore_MPI=true) + println("made x") +Dx = Array{Float64,2}(undef, x.n, x.n) +xchebgrid = Array{Float64,1}(undef, x.n) +for i in 1:x.n + xchebgrid[i] = cos(pi*(i - 1)/(x.n - 1)) +end +#println("x",xchebgrid[:]) +cheb_derivative_matrix!(Dx,xchebgrid,x.n) +#println("") +#println("Dx \n") +#for i in 1:x.n +# println(Dx[i,:]) +#end - time[1] = 0.0 - ff[:,1] .= f[:] #initial condition - for i in 1:ntime-1 - time[i+1] = (i+1)*dt - bb .= ff[:,i] - yy .= LU_obj\bb # implicit backward euler diffusion step - @. ss = -nu*df2_exact # source term - # explicit forward_euler_step with source - @views forward_euler_step!(ff[:,i+1],yy,ss,dt,x.n) - end + # create array for the function f(x) to be differentiated/integrated + f = Array{Float64,1}(undef, x.n) + # create array for the derivative df/dx + df = Array{Float64,1}(undef, x.n) + df2 = Array{Float64,1}(undef, x.n) + df2cheb = Array{Float64,1}(undef, x.n) +df_exact = Array{Float64,1}(undef, x.n) +df2_exact = Array{Float64,1}(undef, x.n) +df_err = Array{Float64,1}(undef, x.n) +df2_err = Array{Float64,1}(undef, x.n) +df2cheb_err = Array{Float64,1}(undef, x.n) + +for ix in 1:x.n + f[ix] = sin(pi*xchebgrid[ix]) + df_exact[ix] = (pi)*cos(pi*xchebgrid[ix]) +end +mul!(df,Dx,f) +for ix in 1:x.n + df_err[ix] = df[ix]-df_exact[ix] +end +# test standard cheb D f = df +#println("df \n",df) +#println("df_exact \n",df_exact) +#println("df_err \n",df_err) +input = OptionsDict("coord" => OptionsDict("ngrid"=>ngrid, + "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero")) +# create the coordinate struct 'x' +# This test runs effectively in serial, so use `ignore_MPI=true` to avoid +# errors due to communicators not being fully set up. +x, spectral = define_coordinate(input, "coord"; ignore_MPI=true) + +Dxreverse = Array{Float64,2}(undef, x.n, x.n) +cheb_derivative_matrix_reversed!(Dxreverse,x) +Dxreverse2 = Array{Float64,2}(undef, x.n, x.n) +mul!(Dxreverse2,Dxreverse,Dxreverse) +D2xreverse = Array{Float64,2}(undef, x.n, x.n) +cheb_second_derivative_matrix_reversed!(D2xreverse,x) + +Dxreverse2[1,1] = 2.0*Dxreverse2[1,1] +Dxreverse2[end,end] = 2.0*Dxreverse2[end,end] +#println("x.grid \n",x.grid) +if x.n < 20 + print_matrix(Dxreverse,"\n Dxreverse \n",x.n,x.n) + print_matrix(Dxreverse2,"\n Dxreverse*Dxreverse \n",x.n,x.n) + print_matrix(D2xreverse,"\n D2xreverse \n",x.n,x.n) + println("\n") +end + +alpha = 512.0 +for ix in 1:x.n +# f[ix] = sin(2.0*pi*x.grid[ix]/x.L) +# df_exact[ix] = (2.0*pi/x.L)*cos(2.0*pi*x.grid[ix]/x.L) +# df2_exact[ix] = -(2.0*pi/x.L)*(2.0*pi/x.L)*sin(2.0*pi*x.grid[ix]/x.L) + + f[ix] = exp(-alpha*(x.grid[ix])^2) + df_exact[ix] = -2.0*alpha*x.grid[ix]*exp(-alpha*(x.grid[ix])^2) + df2_exact[ix] = ((2.0*alpha*x.grid[ix])^2 - 2.0*alpha)*exp(-alpha*(x.grid[ix])^2) +end +#println("test f: \n",f) +# calculate d f / d x from matrix +mul!(df,Dxreverse,f) +# calculate d^2 f / d x from second application of Dx matrix +mul!(df2,Dxreverse2,f) +# calculate d^2 f / d x from applition of D2x matrix +mul!(df2cheb,D2xreverse,f) +for ix in 1:x.n + df_err[ix] = df[ix]-df_exact[ix] + df2_err[ix] = df2[ix]-df2_exact[ix] + df2cheb_err[ix] = df2cheb[ix]-df2_exact[ix] +end +println("Reversed - multiple elements") +#println("df \n",df) +#println("df_exact \n",df_exact) +#println("df_err \n",df_err) +#println("df2 \n",df2) +#println("df2_exact \n",df2_exact) +#println("df2_err \n",df2_err) +#println("df2cheb_err \n",df2cheb_err) + +println("max(df_err) \n",maximum(abs.(df_err))) +println("max(df2_err) \n",maximum(abs.(df2_err))) +println("max(df2cheb_err) \n",maximum(abs.(df2cheb_err))) - ff_error = Array{Float64,1}(undef,x.n) - ff_error[:] .= abs.(ff[:,end] - ff[:,1]) - maxfferr = maximum(ff_error) - #println("ff_error \n",ff_error) - println("max(ff_error) \n",maxfferr) - #println("t[end]: ",time[end]) - MMS_errors[itest] = maxfferr - Dt_list[itest] = dt - end - @views plot(Dt_list, [MMS_errors, 100.0*Dt_list], label=[L"max(\epsilon(f))" L"100\Delta t"], - xlabel=L"\Delta t", ylabel="", xscale=:log10, yscale=:log10, shape =:circle) - outfile = string("ff_err_vs_dt.pdf") - savefig(outfile) +### attempt at matrix inversion via LU decomposition +Dt = 0.1 +Nu = 1.0 +lu_obj, AA = diffusion_matrix(Dxreverse2,x.n,Dt,Nu,return_A=true) +#AA = Array{Float64,2}(undef,x.n,x.n) +#for i in 1:x.n +# for j in 1:x.n +# AA[i,j] = - Dt*Nu*Dxreverse2[i,j] +# end +# AA[i,i] += 1.0 +#end +#lu_obj = lu(AA) +if x.n < 20 + println("L : \n",lu_obj.L) + println("U : \n",lu_obj.U) + println("p vector : \n",lu_obj.p) +end +LUtest = true +AA_test_lhs = lu_obj.L*lu_obj.U +AA_test_rhs = AA[lu_obj.p,:] +for i in 1:x.n + for j in 1:x.n + if abs.(AA_test_lhs[i,j]-AA_test_rhs[i,j]) > zero + global LUtest = false + end end - - if evolution_test - ntime = 100 - nwrite = 1 - dt = 0.001 +end +println("LU == AA : \n",LUtest) + +#bb = ones(x.n) try this for bc = "" rather than bc = "zero" +bb = Array{Float64,1}(undef,x.n) +yy = Array{Float64,1}(undef,x.n) +#for i in 1:x.n +# bb[i] = f[i]#exp(-(4.0*x.grid[i]/x.L)^2) +#end +#yy = lu_obj \ bb # solution to AA yy = bb +#println("result", yy) +#println("check result", AA*yy, bb) +MMS_test = false +evolution_test = false#true +elliptic_solve_test = false#true +elliptic_solve_1D_infinite_domain_test = false#true +elliptic_2Dsolve_test = true +if MMS_test + ntest = 5 + MMS_errors = Array{Float64,1}(undef,ntest) + Dt_list = Array{Float64,1}(undef,ntest) + fac_list = Array{Int64,1}(undef,ntest) + fac_list .= [1, 10, 100, 1000, 10000] + #for itest in [1, 10, 100, 1000, 10000] + for itest in 1:ntest + fac = fac_list[itest] + #println(fac) + ntime = 1000*fac + nwrite = 100*fac + dt = 0.001/fac + #println(ntime," ",dt) nu = 1.0 LU_obj = diffusion_matrix(Dxreverse2,x.n,dt,nu) @@ -687,566 +659,638 @@ if abspath(PROGRAM_FILE) == @__FILE__ time[i+1] = (i+1)*dt bb .= ff[:,i] yy .= LU_obj\bb # implicit backward euler diffusion step - @. ss = 0.0 # source term + @. ss = -nu*df2_exact # source term # explicit forward_euler_step with source @views forward_euler_step!(ff[:,i+1],yy,ss,dt,x.n) end - ffmin = minimum(ff) - ffmax = maximum(ff) - anim = @animate for i in 1:nwrite:ntime - @views plot(x.grid, ff[:,i], xlabel="x", ylabel="f", ylims = (ffmin,ffmax)) - end - outfile = string("ff_vs_x.gif") - gif(anim, outfile, fps=5) + ff_error = Array{Float64,1}(undef,x.n) + ff_error[:] .= abs.(ff[:,end] - ff[:,1]) + maxfferr = maximum(ff_error) + #println("ff_error \n",ff_error) + println("max(ff_error) \n",maxfferr) + #println("t[end]: ",time[end]) + MMS_errors[itest] = maxfferr + Dt_list[itest] = dt + end + @views plot(Dt_list, [MMS_errors, 100.0*Dt_list], label=[L"max(\epsilon(f))" L"100\Delta t"], + xlabel=L"\Delta t", ylabel="", xscale=:log10, yscale=:log10, shape =:circle) + outfile = string("ff_err_vs_dt.pdf") + savefig(outfile) +end + +if evolution_test + ntime = 100 + nwrite = 1 + dt = 0.001 + nu = 1.0 + LU_obj = diffusion_matrix(Dxreverse2,x.n,dt,nu) + + time = Array{Float64,1}(undef,ntime) + ff = Array{Float64,2}(undef,x.n,ntime) + ss = Array{Float64,1}(undef,x.n) #source + + time[1] = 0.0 + ff[:,1] .= f[:] #initial condition + for i in 1:ntime-1 + time[i+1] = (i+1)*dt + bb .= ff[:,i] + yy .= LU_obj\bb # implicit backward euler diffusion step + @. ss = 0.0 # source term + # explicit forward_euler_step with source + @views forward_euler_step!(ff[:,i+1],yy,ss,dt,x.n) end + + ffmin = minimum(ff) + ffmax = maximum(ff) + anim = @animate for i in 1:nwrite:ntime + @views plot(x.grid, ff[:,i], xlabel="x", ylabel="f", ylims = (ffmin,ffmax)) + end + outfile = string("ff_vs_x.gif") + gif(anim, outfile, fps=5) +end + +if elliptic_solve_test + println("elliptic solve test") + ngrid = 25 + nelement_local = 50 + L = 8 + nelement_global = nelement_local + radau = true #false + if radau + input = OptionsDict("vperp" => OptionsDict("ngrid"=>ngrid, + "nelement"=>nelement_global, + "nelement_local"=>nelement_local, "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero_upper")) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + y, y_spectral = define_coordinate(input, "vperp"; ignore_MPI=true) + Dy = Array{Float64,2}(undef, y.n, y.n) + cheb_radau_derivative_matrix_reversed!(Dy,y,y_spectral) + else #lobotto + input = OptionsDict("vpa" => OptionsDict("ngrid"=>ngrid, + "nelement"=>nelement_global, + "nelement_local"=>nelement_local, + "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero_upper")) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + y, y_spectral = define_coordinate(input, "vpa"; ignore_MPI=true) + @. y.grid += y.L/2 + Dy = Array{Float64,2}(undef, y.n, y.n) + cheb_derivative_matrix_reversed!(Dy,y) + end - if elliptic_solve_test - println("elliptic solve test") - ngrid = 25 - nelement_local = 50 - L = 8 - nelement_global = nelement_local - radau = true #false - if radau - input = grid_input("vperp", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "zero_upper", adv_input,comm) - y = define_coordinate(input) - y_spectral = setup_chebyshev_pseudospectral(y) - Dy = Array{Float64,2}(undef, y.n, y.n) - cheb_radau_derivative_matrix_reversed!(Dy,y,y_spectral) - else #lobotto - input = grid_input("vpa", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "zero_upper", adv_input,comm) - y = define_coordinate(input) - @. y.grid += y.L/2 - Dy = Array{Float64,2}(undef, y.n, y.n) - cheb_derivative_matrix_reversed!(Dy,y) + yDy = Array{Float64,2}(undef, y.n, y.n) + for iy in 1:y.n + @. yDy[iy,:] = y.grid[iy]*Dy[iy,:] + end + + + Dy_yDy = Array{Float64,2}(undef, y.n, y.n) + mul!(Dy_yDy,Dy,yDy) + #Dy_yDy[1,1] = 2.0*Dy_yDy[1,1] + #Dy_yDy[end,end] = 2.0*Dy_yDy[end,end] + + D2y = Array{Float64,2}(undef, y.n, y.n) + mul!(D2y,Dy,Dy) + #Dy_yDy[1,1] = 2.0*Dy_yDy[1,1] + D2y[end,end] = 2.0*D2y[end,end] + yD2y = Array{Float64,2}(undef, y.n, y.n) + for iy in 1:y.n + @. yD2y[iy,:] = y.grid[iy]*D2y[iy,:] + end + + if y.n < 20 + print_matrix(Dy,"Dy",y.n,y.n) + print_matrix(yDy,"yDy",y.n,y.n) + print_matrix(Dy_yDy,"Dy_yDy",y.n,y.n) + print_matrix(yD2y+Dy,"yD2y+Dy",y.n,y.n) + end + Sy = Array{Float64,1}(undef, y.n) + Fy = Array{Float64,1}(undef, y.n) + Fy_exact = Array{Float64,1}(undef, y.n) + Fy_err = Array{Float64,1}(undef, y.n) + for iy in 1:y.n + #Sy[iy] = (y.grid[iy] - 1.0)*exp(-y.grid[iy]) + #Fy_exact[iy] = exp(-y.grid[iy]) + Sy[iy] = 4.0*y.grid[iy]*(y.grid[iy]^2 - 1.0)*exp(-y.grid[iy]^2) + Fy_exact[iy] = exp(-y.grid[iy]^2) + end + LL = Array{Float64,2}(undef, y.n, y.n) + #@. LL = yD2y + Dy + for iy in 1:y.n + #@. LL[iy,:] = Dy_yDy[iy,:] #*(1.0/y.grid[iy]) + @. LL[iy,:] = yD2y[iy,:] + Dy[iy,:] #*(1.0/y.grid[iy]) + end + Dirichlet = true + if Dirichlet + # fixed value at orgin -- doesn't work well + #@. LL[1,:] = 0.0 + #Sy[1] = Fy_exact[1] + set_flux = false + if set_flux + # set flux at origin + @. LL[1,:] = 0.0 + ilim = y.imax[1] + @. LL[1,:] = yDy[ilim,:] + + print_vector(Sy,"Sy before",y.n) + integrand = Array{Float64,1}(undef,ilim) + @. integrand[1:ilim] = Sy[1:ilim]*y.wgts[1:ilim]/(2.0*y.grid[1:ilim]) + + print_vector(integrand,"integrand",ilim) + print_vector(y.wgts,"wgts",y.n) + #@. integrand[1:ilim] = y.grid[1:ilim]*Sy[1:ilim]*y.wgts[1:ilim] + flux = sum(integrand) + Sy[1] = flux end - - yDy = Array{Float64,2}(undef, y.n, y.n) - for iy in 1:y.n - @. yDy[iy,:] = y.grid[iy]*Dy[iy,:] - end - - - Dy_yDy = Array{Float64,2}(undef, y.n, y.n) - mul!(Dy_yDy,Dy,yDy) - #Dy_yDy[1,1] = 2.0*Dy_yDy[1,1] - #Dy_yDy[end,end] = 2.0*Dy_yDy[end,end] - - D2y = Array{Float64,2}(undef, y.n, y.n) - mul!(D2y,Dy,Dy) - #Dy_yDy[1,1] = 2.0*Dy_yDy[1,1] - D2y[end,end] = 2.0*D2y[end,end] - yD2y = Array{Float64,2}(undef, y.n, y.n) - for iy in 1:y.n - @. yD2y[iy,:] = y.grid[iy]*D2y[iy,:] - end - - if y.n < 20 - print_matrix(Dy,"Dy",y.n,y.n) - print_matrix(yDy,"yDy",y.n,y.n) - print_matrix(Dy_yDy,"Dy_yDy",y.n,y.n) - print_matrix(yD2y+Dy,"yD2y+Dy",y.n,y.n) - end - Sy = Array{Float64,1}(undef, y.n) - Fy = Array{Float64,1}(undef, y.n) - Fy_exact = Array{Float64,1}(undef, y.n) - Fy_err = Array{Float64,1}(undef, y.n) - for iy in 1:y.n - #Sy[iy] = (y.grid[iy] - 1.0)*exp(-y.grid[iy]) - #Fy_exact[iy] = exp(-y.grid[iy]) - Sy[iy] = 4.0*y.grid[iy]*(y.grid[iy]^2 - 1.0)*exp(-y.grid[iy]^2) - Fy_exact[iy] = exp(-y.grid[iy]^2) - end - LL = Array{Float64,2}(undef, y.n, y.n) - #@. LL = yD2y + Dy - for iy in 1:y.n - #@. LL[iy,:] = Dy_yDy[iy,:] #*(1.0/y.grid[iy]) - @. LL[iy,:] = yD2y[iy,:] + Dy[iy,:] #*(1.0/y.grid[iy]) - end - Dirichlet = true - if Dirichlet - # fixed value at orgin -- doesn't work well - #@. LL[1,:] = 0.0 - #Sy[1] = Fy_exact[1] - set_flux = false - if set_flux - # set flux at origin - @. LL[1,:] = 0.0 - ilim = y.imax[1] - @. LL[1,:] = yDy[ilim,:] - - print_vector(Sy,"Sy before",y.n) - integrand = Array{Float64,1}(undef,ilim) - @. integrand[1:ilim] = Sy[1:ilim]*y.wgts[1:ilim]/(2.0*y.grid[1:ilim]) - - print_vector(integrand,"integrand",ilim) - print_vector(y.wgts,"wgts",y.n) - #@. integrand[1:ilim] = y.grid[1:ilim]*Sy[1:ilim]*y.wgts[1:ilim] - flux = sum(integrand) - Sy[1] = flux - end - # zero at infinity - @. LL[end,:] = 0.0 - LL[end,end] = 1.0 - #LL[1,1] = 1.0 + # zero at infinity + @. LL[end,:] = 0.0 + LL[end,end] = 1.0 + #LL[1,1] = 1.0 # @. LL[1,:] = 2.0*D2y[1,:] - Sy[end] = Fy_exact[end] - - #print_matrix(LL,"LL",y.n,y.n) - #print_vector(Sy,"Sy",y.n) - end + Sy[end] = Fy_exact[end] - #lu_solver = false - #gauss_seidel_solver = true - #if lu_solver - println("det: ", det(LL)) - println("condition number: ", cond(LL)) - LL_lu_obj = lu(sparse(LL)) - - # do elliptic solve - Fy = LL_lu_obj\Sy - #elseif gauss_seidel_solver - # niter=100 - # @. Fy[:] = Fy_exact[:] # initial guess - # gauss_seidel!(Fy,sparse(LL),Sy,maxiter=niter) - #else - # println("no solution method prescribed") - #end - @. Fy_err = abs(Fy - Fy_exact) - println("maximum(Fy_err)",maximum(Fy_err)) - #println("Fy_err",Fy_err) - #println("Fy_exact",Fy_exact) - #println("Fy",Fy) - plot([y.grid,y.grid,y.grid], [Fy,Fy_exact,Fy_err], xlabel="y", ylabel="", label=["F" "F_exact" "F_err"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_elliptic_solve_test.pdf" - savefig(outfile) - plot([y.grid], [Fy_err], xlabel="x", ylabel="", label=["F_err"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_elliptic_solve_test_err.pdf" - savefig(outfile) - + #print_matrix(LL,"LL",y.n,y.n) + #print_vector(Sy,"Sy",y.n) end - if elliptic_solve_1D_infinite_domain_test - println("elliptic solve 1D infinite domain test") - ngrid = 17 - nelement_local = 50 - L = 25 - nelement_global = nelement_local - input = grid_input("vpa", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "zero", adv_input,comm) - x = define_coordinate(input) - Dx = Array{Float64,2}(undef, x.n, x.n) - cheb_derivative_matrix_reversed!(Dx,x) + #lu_solver = false + #gauss_seidel_solver = true + #if lu_solver + println("det: ", det(LL)) + println("condition number: ", cond(LL)) + LL_lu_obj = lu(sparse(LL)) - D2x = Array{Float64,2}(undef, x.n, x.n) - mul!(D2x,Dx,Dx) - Dirichlet= true - if Dirichlet - # Dirichlet BC? - @. D2x[1,:] = 0.0 - @. D2x[end,:] = 0.0 - D2x[1,1] = 1.0 - D2x[end,end] = 1.0 - else - # FD-like zero - BC - D2x[1,1] = 2.0*D2x[1,1] - D2x[end,end] = 2.0*D2x[end,end] - end - - if x.n < 20 - print_matrix(Dx,"Dx",x.n,x.n) - print_matrix(D2x,"D2x",x.n,x.n) - end - LLx = Array{Float64,2}(undef, x.n, x.n) - @. LLx = D2x - - Sx = Array{Float64,1}(undef, x.n) - Fx = Array{Float64,1}(undef, x.n) - Fx_exact = Array{Float64,1}(undef, x.n) - Fx_err = Array{Float64,1}(undef, x.n) - for ix in 1:x.n - Sx[ix] = (4.0*x.grid[ix]^2 - 2.0)*exp(-x.grid[ix]^2) - Fx_exact[ix] = exp(-x.grid[ix]^2) - end # do elliptic solve - if Dirichlet - Sx[1] = 0.0; Sx[end] = 0.0 #Dirichlet BC values - end - - println("condition number: ", cond(LLx)) - LLx_lu_obj = lu(sparse(LLx)) - lu_solver = true#false - #iterative_solver= false#true - if lu_solver - Fx = LLx_lu_obj\Sx - #elseif iterative_solver - # niter=1000 - # @. Fx[:] = 1.0/(x.grid[:]^8 + 1.0) # initial guess Fx_exact[:] - # Fx[1] =0.0; Fx[end] =0.0 - # #gauss_seidel!(Fx,sparse(LLx),Sx,maxiter=niter) - # #jacobi!(Fx,sparse(LLx),Sx,maxiter=niter) - # #idrs!(Fx,sparse(LLx),Sx;abstol=10^(-10)) - else - println("no solution method prescribed") - end - @. Fx_err = abs(Fx - Fx_exact) - - println("test 1: maximum(Fx_err)",maximum(Fx_err)) - #println("Fx_err",Fx_err) - #println("Fx_exact",Fx_exact) - #println("Fx",Fx) - plot([x.grid,x.grid,x.grid], [Fx,Fx_exact,Fx_err], xlabel="x", ylabel="", label=["F" "F_exact" "F_err"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_infinite_domain_elliptic_solve_test.pdf" - savefig(outfile) - plot([x.grid], [Fx_err], xlabel="x", ylabel="", label=["F_err"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_infinite_domain_elliptic_solve_test_err.pdf" - savefig(outfile) - - for ix in 1:x.n - Sx[ix] = exp(-x.grid[ix]^2) - Fx_exact[ix] = (sqrt(pi)/2.0)*x.grid[ix]*erf(x.grid[ix]) + exp(-x.grid[ix]^2)/2.0 - end - if Dirichlet - Sx[1] = 0.0; Sx[end] = 0.0 #Dirichlet BC values - end - - if lu_solver - Fx = LLx_lu_obj\Sx - elseif iterative_solver - niter=1000 - @. Fx[:] = 1.0/(x.grid[:]^8 + 1.0) # initial guess Fx_exact[:] - Fx[1] =0.0; Fx[end] =0.0 - #gauss_seidel!(Fx,sparse(LLx),Sx,maxiter=niter) - #jacobi!(Fx,sparse(LLx),Sx,maxiter=niter) - idrs!(Fx,sparse(LLx),Sx) - else - println("no solution method prescribed") - end - - @. Fx += (sqrt(pi)/2.0)*x.grid[end] - @. Fx_err = abs(Fx - Fx_exact) - println("test 2: maximum(Fx_err)",maximum(Fx_err)) - plot([x.grid], [Fx], xlabel="x", ylabel="", label=["Fx"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_infinite_domain_elliptic_solve_gaussian_source.pdf" - savefig(outfile) - plot([x.grid], [Fx_err], xlabel="x", ylabel="", label=["F_err"], - shape =:circle, markersize = 5, linewidth=2) - outfile = "1D_infinite_domain_elliptic_solve_gaussian_source_err.pdf" - savefig(outfile) + Fy = LL_lu_obj\Sy + #elseif gauss_seidel_solver + # niter=100 + # @. Fy[:] = Fy_exact[:] # initial guess + # gauss_seidel!(Fy,sparse(LL),Sy,maxiter=niter) + #else + # println("no solution method prescribed") + #end + @. Fy_err = abs(Fy - Fy_exact) + println("maximum(Fy_err)",maximum(Fy_err)) + #println("Fy_err",Fy_err) + #println("Fy_exact",Fy_exact) + #println("Fy",Fy) + plot([y.grid,y.grid,y.grid], [Fy,Fy_exact,Fy_err], xlabel="y", ylabel="", label=["F" "F_exact" "F_err"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_elliptic_solve_test.pdf" + savefig(outfile) + plot([y.grid], [Fy_err], xlabel="x", ylabel="", label=["F_err"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_elliptic_solve_test_err.pdf" + savefig(outfile) + +end + +if elliptic_solve_1D_infinite_domain_test + println("elliptic solve 1D infinite domain test") + ngrid = 17 + nelement_local = 50 + L = 25 + nelement_global = nelement_local + input = OptionsDict("vpa" => OptionsDict("ngrid"=>ngrid, + "nelement"=>nelement_global, + "nelement_local"=>nelement_local, + "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero")) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + x, x_spectral = define_coordinate(input, "vpa"; ignore_MPI=true) + Dx = Array{Float64,2}(undef, x.n, x.n) + cheb_derivative_matrix_reversed!(Dx,x) + + D2x = Array{Float64,2}(undef, x.n, x.n) + mul!(D2x,Dx,Dx) + Dirichlet= true + if Dirichlet + # Dirichlet BC? + @. D2x[1,:] = 0.0 + @. D2x[end,:] = 0.0 + D2x[1,1] = 1.0 + D2x[end,end] = 1.0 + else + # FD-like zero - BC + D2x[1,1] = 2.0*D2x[1,1] + D2x[end,end] = 2.0*D2x[end,end] + end + + if x.n < 20 + print_matrix(Dx,"Dx",x.n,x.n) + print_matrix(D2x,"D2x",x.n,x.n) + end + LLx = Array{Float64,2}(undef, x.n, x.n) + @. LLx = D2x + + Sx = Array{Float64,1}(undef, x.n) + Fx = Array{Float64,1}(undef, x.n) + Fx_exact = Array{Float64,1}(undef, x.n) + Fx_err = Array{Float64,1}(undef, x.n) + for ix in 1:x.n + Sx[ix] = (4.0*x.grid[ix]^2 - 2.0)*exp(-x.grid[ix]^2) + Fx_exact[ix] = exp(-x.grid[ix]^2) + end + # do elliptic solve + if Dirichlet + Sx[1] = 0.0; Sx[end] = 0.0 #Dirichlet BC values + end + + println("condition number: ", cond(LLx)) + LLx_lu_obj = lu(sparse(LLx)) + lu_solver = true#false + #iterative_solver= false#true + if lu_solver + Fx = LLx_lu_obj\Sx + #elseif iterative_solver + # niter=1000 + # @. Fx[:] = 1.0/(x.grid[:]^8 + 1.0) # initial guess Fx_exact[:] + # Fx[1] =0.0; Fx[end] =0.0 + # #gauss_seidel!(Fx,sparse(LLx),Sx,maxiter=niter) + # #jacobi!(Fx,sparse(LLx),Sx,maxiter=niter) + # #idrs!(Fx,sparse(LLx),Sx;abstol=10^(-10)) + else + println("no solution method prescribed") + end + @. Fx_err = abs(Fx - Fx_exact) + + println("test 1: maximum(Fx_err)",maximum(Fx_err)) + #println("Fx_err",Fx_err) + #println("Fx_exact",Fx_exact) + #println("Fx",Fx) + plot([x.grid,x.grid,x.grid], [Fx,Fx_exact,Fx_err], xlabel="x", ylabel="", label=["F" "F_exact" "F_err"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_infinite_domain_elliptic_solve_test.pdf" + savefig(outfile) + plot([x.grid], [Fx_err], xlabel="x", ylabel="", label=["F_err"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_infinite_domain_elliptic_solve_test_err.pdf" + savefig(outfile) + + for ix in 1:x.n + Sx[ix] = exp(-x.grid[ix]^2) + Fx_exact[ix] = (sqrt(pi)/2.0)*x.grid[ix]*erf(x.grid[ix]) + exp(-x.grid[ix]^2)/2.0 + end + if Dirichlet + Sx[1] = 0.0; Sx[end] = 0.0 #Dirichlet BC values + end + + if lu_solver + Fx = LLx_lu_obj\Sx + elseif iterative_solver + niter=1000 + @. Fx[:] = 1.0/(x.grid[:]^8 + 1.0) # initial guess Fx_exact[:] + Fx[1] =0.0; Fx[end] =0.0 + #gauss_seidel!(Fx,sparse(LLx),Sx,maxiter=niter) + #jacobi!(Fx,sparse(LLx),Sx,maxiter=niter) + idrs!(Fx,sparse(LLx),Sx) + else + println("no solution method prescribed") + end + + @. Fx += (sqrt(pi)/2.0)*x.grid[end] + @. Fx_err = abs(Fx - Fx_exact) + println("test 2: maximum(Fx_err)",maximum(Fx_err)) + plot([x.grid], [Fx], xlabel="x", ylabel="", label=["Fx"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_infinite_domain_elliptic_solve_gaussian_source.pdf" + savefig(outfile) + plot([x.grid], [Fx_err], xlabel="x", ylabel="", label=["F_err"], + shape =:circle, markersize = 5, linewidth=2) + outfile = "1D_infinite_domain_elliptic_solve_gaussian_source_err.pdf" + savefig(outfile) + +end +if elliptic_2Dsolve_test + println("elliptic 2D solve test") + x_ngrid = 17 + x_nelement_local = 4 + x_L = 12 + y_L = 6 + y_ngrid = 17 + y_nelement_local = 2 + + x_nelement_global = x_nelement_local + y_nelement_global = y_nelement_local + # bc option + dirichlet_zero = true#false# + dirichlet_fixed_value = false#true# + # test option + secular_decay_test = false#true + exponential_decay_test = true#false + dHdvpa_test = false + d2Gdvpa2_test = false#true + # second derivative option + # default = false -> if true then use D2coord matrices based on D_elementwise^2 + second_derivative_elementwise = false#true + + input = OptionsDict("vpa" => OptionsDict("ngrid"=>x_ngrid, + "nelement"=>x_nelement_global, + "nelement_local"=>x_nelement_local, + "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero")) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + x, x_spectral = define_coordinate(input, "vpa"; ignore_MPI=true) + + Dx = Array{Float64,2}(undef, x.n, x.n) + cheb_derivative_matrix_reversed!(Dx,x) + D2x = Array{Float64,2}(undef, x.n, x.n) + if second_derivative_elementwise + cheb_second_derivative_matrix_reversed!(D2x,x) + else + mul!(D2x,Dx,Dx) end + # set x bc on D2x + if dirichlet_zero + D2x[1,1] = 2.0*D2x[1,1] + D2x[end,end] = 2.0*D2x[end,end] + elseif dirichlet_fixed_value + @. D2x[1,:] = 0.0 + @. D2x[end,:] = 0.0 + D2x[1,1] = 1.0 + D2x[end,end] = 1.0 + end - if elliptic_2Dsolve_test - println("elliptic 2D solve test") - x_ngrid = 17 - x_nelement_local = 4 - x_L = 12 - y_L = 6 - y_ngrid = 17 - y_nelement_local = 2 - - x_nelement_global = x_nelement_local - y_nelement_global = y_nelement_local - # bc option - dirichlet_zero = true#false# - dirichlet_fixed_value = false#true# - # test option - secular_decay_test = false#true - exponential_decay_test = true#false - dHdvpa_test = false - d2Gdvpa2_test = false#true - # second derivative option - # default = false -> if true then use D2coord matrices based on D_elementwise^2 - second_derivative_elementwise = false#true - - input = grid_input("vpa", x_ngrid, x_nelement_global, x_nelement_local, - nrank, irank, x_L, discretization, fd_option, "zero", adv_input, comm) - x = define_coordinate(input) - x_spectral = setup_chebyshev_pseudospectral(x) - - Dx = Array{Float64,2}(undef, x.n, x.n) - cheb_derivative_matrix_reversed!(Dx,x) - D2x = Array{Float64,2}(undef, x.n, x.n) - if second_derivative_elementwise - cheb_second_derivative_matrix_reversed!(D2x,x) - else - mul!(D2x,Dx,Dx) - end - # set x bc on D2x - if dirichlet_zero - D2x[1,1] = 2.0*D2x[1,1] - D2x[end,end] = 2.0*D2x[end,end] - elseif dirichlet_fixed_value - @. D2x[1,:] = 0.0 - @. D2x[end,:] = 0.0 - D2x[1,1] = 1.0 - D2x[end,end] = 1.0 - end - - IIx = Array{Float64,2}(undef,x.n,x.n) - @. IIx = 0.0 - for ix in 1:x.n - IIx[ix,ix] = 1.0 - end - - if x.n < 20 - print_matrix(Dx,"Dx",x.n,x.n) - print_matrix(D2x,"D2x",x.n,x.n) - print_matrix(IIx,"IIx",x.n,x.n) - end - - input = grid_input("vperp", y_ngrid, y_nelement_global, y_nelement_local, - nrank, irank, y_L, discretization, fd_option, "zero_upper", adv_input, comm) - y = define_coordinate(input) - y_spectral = setup_chebyshev_pseudospectral(y) - Dy = Array{Float64,2}(undef, y.n, y.n) - cheb_radau_derivative_matrix_reversed!(Dy,y,y_spectral) - - D2y = Array{Float64,2}(undef, y.n, y.n) - if second_derivative_elementwise - cheb_radau_second_derivative_matrix_reversed!(D2y,y,y_spectral) - else - mul!(D2y,Dy,Dy) - end - if dirichlet_zero - D2y[end,end] = 2.0*D2y[end,end] - end - # y derivative operator - LLy = Array{Float64,2}(undef,y.n,y.n) - for iy in 1:y.n - @. LLy[iy,:] = D2y[iy,:] + (1.0/y.grid[iy])*Dy[iy,:] - end - if dirichlet_fixed_value - @. LLy[end,:] = 0.0 - LLy[end,end] = 1.0 - end - IIy = Array{Float64,2}(undef,y.n,y.n) - @. IIy = 0.0 - for iy in 1:y.n - IIy[iy,iy] = 1.0 - end - if y.n < 20 - print_matrix(Dy,"Dy",y.n,y.n) - print_matrix(D2y,"D2y",y.n,y.n) - print_matrix(LLy,"LLy",y.n,y.n) - print_matrix(IIy,"IIy",y.n,y.n) - end - println("Initialised 1D arrays") - ### now form 2D matrix to invert and corresponding sources - - # Array in 2D form - nx = x.n - ny = y.n - Sxy = Array{Float64,2}(undef, nx, ny) - Sxy_check = Array{Float64,2}(undef, nx, ny) - Sxy_check_err = Array{Float64,2}(undef, nx, ny) - Txy = Array{Float64,2}(undef, nx, ny) - Fxy = Array{Float64,2}(undef, nx, ny) - Fxy_exact = Array{Float64,2}(undef, nx, ny) - Fxy_err = Array{Float64,2}(undef, nx, ny) - #LLxy = Array{Float64,4}(undef, nx, ny, nx, ny) - # Array in compound 1D form - # ic = (ix-1) + nx*(iy-1) + 1 - # iy = mod(ic,nx) + 1 - # ix = rem(ic,nx) - function icfunc(ix,iy,nx) - return ix + nx*(iy-1) + IIx = Array{Float64,2}(undef,x.n,x.n) + @. IIx = 0.0 + for ix in 1:x.n + IIx[ix,ix] = 1.0 + end + + if x.n < 20 + print_matrix(Dx,"Dx",x.n,x.n) + print_matrix(D2x,"D2x",x.n,x.n) + print_matrix(IIx,"IIx",x.n,x.n) + end + + input = OptionsDict("vperp" => OptionsDict("ngrid"=>y_ngrid, + "nelement"=>y_nelement_global, + "nelement_local"=>y_nelement_local, + "L"=>L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "bc"=>"zero_upper")) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + y, y_spectral = define_coordinate(input, "vperp"; ignore_MPI=true) + Dy = Array{Float64,2}(undef, y.n, y.n) + cheb_radau_derivative_matrix_reversed!(Dy,y,y_spectral) + + D2y = Array{Float64,2}(undef, y.n, y.n) + if second_derivative_elementwise + cheb_radau_second_derivative_matrix_reversed!(D2y,y,y_spectral) + else + mul!(D2y,Dy,Dy) + end + if dirichlet_zero + D2y[end,end] = 2.0*D2y[end,end] + end + # y derivative operator + LLy = Array{Float64,2}(undef,y.n,y.n) + for iy in 1:y.n + @. LLy[iy,:] = D2y[iy,:] + (1.0/y.grid[iy])*Dy[iy,:] + end + if dirichlet_fixed_value + @. LLy[end,:] = 0.0 + LLy[end,end] = 1.0 + end + IIy = Array{Float64,2}(undef,y.n,y.n) + @. IIy = 0.0 + for iy in 1:y.n + IIy[iy,iy] = 1.0 + end + if y.n < 20 + print_matrix(Dy,"Dy",y.n,y.n) + print_matrix(D2y,"D2y",y.n,y.n) + print_matrix(LLy,"LLy",y.n,y.n) + print_matrix(IIy,"IIy",y.n,y.n) + end + println("Initialised 1D arrays") + ### now form 2D matrix to invert and corresponding sources + + # Array in 2D form + nx = x.n + ny = y.n + Sxy = Array{Float64,2}(undef, nx, ny) + Sxy_check = Array{Float64,2}(undef, nx, ny) + Sxy_check_err = Array{Float64,2}(undef, nx, ny) + Txy = Array{Float64,2}(undef, nx, ny) + Fxy = Array{Float64,2}(undef, nx, ny) + Fxy_exact = Array{Float64,2}(undef, nx, ny) + Fxy_err = Array{Float64,2}(undef, nx, ny) + #LLxy = Array{Float64,4}(undef, nx, ny, nx, ny) + # Array in compound 1D form + # ic = (ix-1) + nx*(iy-1) + 1 + # iy = mod(ic,nx) + 1 + # ix = rem(ic,nx) + function icfunc(ix,iy,nx) + return ix + nx*(iy-1) + end + function iyfunc(ic,nx) + #return mod(ic,nx) + 1 + return floor(Int64,(ic-1)/nx) + 1 + end + function ixfunc(ic,nx) + ix = ic - nx*(iyfunc(ic,nx) - 1) + #return rem(ic,nx) + return ix + end + function kronecker_delta(i,j) + delta = 0.0 + if i == j + delta = 1.0 end - function iyfunc(ic,nx) - #return mod(ic,nx) + 1 - return floor(Int64,(ic-1)/nx) + 1 + return delta + end + nc = nx*ny + Fc = Array{Float64,1}(undef, nc) + Sc = Array{Float64,1}(undef, nc) + LLc = Array{Float64,2}(undef, nc, nc) + + if exponential_decay_test + for iy in 1:ny + for ix in 1:nx + # Exponential test inputs below + Sxy[ix,iy] = ((4.0*x.grid[ix]^2 - 2.0) + (4.0*y.grid[iy]^2 - 4.0))*exp(-y.grid[iy]^2-x.grid[ix]^2) + Fxy_exact[ix,iy] = exp(-x.grid[ix]^2 - y.grid[iy]^2) + end end - function ixfunc(ic,nx) - ix = ic - nx*(iyfunc(ic,nx) - 1) - #return rem(ic,nx) - return ix + elseif secular_decay_test + for iy in 1:ny + for ix in 1:nx + # secular test inputs below + eta2 = x.grid[ix]^2 + y.grid[iy]^2 + zero = 1.0e-10 + if eta2 < zero + Sxy[ix,iy] = 0.0 + Fxy_exact[ix,iy] = 0.5 + else + Sxy[ix,iy] = exp(-1.0/eta2)*(1.0/eta2^2 - 2.0/eta2^3) + Fxy_exact[ix,iy] = 0.5 - 0.5*exp(-1.0/eta2) + end + end end - function kronecker_delta(i,j) - delta = 0.0 - if i == j - delta = 1.0 + elseif dHdvpa_test + for iy in 1:ny + for ix in 1:nx + # Rosenbluth dHdvpa test + Sxy[ix,iy] = -(4.0/sqrt(pi))*(-2.0*x.grid[ix]*exp(-y.grid[iy]^2-x.grid[ix]^2)) + Fxy_exact[ix,iy] = dH_Maxwellian_dvpa(x,y,ix,iy) end - return delta end - nc = nx*ny - Fc = Array{Float64,1}(undef, nc) - Sc = Array{Float64,1}(undef, nc) - LLc = Array{Float64,2}(undef, nc, nc) - - if exponential_decay_test - for iy in 1:ny - for ix in 1:nx - # Exponential test inputs below - Sxy[ix,iy] = ((4.0*x.grid[ix]^2 - 2.0) + (4.0*y.grid[iy]^2 - 4.0))*exp(-y.grid[iy]^2-x.grid[ix]^2) - Fxy_exact[ix,iy] = exp(-x.grid[ix]^2 - y.grid[iy]^2) - end + elseif d2Gdvpa2_test + for iy in 1:ny + for ix in 1:nx + # Rosenbluth d2Gdvpa2 test + Sxy[ix,iy] = 2.0*d2H_Maxwellian_dvpa2(x,y,ix,iy) + Fxy_exact[ix,iy] = d2G_Maxwellian_dvpa2(x,y,ix,iy) + Txy[ix,iy] = 2.0*dH_Maxwellian_dvpa(x,y,ix,iy) end - elseif secular_decay_test - for iy in 1:ny - for ix in 1:nx - # secular test inputs below - eta2 = x.grid[ix]^2 + y.grid[iy]^2 - zero = 1.0e-10 - if eta2 < zero - Sxy[ix,iy] = 0.0 - Fxy_exact[ix,iy] = 0.5 - else - Sxy[ix,iy] = exp(-1.0/eta2)*(1.0/eta2^2 - 2.0/eta2^3) - Fxy_exact[ix,iy] = 0.5 - 0.5*exp(-1.0/eta2) - end - end + @views derivative!(Sxy_check[:,iy],Txy[:,iy],x,x_spectral) + end + @. Sxy_check_err = abs(Sxy - Sxy_check) + println("maximum(Sxy_check_err)",maximum(Sxy_check_err)) + #@views heatmap(y.grid, x.grid, Sxy[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, + # windowsize = (360,240), margin = 15pt) + # outfile = string("Sxy_exact_2D_solve.pdf") + # savefig(outfile) + #@views heatmap(y.grid, x.grid, Sxy_check[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, + # windowsize = (360,240), margin = 15pt) + # outfile = string("Sxy_num_2D_solve.pdf") + # savefig(outfile) + else + println("No Sxy or Fxy_exact specified") + end + + if dirichlet_fixed_value + # set boundary values + if dHdvpa_test + for ix in 1:nx + Sxy[ix,ny] = dHdvpa_inf(x,y,ix,ny) end - elseif dHdvpa_test for iy in 1:ny - for ix in 1:nx - # Rosenbluth dHdvpa test - Sxy[ix,iy] = -(4.0/sqrt(pi))*(-2.0*x.grid[ix]*exp(-y.grid[iy]^2-x.grid[ix]^2)) - Fxy_exact[ix,iy] = dH_Maxwellian_dvpa(x,y,ix,iy) - end + Sxy[1,iy] = dHdvpa_inf(x,y,1,iy) + Sxy[nx,iy] = dHdvpa_inf(x,y,nx,iy) end elseif d2Gdvpa2_test - for iy in 1:ny - for ix in 1:nx - # Rosenbluth d2Gdvpa2 test - Sxy[ix,iy] = 2.0*d2H_Maxwellian_dvpa2(x,y,ix,iy) - Fxy_exact[ix,iy] = d2G_Maxwellian_dvpa2(x,y,ix,iy) - Txy[ix,iy] = 2.0*dH_Maxwellian_dvpa(x,y,ix,iy) - end - @views derivative!(Sxy_check[:,iy],Txy[:,iy],x,x_spectral) + for ix in 1:nx + Sxy[ix,ny] = d2Gdvpa2_inf(x,y,ix,ny) end - @. Sxy_check_err = abs(Sxy - Sxy_check) - println("maximum(Sxy_check_err)",maximum(Sxy_check_err)) - #@views heatmap(y.grid, x.grid, Sxy[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, - # windowsize = (360,240), margin = 15pt) - # outfile = string("Sxy_exact_2D_solve.pdf") - # savefig(outfile) - #@views heatmap(y.grid, x.grid, Sxy_check[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, - # windowsize = (360,240), margin = 15pt) - # outfile = string("Sxy_num_2D_solve.pdf") - # savefig(outfile) - else - println("No Sxy or Fxy_exact specified") + for iy in 1:ny + Sxy[1,iy] = d2Gdvpa2_inf(x,y,1,iy) + Sxy[nx,iy] = d2Gdvpa2_inf(x,y,nx,iy) + end end - - if dirichlet_fixed_value - # set boundary values - if dHdvpa_test - for ix in 1:nx - Sxy[ix,ny] = dHdvpa_inf(x,y,ix,ny) - end - for iy in 1:ny - Sxy[1,iy] = dHdvpa_inf(x,y,1,iy) - Sxy[nx,iy] = dHdvpa_inf(x,y,nx,iy) - end - elseif d2Gdvpa2_test - for ix in 1:nx - Sxy[ix,ny] = d2Gdvpa2_inf(x,y,ix,ny) - end - for iy in 1:ny - Sxy[1,iy] = d2Gdvpa2_inf(x,y,1,iy) - Sxy[nx,iy] = d2Gdvpa2_inf(x,y,nx,iy) - end - end - println("Check boundary specification") - #println(Sxy[:,ny]) - #println(Fxy_exact[:,ny]) - println(abs.(Sxy[:,ny] .- Fxy_exact[:,ny])) - println(abs.(Sxy[1,:] .- Fxy_exact[1,:])) - println(abs.(Sxy[nx,:] .- Fxy_exact[nx,:])) - #println(Sxy[1,:]) - #println(Fxy_exact[1,:]) - #println(Sxy[nx,:]) - #println(Fxy_exact[nx,:]) + println("Check boundary specification") + #println(Sxy[:,ny]) + #println(Fxy_exact[:,ny]) + println(abs.(Sxy[:,ny] .- Fxy_exact[:,ny])) + println(abs.(Sxy[1,:] .- Fxy_exact[1,:])) + println(abs.(Sxy[nx,:] .- Fxy_exact[nx,:])) + #println(Sxy[1,:]) + #println(Fxy_exact[1,:]) + #println(Sxy[nx,:]) + #println(Fxy_exact[nx,:]) + end + # assign values to arrays in compound coordinates + @. LLc = 0.0 + for ic in 1:nc + ix = ixfunc(ic,nx) + iy = iyfunc(ic,nx) + Sc[ic] = Sxy[ix,iy] + for icp in 1:nc + ixp = ixfunc(icp,nx) + iyp = iyfunc(icp,nx) + #println("ic: ",ic," ix: ", ix," iy: ",iy," icp: ",icp," ixp: ", ixp," iyp: ",iyp) + LLc[icp,ic] = D2x[ixp,ix]*IIy[iyp,iy] + LLy[iyp,iy]*IIx[ixp,ix] end - # assign values to arrays in compound coordinates - @. LLc = 0.0 - for ic in 1:nc - ix = ixfunc(ic,nx) - iy = iyfunc(ic,nx) - Sc[ic] = Sxy[ix,iy] - for icp in 1:nc - ixp = ixfunc(icp,nx) - iyp = iyfunc(icp,nx) - #println("ic: ",ic," ix: ", ix," iy: ",iy," icp: ",icp," ixp: ", ixp," iyp: ",iyp) - LLc[icp,ic] = D2x[ixp,ix]*IIy[iyp,iy] + LLy[iyp,iy]*IIx[ixp,ix] - end + end + #set fixed bc in LLc directly + if dirichlet_fixed_value + ix = 1; ixp = 1 + for iyp in 1:ny + for iy in 1:ny + ic = icfunc(ix,iy,nx) + icp = icfunc(ixp,iyp,nx) + LLc[icp,ic] = IIy[iyp,iy] + end end - #set fixed bc in LLc directly - if dirichlet_fixed_value - ix = 1; ixp = 1 - for iyp in 1:ny - for iy in 1:ny - ic = icfunc(ix,iy,nx) - icp = icfunc(ixp,iyp,nx) - LLc[icp,ic] = IIy[iyp,iy] - end - end - ix = nx; ixp = nx - for iyp in 1:ny - for iy in 1:ny - ic = icfunc(ix,iy,nx) - icp = icfunc(ixp,iyp,nx) - LLc[icp,ic] = IIy[iyp,iy] - end - end - iy = ny; iyp = ny - for ixp in 1:nx - for ix in 1:nx - ic = icfunc(ix,iy,nx) - icp = icfunc(ixp,iyp,nx) - LLc[icp,ic] = IIx[ixp,ix] - end - end + ix = nx; ixp = nx + for iyp in 1:ny + for iy in 1:ny + ic = icfunc(ix,iy,nx) + icp = icfunc(ixp,iyp,nx) + LLc[icp,ic] = IIy[iyp,iy] + end end - println("Initialised 2D arrays") - if nc < 30 - print_matrix(LLc,"LLc",nc,nc) - end - println("condition number(LLc): ", cond(LLc)) - println("determinant(LLc): ", det(LLc)) - LLc_lu_obj = lu(LLc) - println("Initialised 2D solve") - # do elliptic solve - Fc = LLc_lu_obj\Sc - #reshape to 2D vector - for ic in 1:nc - ix = ixfunc(ic,nx) - iy = iyfunc(ic,nx) - Fxy[ix,iy] = Fc[ic] + iy = ny; iyp = ny + for ixp in 1:nx + for ix in 1:nx + ic = icfunc(ix,iy,nx) + icp = icfunc(ixp,iyp,nx) + LLc[icp,ic] = IIx[ixp,ix] + end end - #if dHdvpa_test && dirichlet_zero - # for iy in 1:ny - # for ix in 1:nx - # Fxy[ix,iy] += dHdvpa_inf(x,y,ix,iy) - # end - # end - #end - println("Finished 2D solve") - @. Fxy_err = abs(Fxy - Fxy_exact) - - println("maximum(Fxy_err)",maximum(Fxy_err)) - #println("Fxy_err",Fxy_err[1,:]) - #println("Fxy_exact",Fxy_exact[1,:]) - #println("Fxy",Fxy[1,:]) - @views heatmap(y.grid, x.grid, Fxy_exact[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, - windowsize = (360,240), margin = 15pt) - outfile = string("Fxy_exact_2D_solve.pdf") - savefig(outfile) - @views heatmap(y.grid, x.grid, Fxy[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, - windowsize = (360,240), margin = 15pt) - outfile = string("Fxy_num_2D_solve.pdf") - savefig(outfile) - @views heatmap(y.grid, x.grid, Fxy_err[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, - windowsize = (360,240), margin = 15pt) - outfile = string("Fxy_err_2D_solve.pdf") - savefig(outfile) end + println("Initialised 2D arrays") + if nc < 30 + print_matrix(LLc,"LLc",nc,nc) + end + println("condition number(LLc): ", cond(LLc)) + println("determinant(LLc): ", det(LLc)) + LLc_lu_obj = lu(LLc) + println("Initialised 2D solve") + # do elliptic solve + Fc = LLc_lu_obj\Sc + #reshape to 2D vector + for ic in 1:nc + ix = ixfunc(ic,nx) + iy = iyfunc(ic,nx) + Fxy[ix,iy] = Fc[ic] + end + #if dHdvpa_test && dirichlet_zero + # for iy in 1:ny + # for ix in 1:nx + # Fxy[ix,iy] += dHdvpa_inf(x,y,ix,iy) + # end + # end + #end + println("Finished 2D solve") + @. Fxy_err = abs(Fxy - Fxy_exact) + + println("maximum(Fxy_err)",maximum(Fxy_err)) + #println("Fxy_err",Fxy_err[1,:]) + #println("Fxy_exact",Fxy_exact[1,:]) + #println("Fxy",Fxy[1,:]) + @views heatmap(y.grid, x.grid, Fxy_exact[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, + windowsize = (360,240), margin = 15pt) + outfile = string("Fxy_exact_2D_solve.pdf") + savefig(outfile) + @views heatmap(y.grid, x.grid, Fxy[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, + windowsize = (360,240), margin = 15pt) + outfile = string("Fxy_num_2D_solve.pdf") + savefig(outfile) + @views heatmap(y.grid, x.grid, Fxy_err[:,:], xlabel=L"y", ylabel=L"x", c = :deep, interpolation = :cubic, + windowsize = (360,240), margin = 15pt) + outfile = string("Fxy_err_2D_solve.pdf") + savefig(outfile) end diff --git a/test_scripts/chebyshev_radau_test.jl b/test_scripts/chebyshev_radau_test.jl index a4d7d6b65..b832c9412 100644 --- a/test_scripts/chebyshev_radau_test.jl +++ b/test_scripts/chebyshev_radau_test.jl @@ -5,9 +5,9 @@ using MPI import moment_kinetics using moment_kinetics.chebyshev -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.calculus: derivative! +using moment_kinetics.type_definitions: OptionsDict function print_matrix(matrix,name,n,m) @@ -46,10 +46,8 @@ function chebyshevradau_test(; ngrid=5, L_in=3.0, discretization="chebyshev_pseu y_nelement_global = y_nelement_local # total number of elements y_L = L_in bc = "zero" - # fd_option and adv_input not actually used so given values unimportant fd_option = "fourth_order_centered" cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) nrank = 1 irank = 0#1 comm = MPI.COMM_NULL @@ -57,9 +55,16 @@ function chebyshevradau_test(; ngrid=5, L_in=3.0, discretization="chebyshev_pseu # create the 'input' struct containing input info needed to create a # coordinate y_name = "vperp" # to use radau grid - y_input = grid_input(y_name, y_ngrid, y_nelement_global, y_nelement_local, - nrank, irank, y_L, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - y, y_spectral = define_coordinate(y_input) + input = OptionsDict(y_name => OptionsDict("ngrid"=>y_ngrid, "nelement"=>y_nelement_global, + "nelement_local"=>y_nelement_local, "L"=>y_L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>bc, + "element_spacing_option"=>element_spacing_option)) + # create the coordinate struct 'x' + # This test runs effectively in serial, so use `ignore_MPI=true` to avoid + # errors due to communicators not being fully set up. + y, y_spectral = define_coordinate(input, y_name; ignore_MPI=true) Dmat = y_spectral.radau.Dmat print_matrix(Dmat,"Radau Dmat",y.ngrid,y.ngrid) diff --git a/test_scripts/fkpl_direct_integration_test.jl b/test_scripts/fkpl_direct_integration_test.jl index 06e6aeec2..da286fd07 100644 --- a/test_scripts/fkpl_direct_integration_test.jl +++ b/test_scripts/fkpl_direct_integration_test.jl @@ -8,7 +8,6 @@ using MPI using Dates import moment_kinetics -using moment_kinetics.input_structs: grid_input, advection_input using moment_kinetics.coordinates: define_coordinate using moment_kinetics.fokker_planck: init_fokker_planck_collisions_direct_integration using moment_kinetics.fokker_planck_calculus: calculate_rosenbluth_potentials_via_direct_integration! @@ -78,21 +77,20 @@ function init_grids(nelement,ngrid) fd_option = "fourth_order_centered" cheb_option = "matrix" element_spacing_option = "uniform" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = MPI.COMM_NULL # create the 'input' struct containing input info needed to create a # coordinate - vpa_input = grid_input("vpa", vpa_ngrid, vpa_nelement_global, vpa_nelement_local, - nrank, irank, vpa_L, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - vperp_input = grid_input("vperp", vperp_ngrid, vperp_nelement_global, vperp_nelement_local, - nrank, irank, vperp_L, discretization, fd_option, cheb_option, bc, adv_input,comm,element_spacing_option) - + coords_input = OptionsDict( + "vperp"=>OptionsDict("ngrid"=>vperp_ngrid, "nelement"=>vperp_nelement_global, + "nelement_local"=>vperp_nelement_local, "L"=>vperp_L, + "element_spacing_option"=>element_spacing_option), + "vpa"=>OptionsDict("ngrid"=>vpa_ngrid, "nelement"=>vpa_nelement_global, + "nelement_local"=>vpa_nelement_local, "L"=>vpa_L, + "discretization"=>discretization, + "element_spacing_option"=>element_spacing_option), + ) # create the coordinate structs - #println("made inputs") - vpa, vpa_spectral = define_coordinate(vpa_input) - vperp, vperp_spectral = define_coordinate(vperp_input) + vperp, vperp_spectral = define_coordinate(coords_input, "vperp") + vpa, vpa_spectral = define_coordinate(coords_input, "vpa") return vpa, vperp, vpa_spectral, vperp_spectral end diff --git a/test_scripts/gyroaverage_test.jl b/test_scripts/gyroaverage_test.jl index eb1c3bcb6..5550e33b4 100644 --- a/test_scripts/gyroaverage_test.jl +++ b/test_scripts/gyroaverage_test.jl @@ -8,14 +8,15 @@ using Measures using SpecialFunctions: besselj0 import moment_kinetics -using moment_kinetics.input_structs using moment_kinetics.coordinates: define_coordinate +using moment_kinetics.input_structs using moment_kinetics.geo: init_magnetic_geometry using moment_kinetics.communication using moment_kinetics.looping using moment_kinetics.array_allocation: allocate_float, allocate_shared_float using moment_kinetics.gyroaverages: gyroaverage_pdf! using moment_kinetics.gyroaverages: gyroaverage_field!, init_gyro_operators +using moment_kinetics.species_input: get_species_input using moment_kinetics.type_definitions: mk_float, mk_int function print_matrix(matrix,name::String,n::mk_int,m::mk_int) @@ -71,41 +72,62 @@ function gyroaverage_test(;rhostar=0.1, pitch=0.5, ngrid=5, kr=2, kz=2, phaser=0 gyrophase_discretization = "finite_difference" gyrophase_L = 2.0*pi - # fd_option and adv_input not actually used so given values unimportant fd_option = "fourth_order_centered" cheb_option = "matrix" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0#1 - comm = MPI.COMM_NULL element_spacing_option = "uniform" # create the 'input' struct containing input info needed to create a # coordinate - r_input = grid_input("r", r_ngrid, r_nelement_global, r_nelement_local, - nrank, irank, r_L, discretization, fd_option, cheb_option, r_bc, adv_input,comm,element_spacing_option) - z_input = grid_input("z", z_ngrid, z_nelement_global, z_nelement_local, - nrank, irank, z_L, discretization, fd_option, cheb_option, z_bc, adv_input,comm,element_spacing_option) - vperp_input = grid_input("vperp", vperp_ngrid, vperp_nelement_global, vperp_nelement_local, - nrank, irank, vperp_L, discretization, fd_option, cheb_option, vperp_bc, adv_input,comm,element_spacing_option) - vpa_input = grid_input("vpa", vpa_ngrid, vpa_nelement_global, vpa_nelement_local, - nrank, irank, vpa_L, discretization, fd_option, cheb_option, vpa_bc, adv_input,comm,element_spacing_option) - gyrophase_input = grid_input("gyrophase", gyrophase_ngrid, gyrophase_nelement_global, gyrophase_nelement_local, - nrank, irank, gyrophase_L, gyrophase_discretization, fd_option, cheb_option, "periodic", adv_input,comm,element_spacing_option) + coords_input = OptionsDict( + "r"=>OptionsDict("ngrid"=>r_ngrid, "nelement"=>r_nelement_global, + "nelement_local"=>r_nelement_local, "L"=>r_L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>r_bc, + "element_spacing_option"=>element_spacing_option), + "z"=>OptionsDict("ngrid"=>z_ngrid, "nelement"=>z_nelement_global, + "nelement_local"=>z_nelement_local, "L"=>z_L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>z_bc, + "element_spacing_option"=>element_spacing_option), + "vperp"=>OptionsDict("ngrid"=>vperp_ngrid, "nelement"=>vperp_nelement_global, + "nelement_local"=>vperp_nelement_local, "L"=>vperp_L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>vperp_bc, + "element_spacing_option"=>element_spacing_option), + "vpa"=>OptionsDict("ngrid"=>vpa_ngrid, "nelement"=>vpa_nelement_global, + "nelement_local"=>vpa_nelement_local, "L"=>vpa_L, + "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>vpa_bc, + "element_spacing_option"=>element_spacing_option), + "gyrophase"=>OptionsDict("ngrid"=>gyrophase_ngrid, + "nelement"=>gyrophase_nelement_global, + "nelement_local"=>gyrophase_nelement_local, + "L"=>gyrophase_L, "discretization"=>discretization, + "finite_difference_option"=>fd_option, + "cheb_option"=>cheb_option, "bc"=>"periodic", + "element_spacing_option"=>element_spacing_option), + ) # create the coordinate structs - r, r_spectral = define_coordinate(r_input,init_YY=false) - z, z_spectral = define_coordinate(z_input,init_YY=false) - vperp, vperp_spectral = define_coordinate(vperp_input,init_YY=false) - vpa, vpa_spectral = define_coordinate(vpa_input,init_YY=false) - gyrophase, gyrophase_spectral = define_coordinate(gyrophase_input,init_YY=false) + r, r_spectral = define_coordinate(coords_input, "r"; collision_operator_dim=false) + z, z_spectral = define_coordinate(coords_input, "z"; collision_operator_dim=false) + vperp, vperp_spectral = define_coordinate(coords_input, "vperp"; + collision_operator_dim=false) + vpa, vpa_spectral = define_coordinate(coords_input, "vpa"; + collision_operator_dim=false) + gyrophase, gyrophase_spectral = define_coordinate(coords_input, "gyrophase"; + collision_operator_dim=false) # create test geometry #rhostar = 0.1 #rhostar of ions for ExB drift option = "constant-helical" #pitch = 1.0 DeltaB = 1.0 - geometry_in = geometry_input(rhostar,option,pitch,DeltaB) + geometry_in = geometry_input(rhostar,option,pitch,DeltaB,0.0,0.0,0.0,0.0) geometry = init_magnetic_geometry(geometry_in,z,r) # create test composition @@ -132,7 +154,7 @@ function gyroaverage_test(;rhostar=0.1, pitch=0.5, ngrid=5, kr=2, kz=2, phaser=0 end # gyroaverage phi - gyroaverage_field!(gphi,phi,gyro,vperp,z,r) + gyroaverage_field!(gphi,phi,gyro,vperp,z,r,composition) # compute errors begin_serial_region() @@ -214,9 +236,13 @@ function create_test_composition() # `recycling_fraction` to account for ions absorbed by the wall. recycling_fraction = 1.0 gyrokinetic_ions = true - return composition = species_composition(n_species, n_ion_species, n_neutral_species, - electron_physics, use_test_neutral_wall_pdf, T_e, T_wall, phi_wall, Er_constant, - mn_over_mi, me_over_mi, recycling_fraction, gyrokinetic_ions, allocate_float(n_species)) + species_opts = OptionsDict("n_ion_species" => n_ion_species, + "n_neutral_species" => n_neutral_species, "T_e" => T_e, + "T_wall" => T_wall, "phi_wall" => phi_wall, + "mn_over_mi" => mn_over_mi, "me_over_mi" => me_over_mi, + "recycling_fraction" => recycling_fraction, + "gyrokinetic_ions" => gyrokinetic_ions) + return get_species_input(OptionsDict("composition" => species_opts)) end function fill_test_arrays!(phi,gphi,vperp,z,r,geometry,kz,kr,phasez,phaser) diff --git a/test_scripts/spline_derivatives_test.jl b/test_scripts/spline_derivatives_test.jl deleted file mode 100644 index 1deb5d718..000000000 --- a/test_scripts/spline_derivatives_test.jl +++ /dev/null @@ -1,95 +0,0 @@ -if abspath(PROGRAM_FILE) == @__FILE__ - using Pkg - Pkg.activate(".") - - import moment_kinetics - using moment_kinetics.input_structs: grid_input, advection_input - using moment_kinetics.coordinates: define_coordinate - using moment_kinetics.chebyshev: setup_chebyshev_pseudospectral - using moment_kinetics.calculus: derivative!, integral #derivative_handle_wall_bc! - using Plots - - discretization = "chebyshev_pseudospectral" - #discretization = "finite_difference" - etol = 1.0e-15 - outprefix = "derivative_test" - ################### - ## df/dx Nonperiodic (No) BC test - ################### - - # define inputs needed for the test - ngrid = 17 #number of points per element - nelement_local = 4 # number of elements per rank - nelement_global = nelement_local # total number of elements - L = 1.0 #physical box size in reference units - # fd_option and adv_input not actually used so given values unimportant - fd_option = "fourth_order_centered" - adv_input = advection_input("default", 1.0, 0.0, 0.0) - nrank = 1 - irank = 0 - comm = false - # create the 'input' struct containing input info needed to create a - # coordinate - x_input = grid_input("coord", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "", adv_input,comm) - z_input = grid_input("coord", ngrid, nelement_global, nelement_local, - nrank, irank, L, discretization, fd_option, "wall", adv_input,comm) - # create the coordinate struct 'x' - println("made inputs") - x = define_coordinate(x_input) - z = define_coordinate(z_input) - println("made x") - # create arrays needed for Chebyshev pseudospectral treatment in x - # and create the plans for the forward and backward fast Chebyshev - # transforms - if discretization == "chebyshev_pseudospectral" - spectral = setup_chebyshev_pseudospectral(x) - else - spectral = false - end - println("made spectral") - # create array for the function f(x) to be differentiated/integrated - f = Array{Float64,1}(undef, x.n) - # create array for the derivative df/dx - df = Array{Float64,1}(undef, x.n) - df_opt = Array{Float64,1}(undef, x.n) - df_exact = Array{Float64,1}(undef, x.n) - vz = Array{Float64,1}(undef,x.n) - - - xcut = 0.125 - teststring = ".x2."*string(xcut) - ## x^2 test - for ix in 1:x.n - vz[ix] = x.grid[ix] - xcut - if x.grid[ix] > xcut - f[ix] = (x.grid[ix] - xcut)^2 - df_exact[ix] = 2.0*(x.grid[ix] - xcut) - else - f[ix] = 0.0 - df_exact[ix] = 0.0 - end - end - - # differentiate f using standard Chebyshev method - derivative!(df, f, x, spectral) - # differentiate f using Chebyshev with spline for subgrid differentiation - iz = 1 # a wall boundary point - derivative!(df_opt, f, x, spectral, iz, z, vz) - - # plot df, df_opt & df_exact - plot([x.grid,x.grid,x.grid], [vz, f,df_opt,df_exact], xlabel="x", ylabel="", label=["vz" "f" "df_opt" "df_exact"], - shape =:circle, markersize = 5, linewidth=2) - outfile = outprefix*teststring*".onlyspline.pdf" - savefig(outfile) - plot([x.grid,x.grid,x.grid], [f,df,df_opt,df_exact], xlabel="x", ylabel="", label=["f" "df_cheb" "df_opt" "df_exact"], - shape =:circle, markersize = 5, linewidth=2) - outfile = outprefix*teststring*".withspline.pdf" - savefig(outfile) - plot([x.grid,x.grid,x.grid], [f,df,df_exact], xlabel="x", ylabel="", label=["f" "df_cheb" "df_exact"], - shape =:circle, markersize = 5, linewidth=2) - outfile = outprefix*teststring*".pdf" - savefig(outfile) - -end - diff --git a/util/get-run-name.jl b/util/get-run-name.jl index fdbb66a59..ae228182d 100755 --- a/util/get-run-name.jl +++ b/util/get-run-name.jl @@ -20,7 +20,10 @@ end input = TOML.parsefile(inputfile) if "run_name" ∈ keys(input) + # Old position for option run_name = input["run_name"] +elseif "output" ∈ keys(input) && "run_name" ∈ keys(input["output"]) + run_name = input["output"]["run_name"] else # For branch with run name from input file name, should handle that here... run_name = basename(splitext(inputfile)[1]) diff --git a/util/precompile_makie_plots.jl b/util/precompile_makie_plots.jl index 132556e93..7ef17e57f 100644 --- a/util/precompile_makie_plots.jl +++ b/util/precompile_makie_plots.jl @@ -7,42 +7,42 @@ test_output_directory = tempname() run_name = "precompilation" mkpath(test_output_directory) -input_dict = Dict("run_name"=>run_name, - "base_directory" => test_output_directory, - "r_ngrid" => 5, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 5, - "z_nelement" => 1, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 5, - "vperp_nelement" => 1, - #"vperp_bc" => "periodic", - "vperp_L" => 4.0, - "vperp_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 7, - "vpa_nelement" => 1, - "vpa_bc" => "periodic", - "vpa_L" => 4.0, - "vpa_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 7, - "vzeta_nelement" => 1, - "vzeta_bc" => "periodic", - "vzeta_L" => 4.0, - "vzeta_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 7, - "vr_nelement" => 1, - "vr_bc" => "periodic", - "vr_L" => 4.0, - "vr_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 7, - "vz_nelement" => 1, - "vz_bc" => "periodic", - "vz_L" => 4.0, - "vz_discretization" => "chebyshev_pseudospectral", - "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) +input_dict = OptionsDict("output" => OptionsDict("run_name"=>run_name, + "base_directory" => test_output_directory), + "r" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 5, + "nelement" => 1, + #"bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vzeta" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vr" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) run_moment_kinetics(input_dict) diff --git a/util/precompile_plots_plots.jl b/util/precompile_plots_plots.jl index e299919fc..595f7d42a 100644 --- a/util/precompile_plots_plots.jl +++ b/util/precompile_plots_plots.jl @@ -7,42 +7,42 @@ test_output_directory = tempname() run_name = "precompilation" mkpath(test_output_directory) -input_dict = Dict("run_name"=>run_name, - "base_directory" => test_output_directory, - "r_ngrid" => 5, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 5, - "z_nelement" => 1, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 5, - "vperp_nelement" => 1, - #"vperp_bc" => "periodic", - "vperp_L" => 4.0, - "vperp_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 7, - "vpa_nelement" => 1, - "vpa_bc" => "periodic", - "vpa_L" => 4.0, - "vpa_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 7, - "vzeta_nelement" => 1, - "vzeta_bc" => "periodic", - "vzeta_L" => 4.0, - "vzeta_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 7, - "vr_nelement" => 1, - "vr_bc" => "periodic", - "vr_L" => 4.0, - "vr_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 7, - "vz_nelement" => 1, - "vz_bc" => "periodic", - "vz_L" => 4.0, - "vz_discretization" => "chebyshev_pseudospectral", - "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) +input_dict = OptionsDict("output" => OptionsDict("run_name"=>run_name, + "base_directory" => test_output_directory), + "r" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 5, + "nelement" => 1, + #"bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vzeta" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vr" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 7, + "nelement" => 1, + "bc" => "periodic", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) run_moment_kinetics(input_dict) diff --git a/util/precompile_run.jl b/util/precompile_run.jl index 41f6b1d57..09158e055 100644 --- a/util/precompile_run.jl +++ b/util/precompile_run.jl @@ -3,105 +3,108 @@ using Pkg Pkg.activate(".") using moment_kinetics +using moment_kinetics.utils: recursive_merge using moment_kinetics.type_definitions: OptionsDict # Create a temporary directory for test output test_output_directory = tempname() mkpath(test_output_directory) -base_input = Dict("run_name" => "precompilation", - "base_directory" => test_output_directory, - "r_ngrid" => 5, - "r_nelement" => 3, - "r_bc" => "periodic", - "r_discretization" => "finite_difference", - "z_ngrid" => 5, - "z_nelement" => 3, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vperp_ngrid" => 5, - "vperp_nelement" => 3, - "vperp_bc" => "zero", - "vperp_L" => 4.0, - "vperp_discretization" => "finite_difference", - "vpa_ngrid" => 7, - "vpa_nelement" => 3, - "vpa_bc" => "zero", - "vpa_L" => 8.0, - "vpa_discretization" => "finite_difference", - "vzeta_ngrid" => 5, - "vzeta_nelement" => 3, - "vzeta_bc" => "zero", - "vzeta_L" => 4.0, - "vzeta_discretization" => "finite_difference", - "vr_ngrid" => 5, - "vr_nelement" => 3, - "vr_bc" => "zero", - "vr_L" => 4.0, - "vr_discretization" => "finite_difference", - "vz_ngrid" => 7, - "vz_nelement" => 3, - "vz_bc" => "zero", - "vz_L" => 8.0, - "vz_discretization" => "finite_difference", - "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) -cheb_input = merge(base_input, Dict("r_discretization" => "chebyshev_pseudospectral", - "z_discretization" => "chebyshev_pseudospectral", - "vperp_discretization" => "chebyshev_pseudospectral", - "vpa_discretization" => "chebyshev_pseudospectral")) -wall_bc_input = merge(base_input, Dict("z_bc" => "wall")) -wall_bc_cheb_input = merge(cheb_input, Dict("z_bc" => "wall")) +base_input = OptionsDict("output" => OptionsDict("run_name" => "precompilation", + "base_directory" => test_output_directory), + "r" => OptionsDict("ngrid" => 5, + "nelement" => 3, + "bc" => "periodic", + "discretization" => "finite_difference"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 3, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vperp" => OptionsDict("ngrid" => 5, + "nelement" => 3, + "bc" => "zero", + "L" => 4.0, + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 7, + "nelement" => 3, + "bc" => "zero", + "L" => 8.0, + "discretization" => "finite_difference"), + "vzeta" => OptionsDict("ngrid" => 5, + "nelement" => 3, + "bc" => "zero", + "L" => 4.0, + "discretization" => "finite_difference"), + "vr" => OptionsDict("ngrid" => 5, + "nelement" => 3, + "bc" => "zero", + "L" => 4.0, + "discretization" => "finite_difference"), + "vz" => OptionsDict("ngrid" => 7, + "nelement" => 3, + "bc" => "zero", + "L" => 8.0, + "discretization" => "finite_difference"), + "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) +cheb_input = recursive_merge(base_input, OptionsDict("r" => OptionsDict("discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral"))) +wall_bc_input = recursive_merge(base_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) +wall_bc_cheb_input = recursive_merge(cheb_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) -inputs_list = Vector{Dict{String, Any}}(undef, 0) +inputs_list = Vector{OptionsDict}(undef, 0) for input ∈ [base_input, cheb_input, wall_bc_input, wall_bc_cheb_input] push!(inputs_list, input) - x = merge(input, Dict("evolve_moments_density" => true, "ionization_frequency" => 0.0, - "r_ngrid" => 1, "r_nelement" => 1, "vperp_ngrid" => 1, - "vperp_nelement" => 1, "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, "vr_ngrid" => 1, "vr_nelement" => 1)) + x = recursive_merge(input, OptionsDict("evolve_moments" => OptionsDict("density" => true), + "reactions" => OptionsDict("ionization_frequency" => 0.0), + "r" => OptionsDict("ngrid" => 1, "nelement" => 1), + "vperp" => OptionsDict("ngrid" => 1, "nelement" => 1), + "vzeta" => OptionsDict("ngrid" => 1, "nelement" => 1), + "vr" => OptionsDict("ngrid" => 1, "nelement" => 1))) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_flow" => true)) + x = recursive_merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_flow" => true))) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_pressure" => true)) + x = recursive_merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_pressure" => true))) push!(inputs_list, x) end -collisions_input1 = merge(wall_bc_cheb_input, Dict( "composition" => OptionsDict("n_neutral_species" => 0), - "krook_collisions" => OptionsDict("use_krook" => true), - "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "self_collisions" => true, "slowing_down_test" => true), - "vperp_discretization" => "gausslegendre_pseudospectral", - "vpa_discretization" => "gausslegendre_pseudospectral", - )) -collisions_input2 = merge(wall_bc_cheb_input, Dict("composition" => OptionsDict("n_neutral_species" => 0), - "krook_collisions" => OptionsDict("use_krook" => true), - "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "self_collisions" => true, "slowing_down_test" => true), - "vperp_discretization" => "gausslegendre_pseudospectral", - "vpa_discretization" => "gausslegendre_pseudospectral", - "vperp_bc" => "zero-impose-regularity", - )) +collisions_input1 = recursive_merge(wall_bc_cheb_input, OptionsDict("composition" => OptionsDict("n_neutral_species" => 0), + "krook_collisions" => OptionsDict("use_krook" => true), + "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "self_collisions" => true, "slowing_down_test" => true), + "vperp" => OptionsDict("discretization" => "gausslegendre_pseudospectral"), + "vpa" => OptionsDict("discretization" => "gausslegendre_pseudospectral"), + )) +collisions_input2 = recursive_merge(wall_bc_cheb_input, OptionsDict("composition" => OptionsDict("n_neutral_species" => 0), + "krook_collisions" => OptionsDict("use_krook" => true), + "fokker_planck_collisions" => OptionsDict("use_fokker_planck" => true, "self_collisions" => true, "slowing_down_test" => true), + "vperp" => OptionsDict("discretization" => "gausslegendre_pseudospectral", + "bc" => "zero-impose-regularity"), + "vpa" => OptionsDict("discretization" => "gausslegendre_pseudospectral"), + )) # add an additional input for every geometry option available in addition to the default -geo_input1 = merge(wall_bc_cheb_input, Dict("composition" => OptionsDict("n_neutral_species" => 0), - "geometry" => OptionsDict("option" => "1D-mirror", "DeltaB" => 0.5, "pitch" => 0.5, "rhostar" => 1.0))) +geo_input1 = recursive_merge(wall_bc_cheb_input, OptionsDict("composition" => OptionsDict("n_neutral_species" => 0), + "geometry" => OptionsDict("option" => "1D-mirror", "DeltaB" => 0.5, "pitch" => 0.5, "rhostar" => 1.0))) -kinetic_electron_input = merge(cheb_input, Dict("evolve_moments_density" => true, - "evolve_moments_parallel_flow" => true, - "evolve_moments_parallel_pressure" => true, - "r_ngrid" => 1, - "r_nelement" => 1, - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, - "vr_ngrid" => 1, - "vr_nelement" => 1, - "composition" => OptionsDict("electron_physics" => "kinetic_electrons"), - "electron_timestepping" => OptionsDict("nstep" => 1, - "dt" => 2.0e-11, - "initialization_residual_value" => 1.0e10, - "converged_residual_value" => 1.0e10, - "rtol" => 1.0e10, - "no_restart" => true), - )) +kinetic_electron_input = recursive_merge(cheb_input, OptionsDict("evolve_moments" => OptionsDict("density" => true, + "parallel_flow" => true, + "parallel_pressure" => true), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vzeta" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "vr" => OptionsDict("ngrid" => 1, + "nelement" => 1), + "composition" => OptionsDict("electron_physics" => "kinetic_electrons"), + "electron_timestepping" => OptionsDict("nstep" => 1, + "dt" => 2.0e-11, + "initialization_residual_value" => 1.0e10, + "converged_residual_value" => 1.0e10, + "rtol" => 1.0e10, + "no_restart" => true), + )) push!(inputs_list, collisions_input1, collisions_input2, geo_input1, kinetic_electron_input) diff --git a/util/precompile_run_kinetic-electrons.jl b/util/precompile_run_kinetic-electrons.jl index 212d9f9bf..28e8957e7 100644 --- a/util/precompile_run_kinetic-electrons.jl +++ b/util/precompile_run_kinetic-electrons.jl @@ -9,53 +9,53 @@ using moment_kinetics.type_definitions: OptionsDict test_output_directory = tempname() mkpath(test_output_directory) -input = Dict("run_name" => "precompilation", - "base_directory" => test_output_directory, - "evolve_moments_density" => true, - "evolve_moments_parallel_flow" => true, - "evolve_moments_parallel_pressure" => true, - "composition" => OptionsDict("electron_physics" => "kinetic_electrons"), - "r_ngrid" => 1, - "r_nelement" => 1, - "r_bc" => "periodic", - "r_discretization" => "chebyshev_pseudospectral", - "z_ngrid" => 5, - "z_nelement" => 4, - "z_bc" => "wall", - "z_discretization" => "chebyshev_pseudospectral", - "vperp_ngrid" => 1, - "vperp_nelement" => 1, - "vperp_bc" => "zero", - "vperp_L" => 4.0, - "vperp_discretization" => "chebyshev_pseudospectral", - "vpa_ngrid" => 7, - "vpa_nelement" => 8, - "vpa_bc" => "zero", - "vpa_L" => 8.0, - "vpa_discretization" => "chebyshev_pseudospectral", - "vzeta_ngrid" => 1, - "vzeta_nelement" => 1, - "vzeta_bc" => "zero", - "vzeta_L" => 4.0, - "vzeta_discretization" => "chebyshev_pseudospectral", - "vr_ngrid" => 1, - "vr_nelement" => 1, - "vr_bc" => "zero", - "vr_L" => 4.0, - "vr_discretization" => "chebyshev_pseudospectral", - "vz_ngrid" => 7, - "vz_nelement" => 8, - "vz_bc" => "zero", - "vz_L" => 8.0, - "vz_discretization" => "chebyshev_pseudospectral", - "timestepping" => OptionsDict("nstep" => 1, - "dt" => 2.0e-11), - "electron_timestepping" => OptionsDict("nstep" => 1, - "dt" => 2.0e-11, - "initialization_residual_value" => 1.0e10, - "converged_residual_value" => 1.0e10, - "rtol" => 1.0e10, - "no_restart" => true)) +input = OptionsDict("output" => OptionsDict("run_name" => "precompilation", + "base_directory" => test_output_directory), + "evolve_moments" => OptionsDict("density" => true, + "parallel_flow" => true, + "parallel_pressure" => true), + "composition" => OptionsDict("electron_physics" => "kinetic_electrons"), + "r" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "chebyshev_pseudospectral"), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 4, + "bc" => "wall", + "discretization" => "chebyshev_pseudospectral"), + "vperp" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "zero", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("ngrid" => 7, + "nelement" => 8, + "bc" => "zero", + "L" => 8.0, + "discretization" => "chebyshev_pseudospectral"), + "vzeta" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "zero", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vr" => OptionsDict("ngrid" => 1, + "nelement" => 1, + "bc" => "zero", + "L" => 4.0, + "discretization" => "chebyshev_pseudospectral"), + "vz" => OptionsDict("ngrid" => 7, + "nelement" => 8, + "bc" => "zero", + "L" => 8.0, + "discretization" => "chebyshev_pseudospectral"), + "timestepping" => OptionsDict("nstep" => 1, + "dt" => 2.0e-11), + "electron_timestepping" => OptionsDict("nstep" => 1, + "dt" => 2.0e-11, + "initialization_residual_value" => 1.0e10, + "converged_residual_value" => 1.0e10, + "rtol" => 1.0e10, + "no_restart" => true)) run_moment_kinetics(input) diff --git a/util/precompile_run_long.jl b/util/precompile_run_long.jl index 441935757..ce139406b 100644 --- a/util/precompile_run_long.jl +++ b/util/precompile_run_long.jl @@ -7,35 +7,37 @@ Pkg.activate(".") using moment_kinetics using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge # Create a temporary directory for test output test_output_directory = tempname() mkpath(test_output_directory) -base_input = Dict("run_name"=>"precompilation", - "base_directory" => test_output_directory, - "z_ngrid" => 5, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 5, - "vpa_nelement" => 1, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) -cheb_input = merge(base_input, Dict("z_discretization" => "chebyshev_pseudospectral", - "vpa_discretization" => "chebyshev_pseudospectral")) -wall_bc_input = merge(base_input, Dict("z_bc" => "wall")) -wall_bc_cheb_input = merge(cheb_input, Dict("z_bc" => "wall")) +base_input = OptionsDict("output" => OptionsDict("run_name"=>"precompilation", + "base_directory" => test_output_directory), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) +cheb_input = recursive_merge(base_input, OptionsDict("z" => OptionsDict("discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral"))) +wall_bc_input = recursive_merge(base_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) +wall_bc_cheb_input = recursive_merge(cheb_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) inputs_list = Vector{OptionsDict}(undef, 0) for input ∈ [base_input, cheb_input, wall_bc_input, wall_bc_cheb_input] push!(inputs_list, input) - x = merge(input, Dict("evolve_moments_density" => true, "ionization_frequency" => 0.0)) + x = recursive_merge(input, OptionsDict("evolve_moments" => OptionsDict("density" => true), + "reactions" => OptionsDict("ionization_frequency" => 0.0))) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_flow" => true)) + x = recursive_merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_flow" => true))) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_pressure" => true)) + x = recursive_merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_pressure" => true))) push!(inputs_list, x) end diff --git a/util/precompile_run_long_debug1.jl b/util/precompile_run_long_debug1.jl index dbc009bfa..228be341b 100644 --- a/util/precompile_run_long_debug1.jl +++ b/util/precompile_run_long_debug1.jl @@ -7,35 +7,37 @@ Pkg.activate(".") using moment_kinetics using moment_kinetics.type_definitions: OptionsDict +using moment_kinetics.utils: recursive_merge # Create a temporary directory for test output test_output_directory = tempname() mkpath(test_output_directory) -base_input = Dict("run_name"=>"precompilation", - "base_directory" => test_output_directory, - "z_ngrid" => 5, - "z_nelement" => 1, - "z_bc" => "periodic", - "z_discretization" => "finite_difference", - "vpa_ngrid" => 5, - "vpa_nelement" => 1, - "vpa_bc" => "periodic", - "vpa_discretization" => "finite_difference", - "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) -cheb_input = merge(base_input, Dict("z_discretization" => "chebyshev_pseudospectral", - "vpa_discretization" => "chebyshev_pseudospectral")) -wall_bc_input = merge(base_input, Dict("z_bc" => "wall")) -wall_bc_cheb_input = merge(cheb_input, Dict("z_bc" => "wall")) +base_input = OptionsDict("output" => OptionsDict("run_name"=>"precompilation", + "base_directory" => test_output_directory), + "z" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "vpa" => OptionsDict("ngrid" => 5, + "nelement" => 1, + "bc" => "periodic", + "discretization" => "finite_difference"), + "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) +cheb_input = recursive_merge(base_input, OptionsDict("z" => OptionsDict("discretization" => "chebyshev_pseudospectral"), + "vpa" => OptionsDict("discretization" => "chebyshev_pseudospectral"))) +wall_bc_input = recursive_merge(base_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) +wall_bc_cheb_input = recursive_merge(cheb_input, OptionsDict("z" => OptionsDict("bc" => "wall"))) inputs_list = Vector{OptionsDict}(undef, 0) for input ∈ [base_input, cheb_input, wall_bc_input, wall_bc_cheb_input] push!(inputs_list, input) - x = merge(input, Dict("evolve_moments_density" => true, "ionization_frequency" => 0.0)) + x = merge(input, OptionsDict("evolve_moments" => OptionsDict("density" => true), + "ionization_frequency" => 0.0)) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_flow" => true)) + x = merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_flow" => true))) push!(inputs_list, x) - x = merge(x, Dict("evolve_moments_parallel_pressure" => true)) + x = merge(x, OptionsDict("evolve_moments" => OptionsDict("parallel_pressure" => true))) push!(inputs_list, x) end diff --git a/util/precompile_run_short.jl b/util/precompile_run_short.jl index 458cf803f..468ce6149 100644 --- a/util/precompile_run_short.jl +++ b/util/precompile_run_short.jl @@ -9,8 +9,8 @@ using moment_kinetics.type_definitions: OptionsDict test_output_directory = tempname() mkpath(test_output_directory) -input_dict = Dict("run_name"=>"precompilation", - "base_directory" => test_output_directory, +input_dict = Dict("output" => OptionsDict("run_name"=>"precompilation", + "base_directory" => test_output_directory), "timestepping" => OptionsDict("nstep" => 1, "dt" => 2.0e-11)) to = TimerOutput()