# collisions_config_type Derived Type

## type, public, extends(abstract_config_type) :: collisions_config_type

Used to represent the input configuration of collisions

## Components

TypeVisibility AttributesNameInitial
logical, public :: exist =.false.

Does the related namelist exist in the target input file?

integer, public :: index =0

Used to hold the specific index of numbered namelists

Do we want to skip the read step in init?

Do we want to skip the broadcast step in init?

If true (default) then transform from the gyro-averaged distribution function $g$ evolved by GS2 to the non-Boltzmann part of $\delta f$, ($h$), when applying the collision operator. This is the physically appropriate choice, this parameter is primarily for numerical testing.

real, public :: cfac =1.0

Factor multipyling the finite Larmor radius terms in the collision operator. This term is essentially just classical diffusion. Set cfac to 0 to turn off this diffusion.

character(len=20), public :: collision_model ='default'

Selects the collision model used in the simulation. Can be one of

• 'default' : Include both pitch angle scattering and energy diffusion.
• 'collisionless' : Disable the collision operator.
• 'none' : Equivalent to 'collisionless'.
• 'lorentz' : Only pitch angle scattering.
• 'lorentz-test' : Only pitch angle scattering. For testing, disables some components of the operator.
• 'ediffuse' : Only energy diffusion.
• 'krook' : "Home made" Krook operator (this is not recommended).

If no species have a non-zero collision frequency, vnewk, then the collision operator is also automatically disabled.

logical, public :: conservative =.true.

If true (default) then guarantee exact conservation properties.

logical, public :: conserve_forbid_zero =.true.

If true (default) then forces conservation corrections to zero in the forbidden region to avoid introducing unphysical non-zero values for the distribution function in the forbidden region of trapped particles.

logical, public :: conserve_moments =.true.

If true (default) then guarantee collision operator conserves momentum and energy.

logical, public :: const_v =.false.

If true (not the default) then use the thermal velocity to evaluate the collision frequencies to be used. This results in an energy independent collision frequency being used for all species.

character(len=20), public :: ediff_scheme ='default'

Controls how the coefficients in the matrix representing the energy diffusion operator are obtained. Can be one of

• 'default' : Use a conservative scheme.
• 'old' : Use the original non-conservative scheme.

logical, public :: ei_coll_only =.false.

If true (not the default) then force the collision frequency used for all non-electron species to zero and force all electron-electron terms to zero.

real, public :: etol =2.e-2

Only used in get_verr as a part of the adaptive collisionality algorithm. Sets the maximum relative error allowed, above which the collision frequency must be increased.

real, public :: etola =2.e-2

Only used in get_verr as a part of the adaptive collisionality algorithm. Sets the maximum absolute error allowed, above which the collision frequency must be increased.

real, public :: ewindow =1.e-2

Only used in get_verr as a part of the adaptive collisionality algorithm. Sets an offset to apply to the relative error limit set by etol. This is used to provide hysteresis is the adaptive collisionality algorithm so to avoid adjusting the collision frequency up and down every step (similar to delt_cushion).

real, public :: ewindowa =1.e-2

Only used in get_verr as a part of the adaptive collisionality algorithm. Sets an offset to apply to the absolute error limit set by etola. This is used to provide hysteresis is the adaptive collisionality algorithm so to avoid adjusting the collision frequency up and down every step (similar to the delt_cushion).

logical, public :: force_collisions =.false.

Currently we skip the application of the selected collision operator for species with zero collision frequency and disable collisions entirely if no species have non-zero collision frequency. This is generally sensible, but it can be useful to force the use of the collisional code path in some situations such as in code testing. Setting this flag to .true. forces the selected collision model operator to be applied even if the collision frequency is zero.

logical, public :: heating =.false.

If true (not the default) then calculate collisional heating when applying the collion operator. This is purely a diagnostic calculation. It should not change the evolution.

logical, public :: hypermult =.false.

If true (not the default) then multiply the hyper collision frequency by the species' collision frequency [[species_parameters::nu_h]]. This only impacts the pitch angle scattering operator.

logical, public :: le_nxilim_fix =.true.

This flag controls the limit of ixi loops in the le_layout decomposition. When true (default) the limit is set to nxi + 1, which has been observed to remove numerical instabilities.

character(len=20), public :: lorentz_scheme ='default'

Controls how the coefficients in the matrix representing the pitch angle scattering operator are obtained. Can be one of

• 'default' : Use a conservative scheme.
• 'old' : Use the original non-conservative scheme.

integer, public :: ncheck =100

Used as a part of the adaptive collisionality algorithm. When active we check the velocity space error with get_verr every ncheck time steps. This check can be relatively expensive so it is recommended to avoid small values of ncheck.

logical, public :: resistivity =.true.

If true (default) then potentially include the drag term in the pitch angle scattering operator. This is a necessary but not sufficient criteria. For the drag term to be included we also require $\beta\neq 0$, more than one simulated species and finite $A_\|$ perturbations included in the simulation (i.e. fapar /= 0).

logical, public :: special_wfb_lorentz =.false.

If true (not the default) then use special handling for the wfb particle in the pitch angle scattering operator.

logical, public :: split_collisions =.false.

If true (not the default) then remove the collision operator from the usual time advance algorithm. Instead the collision operator is only applied every timesteps_between_collisions timesteps. This can potentially substantially speed up collisional simulations, both in the initialisation and advance phases.

logical, public :: test =.false.

If true (not the default) then performs some additional checks of the data redistribution routines associated with transforming being the standard and collisional data decompositions.

integer, public :: timesteps_between_collisions =1

Should set the number of timesteps between application of the collision operator if split_collisions is true. Currently this is ignored.

logical, public :: use_le_layout =.true.

If true (default) then use a data decomposition for collisions that brings both pitch angle and energy local to a processor. This is typically the most efficient option, however for collisional simulations that only use part of the collision operator (either energy diffusion or pitch angle scattering) then it may be beneficial to set this flag to false such that we use a decomposition that only brings either energy or pitch angle local.

logical, public :: vary_vnew =.false.

Set to true (not the default) to activate the adaptive collisionality algorithm.

real, public :: vnfac =1.1

If the collisionality is to be increased as a part of the adaptive collisionality algorithm then increase it by this factor.

real, public :: vnslow =0.9

If the collisionality is to be decreased as a part of the adaptive collisionality algorithm then decrease it by this factor.

logical, public :: vpar_zero_mean =.true.

Controls how the duplicate vpar = 0 point is handled. When vpar_zero_mean = .true. (the default) the average of g(vpar = 0) for both signs of the parallel velcoity (isgn) is used in the collision operator instead of just g(vpar = 0) at isgn=2. This is seen to suppress a numerical instability when special_wfb_lorentz =.false.. With these defaults pitch angle scattering at $\theta = \pm \pi$ is now being handled physically i.e. vpar = 0 at this theta location is no longer being skipped.

## Type-Bound Procedures

• ### private function is_initialised_generic(self)

Is this instance initialised?

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self

• ### private subroutine init_generic(self, name, requires_index, index)

Fully initialise the config object

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(inout) :: self
character(len=*), intent(in), optional :: name
logical, intent(in), optional :: requires_index
integer, intent(in), optional :: index

• ### private subroutine setup_generic(self, name, requires_index, index)

Do some standard setup/checking

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(inout) :: self
character(len=*), intent(in), optional :: name
logical, intent(in), optional :: requires_index
integer, intent(in), optional :: index

• ### private subroutine write_namelist_header(self, unit)

Write the namelist header for this instance

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self
integer, intent(in) :: unit

• ### private function get_name_generic(self)

Returns the namelist name. Not very useful at the moment but may want to do more interesting things in the future

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self

• ### private function get_requires_index_generic(self)

Returns the requires_index value. Allows access whilst keeping the variable private

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self

• ### private subroutine write_namelist_footer(unit)

Write the namelist footer

#### Arguments

Type IntentOptional AttributesName
integer, intent(in) :: unit

• ### private subroutine write_key_val_string(key, val, unit)

Writes a {key,val} pair where the value is of type character

#### Arguments

Type IntentOptional AttributesName
character(len=*), intent(in) :: key
character(len=*), intent(in) :: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_real(key, val, unit)

Writes a {key,val} pair where the value is of type real

#### Arguments

Type IntentOptional AttributesName
character(len=*), intent(in) :: key
real, intent(in) :: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_complex(key, val, unit)

Writes a {key,val} pair where the value is of type complex

#### Arguments

Type IntentOptional AttributesName
character(len=*), intent(in) :: key
complex, intent(in) :: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_integer(key, val, unit)

Writes a {key,val} pair where the value is of type integer

#### Arguments

Type IntentOptional AttributesName
character(len=*), intent(in) :: key
integer, intent(in) :: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_logical(key, val, unit)

Writes a {key,val} pair where the value is of type logical

#### Arguments

Type IntentOptional AttributesName
character(len=*), intent(in) :: key
logical, intent(in) :: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_real_array(self, key, val, unit)

Writes a {key,val} pair where the value is of type real array

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self
character(len=*), intent(in) :: key
real, intent(in), dimension(:):: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_complex_array(self, key, val, unit)

Writes a {key,val} pair where the value is of type complex array

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self
character(len=*), intent(in) :: key
complex, intent(in), dimension(:):: val
integer, intent(in) :: unit
• ### private subroutine write_key_val_integer_array(self, key, val, unit)

Writes a {key,val} pair where the value is of type integer array

#### Arguments

Type IntentOptional AttributesName
class(abstract_config_type), intent(in) :: self
character(len=*), intent(in) :: key
integer, intent(in), dimension(:):: val
integer, intent(in) :: unit

Reads in the collisions_knobs namelist and populates the member variables

#### Arguments

Type IntentOptional AttributesName
class(collisions_config_type), intent(inout) :: self

• ### private subroutine write_collisions_config(self, unit)

Writes out a namelist representing the current state of the config object

#### Arguments

Type IntentOptional AttributesName
class(collisions_config_type), intent(in) :: self
integer, intent(in), optional :: unit

• ### private subroutine reset_collisions_config(self)

Resets the config object to the initial empty state

#### Arguments

Type IntentOptional AttributesName
class(collisions_config_type), intent(inout) :: self

Broadcasts all config parameters so object is populated identically on all processors

#### Arguments

Type IntentOptional AttributesName
class(collisions_config_type), intent(inout) :: self

• ### private function get_default_name_collisions_config()

Gets the default name for this namelist

None

• ### private function get_default_requires_index_collisions_config()

Gets the default requires index for this namelist

None

### Source Code

  type, extends(abstract_config_type) :: collisions_config_type
! namelist : collisions_knobs
! indexed : false
!> If true (default) then transform from the gyro-averaged
!> distribution function $$g$$ evolved by GS2 to the
!> non-Boltzmann part of $$\delta f$$, ($$h$$), when applying the
!> collision operator. This is the physically appropriate choice,
!> this parameter is primarily for numerical testing.
!> Factor multipyling the finite Larmor radius terms in the
!> collision operator. This term is essentially just classical
!> diffusion. Set cfac to 0 to turn off this diffusion.
!>
!> @note Default changed to 1.0 in order to include classical
!> diffusion April 18 2006
real :: cfac = 1.0
!> Selects the collision model used in the simulation. Can be one
!> of
!>
!> - 'default' : Include both pitch angle scattering and energy
!> diffusion.
!> - 'collisionless' : Disable the collision operator.
!> - 'none' : Equivalent to 'collisionless'.
!> - 'lorentz' : Only pitch angle scattering.
!> - 'lorentz-test' : Only pitch angle scattering. For testing,
!> disables some components of the operator.
!> - 'ediffuse' : Only energy diffusion.
!> - 'krook' : "Home made" Krook operator (this is not recommended).
!>
!> If no species have a non-zero collision frequency, vnewk, then
!> the collision operator is also automatically disabled.
character(len = 20) :: collision_model = 'default'
!> If true (default) then guarantee exact conservation
!> properties.
logical :: conservative = .true.
!> If true (default) then forces conservation corrections to zero
!> in the forbidden region to avoid introducing unphysical
!> non-zero values for the distribution function in the forbidden
!> region of trapped particles.
!>
!> @todo Confirm above documentation is accurate.
!>
!> @note The conserving terms calculated as part of the field
!> particle collision operator should respect the forbidden of
!> the distribution function for trapped particles. This is a
!> cosmetic change, but has the result that plots of the
!> distribution function for trapped particles makes sense. Note
!> that terms involving vpa do not need to be modified Because
!> vpa = 0 in the forbidden region because of this explicit
!> forbid statements have not been added to the drag term
!> involving apar.
logical :: conserve_forbid_zero = .true.
!> If true (default) then guarantee collision operator conserves
!> momentum and energy.
!>
!> @todo Clarify the difference with [[collisions_knobs:conservative]].
!>
!> @note Default changed to reflect improved momentum and energy
!> conversation 07/08
logical :: conserve_moments = .true.
!> If true (not the default) then use the thermal velocity to
!> evaluate the collision frequencies to be used. This results in
!> an energy independent collision frequency being used for all
!> species.
logical :: const_v = .false.
!> Controls how the coefficients in the matrix representing the
!> energy diffusion operator are obtained. Can be one of
!>
!> - 'default' : Use a conservative scheme.
!> - 'old' : Use the original non-conservative scheme.
!>
!> @todo Consider deprecating/removing the 'old' option.
character(len = 20) :: ediff_scheme = 'default'
!> If true (not the default) then force the collision frequency
!> used for all non-electron species to zero and force all
!> electron-electron terms to zero.
logical :: ei_coll_only = .false.
!> Only used in [[get_verr]] as a part of the adaptive
!> collisionality algorithm. Sets the maximum relative error
!> allowed, above which the collision frequency must be
!> increased.
!>
!> @todo Confirm this is really to set the relative error limit.
real :: etol = 2.e-2
!> Only used in [[get_verr]] as a part of the adaptive
!> collisionality algorithm. Sets the maximum absolute error
!> allowed, above which the collision frequency must be
!> increased.
!>
!> @todo Confirm this is really to set the absolute error limit.
real :: etola = 2.e-2
!> Only used in [[get_verr]] as a part of the adaptive
!> collisionality algorithm. Sets an offset to apply to the
!> relative error limit set by [[collisions_knobs:etol]]. This is used to provide
!> hysteresis is the adaptive collisionality algorithm so to
!> avoid adjusting the collision frequency up and down every step
!> (similar to [[reinit_knobs:delt_cushion]]).
!>
!> @todo Confirm the above description.
real :: ewindow = 1.e-2
!> Only used in [[get_verr]] as a part of the adaptive
!> collisionality algorithm. Sets an offset to apply to the
!> absolute error limit set by [[collisions_knobs:etola]]. This is used to provide
!> hysteresis is the adaptive collisionality algorithm so to
!> avoid adjusting the collision frequency up and down every step
!> (similar to the [[reinit_knobs:delt_cushion]]).
!>
!> @todo Confirm the above description.
real :: ewindowa = 1.e-2
!> Currently we skip the application of the selected collision
!> operator for species with zero collision frequency and disable
!> collisions entirely if no species have non-zero collision
!> frequency. This is generally sensible, but it can be useful to
!> force the use of the collisional code path in some situations
!> such as in code testing. Setting this flag to .true. forces
!> the selected collision model operator to be applied even if
!> the collision frequency is zero.
logical :: force_collisions = .false.
!> If true (not the default) then calculate collisional heating
!> when applying the collion operator. This is purely a
!> diagnostic calculation. It should not change the evolution.
!>
!> @todo : Verify this does not influence the evolution.
logical :: heating = .false.
!> If true (not the default) then multiply the hyper collision
!> frequency by the species' collision frequency
!> [[species_parameters::nu_h]]. This only impacts the pitch
!> angle scattering operator.
!>
!> @note The hyper collision frequency is only non-zero if any
!> species have a non-zero nu_h value set in the input. If any
!> are set then the hyper collision frequency is simply nu_h *
!> kperp2 * kperp2 (where kperp2 here is normalised to the
!> maximum kperp2).
logical :: hypermult = .false.
!> This flag controls the limit of ixi loops in the le_layout
!> decomposition.  When true (default) the limit is set to nxi +
!> 1, which has been observed to remove numerical instabilities.
!>
!> @note The "old" behavior was a limit of nxi, which is
!> incorrect. With this limit and trapped particles, there are
!> numerical instabilities caused by missing terms for totally
!> trapped particles. By changing the limit to nxi + 1 these
!> numerical instabilities are removed and the le_layout gives
!> the same result as the standard layout. The limit nxi + 1
!> should used as we then include the ixi index for the
!> duplicate vpar=0 point which must be included For velocity
!> integration to give the correct value.
!>
!> @todo Consider removing this flag and just use the correct
!> limit.  The motivation for retaining this flag is to allow old
!> results to be reproduced.
logical :: le_nxilim_fix = .true.
!> Controls how the coefficients in the matrix representing the
!> pitch angle scattering operator are obtained. Can be one of
!>
!> - 'default' : Use a conservative scheme.
!> - 'old' : Use the original non-conservative scheme.
!>
!> @todo Consider deprecating/removing the 'old' option.
character(len = 20) :: lorentz_scheme = 'default'
!> Used as a part of the adaptive collisionality algorithm. When
!> active we check the velocity space error with [[get_verr]]
!> every ncheck time steps. This check can be relatively
!> expensive so it is recommended to avoid small values of
!> ncheck.
!>
!> @warning The new diagnostics module currently ignores this
!> value and instead uses its own input variable named ncheck
!> (which has a different default). See [this
!> bug](https://bitbucket.org/gyrokinetics/gs2/issues/88).
integer :: ncheck = 100
!> If true (default) then potentially include the drag term in
!> the pitch angle scattering operator. This is a necessary but
!> not sufficient criteria. For the drag term to be included we
!> also require $$\beta\neq 0$$, more than one simulated species
!> and finite $$A_\|$$ perturbations included in the simulation
!> (i.e. fapar /= 0).
logical :: resistivity = .true.
!> If true (not the default) then use special handling for the
!> wfb particle in the pitch angle scattering operator.
!>
!> @note MRH changed default 16/08/2018. Previous default of true
!> seemed to cause a numerical issue in flux tube simulations for
!> the zonal modes at large $$k_x$$.
!>
!> @todo Improve this documentation
logical :: special_wfb_lorentz = .false.
!> If true (not the default) then remove the collision operator
!> operator is only applied every
!> [[collisions_knobs:timesteps_between_collisions]]
!> timesteps. This can potentially substantially speed up
!> collisional simulations, both in the initialisation and
!>
!> @warning Currently the input
!> [[collisions_knobs:timesteps_between_collisions]] is ignored
!> so collisions are applied every time step. The primary result
!> of split_collision = .true. currently is that collisions are
!> not applied in the first linear solve used as a part of a
!> single time step. Hence the cost of collisions in advance are
!> roughly halved. The full saving in the initialisation phase is
!> still realised.
logical :: split_collisions = .false.
!> If true (not the default) then performs some additional checks
!> of the data redistribution routines associated with
!> transforming being the standard and collisional data
!> decompositions.
logical :: test = .false.
!> Should set the number of timesteps between application of the
!> collision operator if [[collisions_knobs:split_collisions]] is
!> true. Currently this is ignored.
!>
!> @warning This value is currently ignored.
integer :: timesteps_between_collisions = 1
!> If true (default) then use a data decomposition for collisions
!> that brings both pitch angle and energy local to a
!> processor. This is typically the most efficient option,
!> however for collisional simulations that only use part of the
!> collision operator (either energy diffusion or pitch angle
!> scattering) then it may be beneficial to set this flag to
!> false such that we use a decomposition that only brings either
!> energy or pitch angle local.
logical :: use_le_layout = .true.
!> Set to true (not the default) to activate the adaptive
!> collisionality algorithm.
!>
!> @todo Provide more documentation on the adaptive
!> collisionality algorithm.
logical :: vary_vnew = .false.
!> If the collisionality is to be increased as a part of the
!> adaptive collisionality algorithm then increase it by this
!> factor.
real :: vnfac = 1.1
!> If the collisionality is to be decreased as a part of the
!> adaptive collisionality algorithm then decrease it by this
!> factor.
real :: vnslow = 0.9
!> Controls how the duplicate vpar = 0 point is handled.  When
!> vpar_zero_mean = .true. (the default) the average of g(vpar
!> = 0) for both signs of the parallel velcoity (isgn) is used
!> in the collision operator instead of just g(vpar = 0) at
!> isgn=2.  This is seen to suppress a numerical instability
!> when special_wfb_lorentz =.false.. With these defaults pitch
!> angle scattering at $$\theta = \pm \pi$$ is now being handled
!> physically i.e. vpar = 0 at this theta location is no longer
!> being skipped.
!>
!> @todo Consider removing this option.
logical :: vpar_zero_mean = .true.
contains