Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial functionality for partially-implicit 'IMEX' timestepping #219

Merged
merged 75 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
b32accf
Remove update_chodura!() call from time_advance!()
johnomotani May 7, 2024
eaefdb9
Fix timestep diagnostics after addition of gyroaveraging feature
johnomotani May 6, 2024
7790cdd
Use distributed-MPI parallelism in more of the tests
johnomotani May 8, 2024
0366cb8
Support selecting a subset of time points in timestep_diagnostics()
johnomotani May 12, 2024
bf2862a
Record which variable had largest error norm when RK accuracy limited dt
johnomotani May 9, 2024
e749e2e
Use some different line styles so limit_caused_by plot is easier to read
johnomotani May 9, 2024
14fec1d
Try to recover by decreasing timestep if error_norm is NaN
johnomotani May 8, 2024
2168703
Fix output time for adaptive timestep runs
johnomotani May 15, 2024
152f917
Fix CFL condition diagnostics for non-moment-kinetic runs
johnomotani May 17, 2024
1f9b8cd
Fix hard_force_moment_constraints!() for non-moment-kinetic case
johnomotani May 17, 2024
4bb6d55
Use dashed lines for neutral CFL limits
johnomotani May 17, 2024
805f27f
Use NaNMath when plotting CFL limits to avoid errors
johnomotani May 17, 2024
de88da2
Make use of `yscale` slightly more robust in plot_1d()
johnomotani May 22, 2024
f6dacc1
Fix y-axis limits when using log scale in animate_f_unnorm_vs_vpa
johnomotani May 22, 2024
1e3d52b
Plot 4 grid points near the boundary in wall plots, and add log plots
johnomotani May 22, 2024
c99e9f4
Comment out kinetic electron blocks in constraints_plots()
johnomotani May 22, 2024
3cff3eb
Handle Dirichlet bc in gausslegendre diffusion matrices
johnomotani May 22, 2024
0d3c06b
Fix post-processing loading of advection speeds
johnomotani May 26, 2024
b91769b
Check t_params.step_counter[] to write output when not adaptive
johnomotani May 7, 2024
3964b00
Re-apply output step fix with `just_completed_output_step`
johnomotani May 12, 2024
029bba4
Option to write after fixed step count when using adaptive timestep
johnomotani May 7, 2024
2b21389
Function for z-derivatives of 1D arrays
johnomotani May 8, 2024
434ac35
Simplify convert_butcher_tableau_for_moment_kinetics()
johnomotani Apr 29, 2024
3f2745c
Add IMEX support to calculate_rk_coeffs.jl
johnomotani Apr 30, 2024
9d7e2f8
Support IMEX schemes in test-rk-timestep.jl
johnomotani May 1, 2024
5c9cbd4
Split up rk_update!() function
johnomotani May 18, 2024
2dfab31
Add framework for IMEX timestepping
johnomotani May 2, 2024
3af052f
Jacobian-free Newton-Krylov (GMRES) nonlinear solver
johnomotani May 2, 2024
8dd9f29
Tests for nonlinear_solvers
johnomotani May 7, 2024
d964094
Add tuple of variable names that exist in output file to run_info
johnomotani May 8, 2024
251bbb7
Load and plot nonlinear solver diagnostics
johnomotani May 8, 2024
94ad3df
Leave t_input as a Dict so it can be modified by setup_time_advance()
johnomotani May 12, 2024
345f9fa
Implicit solve for vpa_advection term
johnomotani May 12, 2024
6c44675
Start working on preconditioner for implicit_vpa_advection!()
johnomotani May 12, 2024
aa1a8ac
Test both z and vpa coords in nonlinear_solver_tests.jl
johnomotani May 14, 2024
403c509
Option to re-factorise preconditioner only after certain interval
johnomotani May 14, 2024
1cdcdef
Fix application of boundary conditions in residual_func!()
johnomotani May 15, 2024
e085114
Include vpa diffusion when doing implicit vpa advection
johnomotani May 15, 2024
d339a7e
Include diffusion in preconditioner, assuming weak-form implementation
johnomotani May 15, 2024
cb8cc6b
Function to apply moment constraints to a 'residual'
johnomotani May 16, 2024
b952af2
Impose moment constraints on implicit-solve residual
johnomotani May 16, 2024
f8167f4
By default set nonlinear solver tols 1/10 times timesolver tols
johnomotani May 17, 2024
7b1737f
Simplify setup of output variables for time solver diagnostics
johnomotani May 17, 2024
b6cdca3
Timestep failure to decrease timestep when nonlinear iteration fails
johnomotani May 17, 2024
7b07c57
Fix IMEX time advance
johnomotani May 18, 2024
e344afa
Fix advance flags for numerical dissipation to work with IMEX
johnomotani May 18, 2024
7308209
Fix moment constraints for IMEX schemes
johnomotani May 18, 2024
04f4d1c
Separate ionization/CX collisions functions for ions/neutrals
johnomotani May 19, 2024
96d5cdc
Option for implicit advance of all terms in ion kinetic equation
johnomotani May 19, 2024
0d0ac3a
Consistently treat rtol/atol in distributed_norm() and distributed_dot()
johnomotani May 20, 2024
e3afc22
Optimise parallel_map() computations in nonlinear_solvers
johnomotani May 20, 2024
b02e70d
Variants of hard_force_moment_constraints!() that loop over spatial grid
johnomotani May 21, 2024
3365c3d
Separate 'advance flags' for ion and neutral numerical dissipation
johnomotani May 21, 2024
ee3eec9
Fudge factor to avoid unlikely but endless timestep-failure loop
johnomotani May 21, 2024
bbfaace
Prevent timestep increase when number of nonlinear iterations was large
johnomotani May 22, 2024
6876820
Allow using Chebyshev discretization in vpa advection preconditioner
johnomotani May 22, 2024
ec934dd
Check for duplicated entries in `advance` and `advance_implicit`
johnomotani May 22, 2024
d49a11f
Update derived moments and their derivatives in implicit solves for pdf
johnomotani May 22, 2024
a4738bc
Plot CFL conditions for implicit terms, but dotted
johnomotani May 26, 2024
f0a0bc1
Impose moment constraints on residual for implicit ion advance
johnomotani May 26, 2024
9b8bcef
Comment out preconditioner in implicit_vpa_advection!()
johnomotani May 26, 2024
c82fe05
Collect nonlinear solver diagnostics from all processes, where necessary
johnomotani May 26, 2024
c92e761
Increase 'epsilon' for approximate Jacobian calculation
johnomotani May 26, 2024
208e700
Decrease range of step sizes for line search in nonlinear solves
johnomotani May 26, 2024
baffe03
Remove extra status printouts
johnomotani May 29, 2024
5b3800c
Fix call to neutral_ionization_collisions_3V!()
johnomotani May 30, 2024
0a98a7a
Use nonlinear_max_iterations=100 to avoid warning messages from tests
johnomotani Jun 1, 2024
ec542b1
Fix for plotting of timestep diagnostics
johnomotani Jun 3, 2024
2033d7f
Make nonlinear solver tests work in parallel
johnomotani Jun 4, 2024
4d84e9b
Calculate low-order solution rather than error for adaptive RK schemes
johnomotani Jun 5, 2024
9e60f3e
Apply boundary conditions and constraints to low-order solution
johnomotani Jun 6, 2024
63fae8c
Skip nonlinear solver tests on macOS
johnomotani Jun 11, 2024
f643dda
Fix region in distributed_dot_s_r_z_vperp_vpa()
johnomotani Jun 20, 2024
2138739
In nonlinear solve, always do at least one Newton iteration
johnomotani Jun 29, 2024
4f31b31
Fix Jacobian-vector product for updated error tolerances
johnomotani Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
700 changes: 557 additions & 143 deletions makie_post_processing/makie_post_processing/src/makie_post_processing.jl

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions moment_kinetics/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ LegendrePolynomials = "3db4a2ba-fc88-11e8-3e01-49c72059a882"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LsqFit = "2fda8390-95c7-5789-9bda-21331edee243"
MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
MPIPreferences = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267"
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
Expand Down
8 changes: 7 additions & 1 deletion moment_kinetics/src/calculus.jl
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,10 @@ function assign_endpoint!(df1d::AbstractArray{mk_float,Ndims},
# test against coord name -- make sure to use exact string delimiters e.g. "x" not 'x'
# test against Ndims (autodetermined) to choose which array slices to use in assigning endpoints
#println("DEBUG MESSAGE: coord.name: ",coord.name," Ndims: ",Ndims," key: ",key)
if coord.name == "z" && Ndims==2
if coord.name == "z" && Ndims==1
df1d[j] = receive_buffer[]
#println("ASSIGNING DATA")
elseif coord.name == "z" && Ndims==2
df1d[j,:] .= receive_buffer[:]
#println("ASSIGNING DATA")
elseif coord.name == "z" && Ndims==3
Expand All @@ -374,6 +377,9 @@ function assign_endpoint!(df1d::AbstractArray{mk_float,Ndims},
elseif coord.name == "z" && Ndims==6
df1d[:,:,:,j,:,:] .= receive_buffer[:,:,:,:,:]
#println("ASSIGNING DATA")
elseif coord.name == "r" && Ndims==1
df1d[j] = receive_buffer[]
#println("ASSIGNING DATA")
elseif coord.name == "r" && Ndims==2
df1d[:,j] .= receive_buffer[:]
#println("ASSIGNING DATA")
Expand Down
89 changes: 56 additions & 33 deletions moment_kinetics/src/charge_exchange.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ using ..looping
using ..interpolation: interpolate_to_grid_vpa!

"""
update the evolved pdf for each ion and electron species to account for
charge exchange collisions between ions and neutrals
update the evolved pdf for each ion species to account for charge exchange collisions
between ions and neutrals
"""
function charge_exchange_collisions_1V!(f_out, f_neutral_out, fvec_in, moments,
composition, vpa, vz, charge_exchange_frequency,
vpa_spectral, vz_spectral, dt)
function ion_charge_exchange_collisions_1V!(f_out, fvec_in, moments, composition, vpa, vz,
charge_exchange_frequency, vpa_spectral,
vz_spectral, dt)
# This routine assumes a 1D model with:
# nvz = nvpa and identical vz and vpa grids

Expand All @@ -32,19 +32,6 @@ function charge_exchange_collisions_1V!(f_out, f_neutral_out, fvec_in, moments,
moments.neutral.vth[:,:,is], moments, vpa, vz, charge_exchange_frequency,
vz_spectral, dt)
end

begin_sn_r_z_region(no_synchronize=true)
@loop_sn isn begin
# apply CX collisions to all neutral species
# for each neutral species, obtain affect of charge exchange collisions
# with the corresponding ion species
@views charge_exchange_collisions_single_species!(
f_neutral_out[:,1,1,:,:,isn], fvec_in.pdf_neutral[:,1,1,:,:,isn],
fvec_in.pdf[:,1,:,:,isn], fvec_in.density[:,:,isn],
fvec_in.uz_neutral[:,:,isn], fvec_in.upar[:,:,isn],
moments.neutral.vth[:,:,isn], moments.ion.vth[:,:,isn], moments,
vz, vpa, charge_exchange_frequency, vpa_spectral, dt)
end
else
begin_s_r_z_region()
@loop_s is begin
Expand All @@ -58,8 +45,35 @@ function charge_exchange_collisions_1V!(f_out, f_neutral_out, fvec_in, moments,
- fvec_in.pdf[ivpa,1,iz,ir,is]*fvec_in.density_neutral[iz,ir,is])
end
end
end
end

"""
update the evolved pdf for each neutral species to account for charge exchange collisions
between ions and neutrals
"""
function neutral_charge_exchange_collisions_1V!(f_neutral_out, fvec_in, moments,
composition, vpa, vz,
charge_exchange_frequency, vpa_spectral,
vz_spectral, dt)
# This routine assumes a 1D model with:
# nvz = nvpa and identical vz and vpa grids

begin_sn_r_z_region(no_synchronize=true)
if moments.evolve_density
begin_sn_r_z_region()
@loop_sn isn begin
# apply CX collisions to all neutral species
# for each neutral species, obtain affect of charge exchange collisions
# with the corresponding ion species
@views charge_exchange_collisions_single_species!(
f_neutral_out[:,1,1,:,:,isn], fvec_in.pdf_neutral[:,1,1,:,:,isn],
fvec_in.pdf[:,1,:,:,isn], fvec_in.density[:,:,isn],
fvec_in.uz_neutral[:,:,isn], fvec_in.upar[:,:,isn],
moments.neutral.vth[:,:,isn], moments.ion.vth[:,:,isn], moments,
vz, vpa, charge_exchange_frequency, vpa_spectral, dt)
end
else
begin_sn_r_z_region()
@loop_sn isn begin
# apply CX collisions to all neutral species
# for each neutral species, obtain affect of charge exchange collisions
Expand Down Expand Up @@ -135,21 +149,10 @@ function charge_exchange_collisions_single_species!(f_out, pdf_in, pdf_other,
end
end

function charge_exchange_collisions_3V!(f_out, f_neutral_out, f_neutral_gav_in, f_ion_vrvzvzeta_in, fvec_in, composition, vz, vr, vzeta, vpa, vperp, z, r,
charge_exchange_frequency, dt)
function ion_charge_exchange_collisions_3V!(f_out, f_neutral_gav_in, fvec_in, composition,
vz, vr, vzeta, vpa, vperp, z, r,
charge_exchange_frequency, dt)
# This routine assumes a 3V model with:
@boundscheck vz.n == size(f_neutral_out,1) || throw(BoundsError(f_neutral_out))
@boundscheck vr.n == size(f_neutral_out,2) || throw(BoundsError(f_neutral_out))
@boundscheck vzeta.n == size(f_neutral_out,3) || throw(BoundsError(f_neutral_out))
@boundscheck z.n == size(f_neutral_out,4) || throw(BoundsError(f_neutral_out))
@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))
@boundscheck vz.n == size(f_ion_vrvzvzeta_in,1) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck vr.n == size(f_ion_vrvzvzeta_in,2) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck vzeta.n == size(f_ion_vrvzvzeta_in,3) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck z.n == size(f_ion_vrvzvzeta_in,4) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck r.n == size(f_ion_vrvzvzeta_in,5) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck composition.n_neutral_species == size(f_ion_vrvzvzeta_in,6) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck vpa.n == size(f_out,1) || throw(BoundsError(f_out))
@boundscheck vperp.n == size(f_out,2) || throw(BoundsError(f_out))
@boundscheck z.n == size(f_out,3) || throw(BoundsError(f_out))
Expand All @@ -173,6 +176,26 @@ function charge_exchange_collisions_3V!(f_out, f_neutral_out, f_neutral_gav_in,
- fvec_in.pdf[ivpa,ivperp,iz,ir,is]*fvec_in.density_neutral[iz,ir,isn])
end
end
end

function neutral_charge_exchange_collisions_3V!(f_neutral_out, f_ion_vrvzvzeta_in,
fvec_in, composition, vz, vr, vzeta, vpa,
vperp, z, r, charge_exchange_frequency,
dt)
# This routine assumes a 3V model with:
@boundscheck vz.n == size(f_neutral_out,1) || throw(BoundsError(f_neutral_out))
@boundscheck vr.n == size(f_neutral_out,2) || throw(BoundsError(f_neutral_out))
@boundscheck vzeta.n == size(f_neutral_out,3) || throw(BoundsError(f_neutral_out))
@boundscheck z.n == size(f_neutral_out,4) || throw(BoundsError(f_neutral_out))
@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))
@boundscheck vz.n == size(f_ion_vrvzvzeta_in,1) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck vr.n == size(f_ion_vrvzvzeta_in,2) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck vzeta.n == size(f_ion_vrvzvzeta_in,3) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck z.n == size(f_ion_vrvzvzeta_in,4) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck r.n == size(f_ion_vrvzvzeta_in,5) || throw(BoundsError(f_ion_vrvzvzeta_in))
@boundscheck composition.n_neutral_species == size(f_ion_vrvzvzeta_in,6) || throw(BoundsError(f_ion_vrvzvzeta_in))

begin_sn_r_z_vzeta_vr_vz_region()
@loop_sn_r_z_vzeta_vr_vz isn ir iz ivzeta ivr ivz begin
# apply CX collisions to all neutral species
Expand Down
21 changes: 16 additions & 5 deletions moment_kinetics/src/coordinates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ struct coordinate{T <: AbstractVector{mk_float}}
scratch2::Array{mk_float,1}
# scratch3 is an array used for intermediate calculations requiring n entries
scratch3::Array{mk_float,1}
# scratch4 is an array used for intermediate calculations requiring n entries
scratch4::Array{mk_float,1}
# scratch5 is an array used for intermediate calculations requiring n entries
scratch5::Array{mk_float,1}
# scratch6 is an array used for intermediate calculations requiring n entries
scratch6::Array{mk_float,1}
# scratch7 is an array used for intermediate calculations requiring n entries
scratch7::Array{mk_float,1}
# scratch_shared is a shared-memory array used for intermediate calculations requiring
# n entries
scratch_shared::T
Expand Down Expand Up @@ -221,10 +229,12 @@ function define_coordinate(input, parallel_io::Bool=false; run_directory=nothing
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, wgts, uniform_grid, duniform_dgrid, 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)
input.bc, wgts, uniform_grid, duniform_dgrid, 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)

if coord.n == 1 && occursin("v", coord.name)
spectral = null_velocity_dimension_info()
Expand All @@ -242,7 +252,8 @@ function define_coordinate(input, parallel_io::Bool=false; run_directory=nothing
elseif 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)
spectral = setup_gausslegendre_pseudospectral(coord, collision_operator_dim=collision_operator_dim,
dirichlet_bc=occursin("zero", coord.bc))
# obtain the local derivatives of the uniform grid with respect to the used grid
derivative!(coord.duniform_dgrid, coord.uniform_grid, coord, spectral)
else
Expand Down
27 changes: 27 additions & 0 deletions moment_kinetics/src/derivatives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,33 @@ dfns (ion) -> [vpa,vperp,z,r,s]
dfns (neutrals) -> [vz,vr,vzeta,z,r,sn]
"""

#df/dz
#1D version for f[z], used by implicit solvers
function derivative_z!(dfdz::AbstractArray{mk_float,1}, f::AbstractArray{mk_float,1},
dfdz_lower_endpoints::AbstractArray{mk_float,0},
dfdz_upper_endpoints::AbstractArray{mk_float,0},
z_send_buffer::AbstractArray{mk_float,0},
z_receive_buffer::AbstractArray{mk_float,0}, z_spectral, z)

begin_serial_region()

@serial_region begin
# differentiate f w.r.t z
derivative!(dfdz, f, z, z_spectral)
# get external endpoints to reconcile via MPI
dfdz_lower_endpoints[] = z.scratch_2d[1,1]
dfdz_upper_endpoints[] = z.scratch_2d[end,end]
end

# now reconcile element boundaries across
# processes with large message involving all y
if z.nelement_local < z.nelement_global
reconcile_element_boundaries_MPI!(
dfdz, dfdz_lower_endpoints, dfdz_upper_endpoints, z_send_buffer,
z_receive_buffer, z)
end
end

#df/dz
#2D version for f[z,r] -> Er, Ez, phi
function derivative_z!(dfdz::AbstractArray{mk_float,2}, f::AbstractArray{mk_float,2},
Expand Down
Loading
Loading